@almadar/ui 5.35.0 → 5.37.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.
@@ -7,9 +7,6 @@ import { EventBusContext, useTraitScope, OrbitalProvider, TraitScopeProvider, Ve
7
7
  import { createLogger, isLogLevelEnabled } from '@almadar/logger';
8
8
  import * as LucideIcons2 from 'lucide-react';
9
9
  import { Loader2, X, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, Code, FileText, WrapText, Check, Copy, RotateCcw, Play, Terminal, XCircle, AlertTriangle, Trash2, Link2, ZoomOut, ZoomIn, Download, Menu as Menu$1, Package, Calendar, MoreHorizontal, Image as Image$1, Upload, ArrowLeft, HelpCircle, PauseCircle, Search, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, Minus, Eraser, TrendingUp, TrendingDown, AlertCircle, Circle, Clock, CheckCircle2, Pause, SkipForward, Bug, Send, ChevronUp, ChevronDown, Wrench, Tag, User, DollarSign, Zap, Sword, Move, Heart, Shield } from 'lucide-react';
10
- import * as PhosphorIcons from '@phosphor-icons/react';
11
- import * as TablerIcons from '@tabler/icons-react';
12
- import * as FaIcons from 'react-icons/fa';
13
10
  import { createPortal } from 'react-dom';
14
11
  import { useTranslate, useEventBus as useEventBus$1 } from '@almadar/ui/hooks';
15
12
  import { evaluate, createMinimalContext } from '@almadar/evaluator';
@@ -529,6 +526,41 @@ function kebabToPascal(name) {
529
526
  return part.charAt(0).toUpperCase() + part.slice(1);
530
527
  }).join("");
531
528
  }
529
+ function loadLib(key, importer) {
530
+ let p2 = libPromises.get(key);
531
+ if (!p2) {
532
+ p2 = importer().then((m) => m);
533
+ libPromises.set(key, p2);
534
+ }
535
+ return p2;
536
+ }
537
+ function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
538
+ const Lazy = React82__default.lazy(async () => {
539
+ const lib = await loadLib(libKey, importer);
540
+ const Comp = pick(lib);
541
+ if (!Comp) {
542
+ warnFallback(fallbackName, family);
543
+ return { default: makeLucideAdapter(fallbackName, true) };
544
+ }
545
+ return { default: Comp };
546
+ });
547
+ const Wrapped = (props) => /* @__PURE__ */ jsx(
548
+ React82__default.Suspense,
549
+ {
550
+ fallback: /* @__PURE__ */ jsx(
551
+ "span",
552
+ {
553
+ "aria-hidden": true,
554
+ className: props.className,
555
+ style: { display: "inline-block", ...props.style }
556
+ }
557
+ ),
558
+ children: /* @__PURE__ */ jsx(Lazy, { ...props })
559
+ }
560
+ );
561
+ Wrapped.displayName = `Lazy.${libKey}.${fallbackName}`;
562
+ return Wrapped;
563
+ }
532
564
  function resolveLucide(name) {
533
565
  if (lucideAliases[name]) return lucideAliases[name];
534
566
  const pascal = kebabToPascal(name);
@@ -539,60 +571,81 @@ function resolveLucide(name) {
539
571
  if (asIs && typeof asIs === "object") return asIs;
540
572
  return LucideIcons2.HelpCircle;
541
573
  }
542
- function resolvePhosphor(name, weight) {
574
+ function resolvePhosphor(name, weight, family) {
543
575
  const target = phosphorAliases[name] ?? kebabToPascal(name);
544
- const map = PhosphorIcons;
545
- const PhosphorComp = map[target];
546
- if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
547
- const Component = PhosphorComp;
548
- const Adapter = (props) => /* @__PURE__ */ jsx(
549
- Component,
550
- {
551
- weight,
552
- className: props.className,
553
- style: props.style,
554
- size: props.size ?? "1em"
555
- }
576
+ return lazyFamilyIcon(
577
+ "phosphor",
578
+ () => import('@phosphor-icons/react'),
579
+ (lib) => {
580
+ const PhosphorComp = lib[target];
581
+ if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
582
+ const Component = PhosphorComp;
583
+ const Adapter = (props) => /* @__PURE__ */ jsx(
584
+ Component,
585
+ {
586
+ weight,
587
+ className: props.className,
588
+ style: props.style,
589
+ size: props.size ?? "1em"
590
+ }
591
+ );
592
+ Adapter.displayName = `Phosphor.${target}.${weight}`;
593
+ return Adapter;
594
+ },
595
+ name,
596
+ family
556
597
  );
557
- Adapter.displayName = `Phosphor.${target}.${weight}`;
558
- return Adapter;
559
598
  }
560
- function resolveTabler(name) {
599
+ function resolveTabler(name, family) {
561
600
  const suffix = tablerAliases[name] ?? kebabToPascal(name);
562
601
  const target = `Icon${suffix}`;
563
- const map = TablerIcons;
564
- const TablerComp = map[target];
565
- if (!TablerComp || typeof TablerComp !== "object") return null;
566
- const Component = TablerComp;
567
- const Adapter = (props) => /* @__PURE__ */ jsx(
568
- Component,
569
- {
570
- stroke: props.strokeWidth ?? 1.5,
571
- className: props.className,
572
- style: props.style,
573
- size: props.size ?? 24
574
- }
602
+ return lazyFamilyIcon(
603
+ "tabler",
604
+ () => import('@tabler/icons-react'),
605
+ (lib) => {
606
+ const TablerComp = lib[target];
607
+ if (!TablerComp || typeof TablerComp !== "object") return null;
608
+ const Component = TablerComp;
609
+ const Adapter = (props) => /* @__PURE__ */ jsx(
610
+ Component,
611
+ {
612
+ stroke: props.strokeWidth ?? 1.5,
613
+ className: props.className,
614
+ style: props.style,
615
+ size: props.size ?? 24
616
+ }
617
+ );
618
+ Adapter.displayName = `Tabler.${target}`;
619
+ return Adapter;
620
+ },
621
+ name,
622
+ family
575
623
  );
576
- Adapter.displayName = `Tabler.${target}`;
577
- return Adapter;
578
624
  }
579
- function resolveFa(name) {
625
+ function resolveFa(name, family) {
580
626
  const suffix = faAliases[name] ?? kebabToPascal(name);
581
627
  const target = `Fa${suffix}`;
582
- const map = FaIcons;
583
- const FaComp = map[target];
584
- if (!FaComp || typeof FaComp !== "function") return null;
585
- const Component = FaComp;
586
- const Adapter = (props) => /* @__PURE__ */ jsx(
587
- Component,
588
- {
589
- className: props.className,
590
- style: props.style,
591
- size: props.size ?? "1em"
592
- }
628
+ return lazyFamilyIcon(
629
+ "fa",
630
+ () => import('react-icons/fa'),
631
+ (lib) => {
632
+ const FaComp = lib[target];
633
+ if (!FaComp || typeof FaComp !== "function") return null;
634
+ const Component = FaComp;
635
+ const Adapter = (props) => /* @__PURE__ */ jsx(
636
+ Component,
637
+ {
638
+ className: props.className,
639
+ style: props.style,
640
+ size: props.size ?? "1em"
641
+ }
642
+ );
643
+ Adapter.displayName = `Fa.${target}`;
644
+ return Adapter;
645
+ },
646
+ name,
647
+ family
593
648
  );
594
- Adapter.displayName = `Fa.${target}`;
595
- return Adapter;
596
649
  }
597
650
  function warnFallback(name, family) {
598
651
  const key = `${family}::${name}`;
@@ -626,39 +679,22 @@ function resolveIconForFamily(name, family) {
626
679
  switch (family) {
627
680
  case "lucide":
628
681
  return makeLucideAdapter(name, false);
629
- case "phosphor-outline": {
630
- const p2 = resolvePhosphor(name, "regular");
631
- if (p2) return p2;
632
- warnFallback(name, family);
633
- return makeLucideAdapter(name, true);
634
- }
635
- case "phosphor-fill": {
636
- const p2 = resolvePhosphor(name, "fill");
637
- if (p2) return p2;
638
- warnFallback(name, family);
639
- return makeLucideAdapter(name, true);
640
- }
641
- case "phosphor-duotone": {
642
- const p2 = resolvePhosphor(name, "duotone");
643
- if (p2) return p2;
644
- warnFallback(name, family);
645
- return makeLucideAdapter(name, true);
646
- }
647
- case "tabler": {
648
- const t = resolveTabler(name);
649
- if (t) return t;
650
- warnFallback(name, family);
651
- return makeLucideAdapter(name, true);
652
- }
653
- case "fa-solid": {
654
- const f3 = resolveFa(name);
655
- if (f3) return f3;
656
- warnFallback(name, family);
657
- return makeLucideAdapter(name, true);
658
- }
659
- }
660
- }
661
- var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
682
+ // Non-lucide families resolve to a lazy, Suspense-wrapped component that
683
+ // dynamic-imports the library on first render and falls back to lucide
684
+ // internally when the family lacks the icon (see lazyFamilyIcon).
685
+ case "phosphor-outline":
686
+ return resolvePhosphor(name, "regular", family);
687
+ case "phosphor-fill":
688
+ return resolvePhosphor(name, "fill", family);
689
+ case "phosphor-duotone":
690
+ return resolvePhosphor(name, "duotone", family);
691
+ case "tabler":
692
+ return resolveTabler(name, family);
693
+ case "fa-solid":
694
+ return resolveFa(name, family);
695
+ }
696
+ }
697
+ var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, libPromises, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
662
698
  var init_iconFamily = __esm({
663
699
  "lib/iconFamily.tsx"() {
664
700
  "use client";
@@ -674,6 +710,7 @@ var init_iconFamily = __esm({
674
710
  cachedFamily = null;
675
711
  listeners = /* @__PURE__ */ new Set();
676
712
  observer = null;
713
+ libPromises = /* @__PURE__ */ new Map();
677
714
  lucideAliases = {
678
715
  close: LucideIcons2.X,
679
716
  trash: LucideIcons2.Trash2,
@@ -16939,61 +16976,53 @@ var init_Breadcrumb = __esm({
16939
16976
  function BuilderBoard({
16940
16977
  entity,
16941
16978
  completeEvent = "PUZZLE_COMPLETE",
16979
+ placeEvent,
16980
+ checkEvent,
16981
+ playAgainEvent,
16942
16982
  className
16943
16983
  }) {
16944
16984
  const { emit } = useEventBus();
16945
16985
  const { t } = useTranslate();
16946
16986
  const resolved = boardEntity(entity);
16947
- const [placements, setPlacements] = useState({});
16948
16987
  const [headerError, setHeaderError] = useState(false);
16949
- const [submitted, setSubmitted] = useState(false);
16950
- const [attempts, setAttempts] = useState(0);
16951
- const [showHint, setShowHint] = useState(false);
16988
+ const [selectedComponent, setSelectedComponent] = useState(null);
16952
16989
  const components = Array.isArray(resolved?.components) ? resolved.components : [];
16953
16990
  const slots = Array.isArray(resolved?.slots) ? resolved.slots : [];
16991
+ const placements = {};
16992
+ for (const slot of slots) {
16993
+ if (slot.placedComponentId) placements[slot.id] = slot.placedComponentId;
16994
+ }
16995
+ const attempts = num(resolved?.attempts);
16996
+ const result = str(resolved?.result) || "none";
16997
+ const submitted = result === "win";
16954
16998
  const usedComponentIds = new Set(Object.values(placements));
16955
16999
  const availableComponents = components.filter((c) => !usedComponentIds.has(c.id));
16956
- const [selectedComponent, setSelectedComponent] = useState(null);
16957
- const allPlaced = Object.keys(placements).length === slots.length;
17000
+ const allPlaced = slots.length > 0 && slots.every((s) => Boolean(placements[s.id]));
16958
17001
  const results = submitted ? slots.map((slot) => ({
16959
17002
  slot,
16960
17003
  placed: placements[slot.id],
16961
- correct: placements[slot.id] === slot.acceptsComponentId
17004
+ correct: placements[slot.id] === slot.requiredComponentId
16962
17005
  })) : [];
16963
- const allCorrect = results.length > 0 && results.every((r) => r.correct);
17006
+ const showHint = attempts >= 2 && Boolean(str(resolved?.hint));
16964
17007
  const handlePlaceComponent = (slotId) => {
16965
17008
  if (submitted || !selectedComponent) return;
16966
- setPlacements((prev) => ({ ...prev, [slotId]: selectedComponent }));
17009
+ if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: selectedComponent });
16967
17010
  setSelectedComponent(null);
16968
17011
  };
16969
17012
  const handleRemoveFromSlot = (slotId) => {
16970
17013
  if (submitted) return;
16971
- setPlacements((prev) => {
16972
- const next = { ...prev };
16973
- delete next[slotId];
16974
- return next;
16975
- });
17014
+ if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: "" });
16976
17015
  };
16977
- const handleSubmit = useCallback(() => {
16978
- setSubmitted(true);
16979
- setAttempts((a) => a + 1);
16980
- const correct = slots.every((slot) => placements[slot.id] === slot.acceptsComponentId);
16981
- if (correct) {
17016
+ const handleSubmit = () => {
17017
+ if (checkEvent) emit(`UI:${checkEvent}`, {});
17018
+ const solved = slots.length > 0 && slots.every((s) => placements[s.id] === s.requiredComponentId);
17019
+ if (solved && completeEvent) {
16982
17020
  emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
16983
17021
  }
16984
- }, [slots, placements, attempts, completeEvent, emit]);
16985
- const handleReset = () => {
16986
- setSubmitted(false);
16987
- if (attempts >= 2 && str(resolved?.hint)) {
16988
- setShowHint(true);
16989
- }
16990
17022
  };
16991
- const handleFullReset = () => {
16992
- setPlacements({});
16993
- setSubmitted(false);
17023
+ const handlePlayAgain = () => {
16994
17024
  setSelectedComponent(null);
16995
- setAttempts(0);
16996
- setShowHint(false);
17025
+ if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
16997
17026
  };
16998
17027
  const getComponentById = (id) => components.find((c) => c.id === id);
16999
17028
  if (!resolved) return null;
@@ -17043,13 +17072,13 @@ function BuilderBoard({
17043
17072
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("builder.blueprint") }),
17044
17073
  /* @__PURE__ */ jsx(VStack, { gap: "sm", children: slots.map((slot) => {
17045
17074
  const placedComp = placements[slot.id] ? getComponentById(placements[slot.id]) : null;
17046
- const result = results.find((r) => r.slot.id === slot.id);
17075
+ const result2 = results.find((r) => r.slot.id === slot.id);
17047
17076
  return /* @__PURE__ */ jsxs(
17048
17077
  HStack,
17049
17078
  {
17050
17079
  gap: "sm",
17051
17080
  align: "center",
17052
- className: `p-3 border-2 rounded ${result ? result.correct ? "border-success" : "border-error" : selectedComponent ? "border-dashed border-foreground cursor-pointer" : "border-border"}`,
17081
+ className: `p-3 border-2 rounded ${result2 ? result2.correct ? "border-success" : "border-error" : selectedComponent ? "border-dashed border-foreground cursor-pointer" : "border-border"}`,
17053
17082
  onClick: () => handlePlaceComponent(slot.id),
17054
17083
  children: [
17055
17084
  /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "flex-1", children: [
@@ -17064,7 +17093,7 @@ function BuilderBoard({
17064
17093
  ] }) : null,
17065
17094
  placedComp.label
17066
17095
  ] }),
17067
- result && /* @__PURE__ */ jsx(Icon, { icon: result.correct ? CheckCircle : XCircle, size: "sm", className: result.correct ? "text-success" : "text-error" })
17096
+ result2 && /* @__PURE__ */ jsx(Icon, { icon: result2.correct ? CheckCircle : XCircle, size: "sm", className: result2.correct ? "text-success" : "text-error" })
17068
17097
  ] }) : /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("builder.empty") })
17069
17098
  ]
17070
17099
  },
@@ -17073,16 +17102,16 @@ function BuilderBoard({
17073
17102
  }) })
17074
17103
  ] }) }),
17075
17104
  submitted && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
17076
- /* @__PURE__ */ jsx(Icon, { icon: allCorrect ? CheckCircle : XCircle, size: "lg", className: allCorrect ? "text-success" : "text-error" }),
17077
- /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("builder.success") : str(resolved.failMessage) || t("builder.incorrect") })
17105
+ /* @__PURE__ */ jsx(Icon, { icon: CheckCircle, size: "lg", className: "text-success" }),
17106
+ /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: str(resolved.successMessage) || t("builder.success") })
17078
17107
  ] }) }),
17079
17108
  showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
17080
17109
  /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
17081
- !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
17110
+ !submitted && /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
17082
17111
  /* @__PURE__ */ jsx(Icon, { icon: Wrench, size: "sm" }),
17083
17112
  t("builder.build")
17084
- ] }) : !allCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("builder.tryAgain") }) : null,
17085
- /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handleFullReset, children: [
17113
+ ] }),
17114
+ /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handlePlayAgain, children: [
17086
17115
  /* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
17087
17116
  t("builder.reset")
17088
17117
  ] })
@@ -20538,57 +20567,84 @@ var init_ChartLegend = __esm({
20538
20567
  function ClassifierBoard({
20539
20568
  entity,
20540
20569
  completeEvent = "PUZZLE_COMPLETE",
20570
+ assignEvent,
20571
+ checkEvent,
20572
+ playAgainEvent,
20541
20573
  className
20542
20574
  }) {
20543
20575
  const { emit } = useEventBus();
20544
20576
  const { t } = useTranslate();
20545
20577
  const resolved = boardEntity(entity);
20546
- const [assignments, setAssignments] = useState({});
20578
+ const [localAssignments, setLocalAssignments] = useState({});
20547
20579
  const [headerError, setHeaderError] = useState(false);
20548
- const [submitted, setSubmitted] = useState(false);
20549
- const [attempts, setAttempts] = useState(0);
20580
+ const [localSubmitted, setLocalSubmitted] = useState(false);
20581
+ const [localAttempts, setLocalAttempts] = useState(0);
20550
20582
  const [showHint, setShowHint] = useState(false);
20551
20583
  const items = Array.isArray(resolved?.items) ? resolved.items : [];
20552
20584
  const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
20585
+ const entityResult = str(resolved?.result);
20586
+ const entityDrivesResult = entityResult.length > 0;
20587
+ const entityHasAssignments = items.some((item) => item.assignedCategory != null);
20588
+ const assignments = entityHasAssignments ? items.reduce((acc, item) => {
20589
+ if (item.assignedCategory != null) acc[item.id] = item.assignedCategory;
20590
+ return acc;
20591
+ }, {}) : localAssignments;
20592
+ const attempts = entityDrivesResult ? num(resolved?.attempts) : localAttempts;
20593
+ const submitted = entityDrivesResult || localSubmitted;
20553
20594
  const unassignedItems = items.filter((item) => !assignments[item.id]);
20554
- const allAssigned = Object.keys(assignments).length === items.length;
20595
+ const allAssigned = items.length > 0 && Object.keys(assignments).length === items.length;
20555
20596
  const results = submitted ? items.map((item) => ({
20556
20597
  item,
20557
20598
  assigned: assignments[item.id],
20558
20599
  correct: assignments[item.id] === item.correctCategory
20559
20600
  })) : [];
20560
- const allCorrect = results.length > 0 && results.every((r) => r.correct);
20601
+ const allCorrect = entityDrivesResult ? entityResult === "success" : results.length > 0 && results.every((r) => r.correct);
20561
20602
  const correctCount = results.filter((r) => r.correct).length;
20562
20603
  const handleAssign = (itemId, categoryId) => {
20563
20604
  if (submitted) return;
20564
- setAssignments((prev) => ({ ...prev, [itemId]: categoryId }));
20605
+ if (assignEvent) {
20606
+ emit(`UI:${assignEvent}`, { itemId, categoryId });
20607
+ }
20608
+ if (!entityHasAssignments) {
20609
+ setLocalAssignments((prev) => ({ ...prev, [itemId]: categoryId }));
20610
+ }
20565
20611
  };
20566
20612
  const handleUnassign = (itemId) => {
20567
20613
  if (submitted) return;
20568
- setAssignments((prev) => {
20569
- const next = { ...prev };
20570
- delete next[itemId];
20571
- return next;
20572
- });
20614
+ if (!entityHasAssignments) {
20615
+ setLocalAssignments((prev) => {
20616
+ const next = { ...prev };
20617
+ delete next[itemId];
20618
+ return next;
20619
+ });
20620
+ }
20573
20621
  };
20574
20622
  const handleSubmit = useCallback(() => {
20575
- setSubmitted(true);
20576
- setAttempts((a) => a + 1);
20577
- const correct = items.every((item) => assignments[item.id] === item.correctCategory);
20578
- if (correct) {
20579
- emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
20623
+ if (checkEvent) {
20624
+ emit(`UI:${checkEvent}`, {});
20625
+ }
20626
+ if (!entityDrivesResult) {
20627
+ setLocalSubmitted(true);
20628
+ setLocalAttempts((a) => a + 1);
20629
+ const correct = items.every((item) => assignments[item.id] === item.correctCategory);
20630
+ if (correct) {
20631
+ emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
20632
+ }
20580
20633
  }
20581
- }, [items, assignments, attempts, completeEvent, emit]);
20634
+ }, [checkEvent, entityDrivesResult, items, assignments, attempts, completeEvent, emit]);
20582
20635
  const handleReset = () => {
20583
- setSubmitted(false);
20636
+ if (!entityDrivesResult) setLocalSubmitted(false);
20584
20637
  if (attempts >= 2 && str(resolved?.hint)) {
20585
20638
  setShowHint(true);
20586
20639
  }
20587
20640
  };
20588
20641
  const handleFullReset = () => {
20589
- setAssignments({});
20590
- setSubmitted(false);
20591
- setAttempts(0);
20642
+ if (playAgainEvent) {
20643
+ emit(`UI:${playAgainEvent}`, {});
20644
+ }
20645
+ setLocalAssignments({});
20646
+ setLocalSubmitted(false);
20647
+ setLocalAttempts(0);
20592
20648
  setShowHint(false);
20593
20649
  };
20594
20650
  if (!resolved) return null;
@@ -28471,13 +28527,13 @@ var init_MapView = __esm({
28471
28527
  shadowSize: [41, 41]
28472
28528
  });
28473
28529
  L.Marker.prototype.options.icon = defaultIcon;
28474
- const { useEffect: useEffect73, useRef: useRef67, useCallback: useCallback113, useState: useState107 } = React82__default;
28530
+ const { useEffect: useEffect74, useRef: useRef68, useCallback: useCallback111, useState: useState107 } = React82__default;
28475
28531
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
28476
28532
  const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
28477
28533
  function MapUpdater({ centerLat, centerLng, zoom }) {
28478
28534
  const map = useMap();
28479
- const prevRef = useRef67({ centerLat, centerLng, zoom });
28480
- useEffect73(() => {
28535
+ const prevRef = useRef68({ centerLat, centerLng, zoom });
28536
+ useEffect74(() => {
28481
28537
  const prev = prevRef.current;
28482
28538
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
28483
28539
  map.setView([centerLat, centerLng], zoom);
@@ -28488,7 +28544,7 @@ var init_MapView = __esm({
28488
28544
  }
28489
28545
  function MapClickHandler({ onMapClick }) {
28490
28546
  const map = useMap();
28491
- useEffect73(() => {
28547
+ useEffect74(() => {
28492
28548
  if (!onMapClick) return;
28493
28549
  const handler = (e) => {
28494
28550
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -28517,7 +28573,7 @@ var init_MapView = __esm({
28517
28573
  }) {
28518
28574
  const eventBus = useEventBus3();
28519
28575
  const [clickedPosition, setClickedPosition] = useState107(null);
28520
- const handleMapClick = useCallback113((lat, lng) => {
28576
+ const handleMapClick = useCallback111((lat, lng) => {
28521
28577
  if (showClickedPin) {
28522
28578
  setClickedPosition({ lat, lng });
28523
28579
  }
@@ -28526,7 +28582,7 @@ var init_MapView = __esm({
28526
28582
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
28527
28583
  }
28528
28584
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
28529
- const handleMarkerClick = useCallback113((marker) => {
28585
+ const handleMarkerClick = useCallback111((marker) => {
28530
28586
  onMarkerClick?.(marker);
28531
28587
  if (markerClickEvent) {
28532
28588
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -37748,51 +37804,52 @@ var init_DataTable = __esm({
37748
37804
  function DebuggerBoard({
37749
37805
  entity,
37750
37806
  completeEvent = "PUZZLE_COMPLETE",
37807
+ toggleFlagEvent,
37808
+ checkEvent,
37809
+ playAgainEvent,
37751
37810
  className
37752
37811
  }) {
37753
37812
  const { emit } = useEventBus();
37754
37813
  const { t } = useTranslate();
37755
37814
  const resolved = boardEntity(entity);
37756
- const [flaggedLines, setFlaggedLines] = useState(/* @__PURE__ */ new Set());
37757
37815
  const [headerError, setHeaderError] = useState(false);
37758
- const [submitted, setSubmitted] = useState(false);
37759
- const [attempts, setAttempts] = useState(0);
37760
37816
  const [showHint, setShowHint] = useState(false);
37817
+ const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
37818
+ const result = resolved?.result ?? null;
37819
+ const attempts = num(resolved?.attempts);
37820
+ const submitted = result != null;
37821
+ const bugLines = lines.filter((l) => l.isBug);
37822
+ const flaggedLines = lines.filter((l) => l.isFlagged);
37823
+ const correctFlags = lines.filter((l) => l.isBug && l.isFlagged);
37824
+ const falseFlags = lines.filter((l) => !l.isBug && l.isFlagged);
37825
+ const allCorrect = result === "win";
37761
37826
  const toggleLine = (lineId) => {
37762
37827
  if (submitted) return;
37763
- setFlaggedLines((prev) => {
37764
- const next = new Set(prev);
37765
- if (next.has(lineId)) {
37766
- next.delete(lineId);
37767
- } else {
37768
- next.add(lineId);
37769
- }
37770
- return next;
37771
- });
37828
+ if (toggleFlagEvent) {
37829
+ emit(`UI:${toggleFlagEvent}`, { lineId });
37830
+ }
37772
37831
  };
37773
- const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
37774
- const bugLines = lines.filter((l) => l.isBug);
37775
- const correctFlags = lines.filter((l) => l.isBug && flaggedLines.has(l.id));
37776
- const falseFlags = lines.filter((l) => !l.isBug && flaggedLines.has(l.id));
37777
- const allCorrect = submitted && correctFlags.length === bugLines.length && falseFlags.length === 0;
37778
37832
  const handleSubmit = useCallback(() => {
37779
- setSubmitted(true);
37780
- setAttempts((a) => a + 1);
37833
+ if (checkEvent) {
37834
+ emit(`UI:${checkEvent}`, {});
37835
+ }
37781
37836
  const correct = correctFlags.length === bugLines.length && falseFlags.length === 0;
37782
37837
  if (correct) {
37783
37838
  emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
37784
37839
  }
37785
- }, [correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
37840
+ }, [checkEvent, correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
37786
37841
  const handleReset = () => {
37787
- setSubmitted(false);
37842
+ if (playAgainEvent) {
37843
+ emit(`UI:${playAgainEvent}`, {});
37844
+ }
37788
37845
  if (attempts >= 2 && str(resolved?.hint)) {
37789
37846
  setShowHint(true);
37790
37847
  }
37791
37848
  };
37792
37849
  const handleFullReset = () => {
37793
- setFlaggedLines(/* @__PURE__ */ new Set());
37794
- setSubmitted(false);
37795
- setAttempts(0);
37850
+ if (playAgainEvent) {
37851
+ emit(`UI:${playAgainEvent}`, {});
37852
+ }
37796
37853
  setShowHint(false);
37797
37854
  };
37798
37855
  if (!resolved) return null;
@@ -37820,7 +37877,7 @@ function DebuggerBoard({
37820
37877
  /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(num(resolved.bugCount)) }) })
37821
37878
  ] }) }),
37822
37879
  /* @__PURE__ */ jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsx(VStack, { gap: "none", children: lines.map((line, i) => {
37823
- const isFlagged = flaggedLines.has(line.id);
37880
+ const isFlagged = !!line.isFlagged;
37824
37881
  let lineStyle = "";
37825
37882
  if (submitted) {
37826
37883
  if (line.isBug && isFlagged) lineStyle = "bg-success/10";
@@ -37854,9 +37911,9 @@ function DebuggerBoard({
37854
37911
  /* @__PURE__ */ jsx(
37855
37912
  Icon,
37856
37913
  {
37857
- icon: flaggedLines.has(line.id) ? CheckCircle : XCircle,
37914
+ icon: line.isFlagged ? CheckCircle : XCircle,
37858
37915
  size: "xs",
37859
- className: flaggedLines.has(line.id) ? "text-success mt-0.5" : "text-warning mt-0.5"
37916
+ className: line.isFlagged ? "text-success mt-0.5" : "text-warning mt-0.5"
37860
37917
  }
37861
37918
  ),
37862
37919
  /* @__PURE__ */ jsxs(VStack, { gap: "none", children: [
@@ -37867,7 +37924,7 @@ function DebuggerBoard({
37867
37924
  ] }) }),
37868
37925
  showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
37869
37926
  /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
37870
- !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.size === 0, children: [
37927
+ !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.length === 0, children: [
37871
37928
  /* @__PURE__ */ jsx(Icon, { icon: Send, size: "sm" }),
37872
37929
  t("debugger.submit")
37873
37930
  ] }) : !allCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("debugger.tryAgain") }) : null,
@@ -41631,6 +41688,9 @@ function getOpponentAction(strategy, actions, history) {
41631
41688
  function NegotiatorBoard({
41632
41689
  entity,
41633
41690
  completeEvent = "PUZZLE_COMPLETE",
41691
+ playRoundEvent,
41692
+ finishEvent,
41693
+ playAgainEvent,
41634
41694
  className
41635
41695
  }) {
41636
41696
  const { emit } = useEventBus();
@@ -41639,13 +41699,14 @@ function NegotiatorBoard({
41639
41699
  const [history, setHistory] = useState([]);
41640
41700
  const [headerError, setHeaderError] = useState(false);
41641
41701
  const [showHint, setShowHint] = useState(false);
41642
- const totalRounds = num(resolved?.totalRounds);
41702
+ const totalRounds = num(resolved?.maxRounds);
41643
41703
  const targetScore = num(resolved?.targetScore);
41644
- const currentRound = history.length;
41645
- const isComplete = currentRound >= totalRounds;
41646
- const playerTotal = history.reduce((s, r) => s + r.playerPayoff, 0);
41704
+ const currentRound = num(resolved?.round);
41705
+ const result = str(resolved?.result) || "none";
41706
+ const playerTotal = num(resolved?.score);
41707
+ const isComplete = result !== "none" || totalRounds > 0 && currentRound >= totalRounds;
41708
+ const won = result === "win";
41647
41709
  const opponentTotal = history.reduce((s, r) => s + r.opponentPayoff, 0);
41648
- const won = isComplete && playerTotal >= targetScore;
41649
41710
  const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
41650
41711
  const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
41651
41712
  const handleAction = useCallback((actionId) => {
@@ -41654,29 +41715,45 @@ function NegotiatorBoard({
41654
41715
  const payoff = payoffMatrix.find(
41655
41716
  (p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
41656
41717
  );
41657
- const result = {
41658
- round: currentRound + 1,
41659
- playerAction: actionId,
41660
- opponentAction,
41661
- playerPayoff: payoff?.playerPayoff ?? 0,
41662
- opponentPayoff: payoff?.opponentPayoff ?? 0
41663
- };
41664
- const newHistory = [...history, result];
41665
- setHistory(newHistory);
41666
- if (newHistory.length >= totalRounds) {
41667
- const total = newHistory.reduce((s, r) => s + r.playerPayoff, 0);
41668
- if (total >= targetScore) {
41669
- emit(`UI:${completeEvent}`, { success: true, score: total });
41670
- }
41671
- if (newHistory.length >= 3 && str(resolved?.hint)) {
41718
+ const playerPayoff = payoff?.playerPayoff ?? 0;
41719
+ setHistory((prev) => [
41720
+ ...prev,
41721
+ {
41722
+ round: prev.length + 1,
41723
+ playerAction: actionId,
41724
+ opponentAction,
41725
+ playerPayoff,
41726
+ opponentPayoff: payoff?.opponentPayoff ?? 0
41727
+ }
41728
+ ]);
41729
+ if (playRoundEvent) {
41730
+ emit(`UI:${playRoundEvent}`, { playerAction: actionId, payoff: playerPayoff });
41731
+ }
41732
+ if (totalRounds > 0 && currentRound + 1 >= totalRounds) {
41733
+ if (finishEvent) {
41734
+ emit(`UI:${finishEvent}`, {});
41735
+ }
41736
+ if (str(resolved?.hint)) {
41672
41737
  setShowHint(true);
41673
41738
  }
41674
41739
  }
41675
- }, [isComplete, resolved, totalRounds, targetScore, actions, payoffMatrix, history, currentRound, completeEvent, emit]);
41676
- const handleReset = () => {
41740
+ }, [isComplete, resolved, totalRounds, currentRound, actions, payoffMatrix, history, playRoundEvent, finishEvent, emit]);
41741
+ const handleReset = useCallback(() => {
41677
41742
  setHistory([]);
41678
41743
  setShowHint(false);
41679
- };
41744
+ if (playAgainEvent) {
41745
+ emit(`UI:${playAgainEvent}`, {});
41746
+ }
41747
+ }, [playAgainEvent, emit]);
41748
+ const completedRef = useRef(false);
41749
+ useEffect(() => {
41750
+ if (result === "win" && !completedRef.current) {
41751
+ completedRef.current = true;
41752
+ emit(`UI:${completeEvent}`, { success: true, score: playerTotal });
41753
+ } else if (result === "none") {
41754
+ completedRef.current = false;
41755
+ }
41756
+ }, [result, playerTotal, completeEvent, emit]);
41680
41757
  const getActionLabel = (id) => actions.find((a) => a.id === id)?.label ?? id;
41681
41758
  if (!resolved) return null;
41682
41759
  const theme = resolved.theme ?? void 0;
@@ -44642,67 +44719,47 @@ var init_SimulationGraph = __esm({
44642
44719
  function SimulatorBoard({
44643
44720
  entity,
44644
44721
  completeEvent = "PUZZLE_COMPLETE",
44722
+ setAEvent,
44723
+ setBEvent,
44724
+ checkEvent,
44725
+ playAgainEvent,
44645
44726
  className
44646
44727
  }) {
44647
44728
  const { emit } = useEventBus();
44648
44729
  const { t } = useTranslate();
44649
44730
  const resolved = boardEntity(entity);
44650
44731
  const parameters = Array.isArray(resolved?.parameters) ? resolved.parameters : [];
44651
- const [values, setValues] = useState(() => {
44652
- const init = {};
44653
- for (const p2 of parameters) {
44654
- init[p2.id] = p2.initial;
44655
- }
44656
- return init;
44657
- });
44658
44732
  const [headerError, setHeaderError] = useState(false);
44659
- const [submitted, setSubmitted] = useState(false);
44660
- const [attempts, setAttempts] = useState(0);
44661
- const [showHint, setShowHint] = useState(false);
44662
- const computeOutput = useCallback((params) => {
44663
- try {
44664
- const fn = new Function("params", `return (${str(resolved?.computeExpression)})`);
44665
- return fn(params);
44666
- } catch {
44667
- return 0;
44668
- }
44669
- }, [resolved?.computeExpression]);
44670
- const output = useMemo(() => computeOutput(values) ?? 0, [computeOutput, values]);
44671
- const targetValue = num(resolved?.targetValue);
44672
- const targetTolerance = num(resolved?.targetTolerance);
44673
- const isCorrect = Math.abs(output - targetValue) <= targetTolerance;
44674
- const handleParameterChange = (id, value) => {
44675
- if (submitted) return;
44676
- setValues((prev) => ({ ...prev, [id]: value }));
44677
- };
44678
- const handleSubmit = () => {
44679
- setSubmitted(true);
44680
- setAttempts((a) => a + 1);
44681
- if (isCorrect) {
44682
- emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
44683
- }
44733
+ if (!resolved) return null;
44734
+ const paramA = num(resolved.paramA);
44735
+ const paramB = num(resolved.paramB);
44736
+ const output = num(resolved.output);
44737
+ const targetValue = num(resolved.target);
44738
+ const targetTolerance = num(resolved.tolerance);
44739
+ const attempts = num(resolved.attempts);
44740
+ const result = str(resolved.result);
44741
+ const isWin = result === "win";
44742
+ const isComplete = result !== "none" && result !== "";
44743
+ const paramAValue = parameters[0];
44744
+ const paramBValue = parameters[1];
44745
+ const sliderValues = [paramA, paramB];
44746
+ const sliderEvents = [setAEvent, setBEvent];
44747
+ const handleParameterChange = (index, value) => {
44748
+ if (isComplete) return;
44749
+ const ev = sliderEvents[index];
44750
+ if (ev) emit(`UI:${ev}`, { value });
44684
44751
  };
44685
- const handleReset = () => {
44686
- setSubmitted(false);
44687
- if (attempts >= 2 && str(resolved?.hint)) {
44688
- setShowHint(true);
44689
- }
44752
+ const handleCheck = () => {
44753
+ if (checkEvent) emit(`UI:${checkEvent}`, {});
44690
44754
  };
44691
- const handleFullReset = () => {
44692
- const init = {};
44693
- for (const p2 of parameters) {
44694
- init[p2.id] = p2.initial;
44695
- }
44696
- setValues(init);
44697
- setSubmitted(false);
44698
- setAttempts(0);
44699
- setShowHint(false);
44755
+ const handlePlayAgain = () => {
44756
+ if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
44700
44757
  };
44701
- if (!resolved) return null;
44702
44758
  const theme = resolved.theme ?? void 0;
44703
44759
  const themeBackground = theme?.background;
44704
44760
  const headerImage = str(resolved.headerImage);
44705
44761
  const hint = str(resolved.hint);
44762
+ const showHint = isComplete && !isWin && attempts >= 2 && Boolean(hint);
44706
44763
  const outputLabel = str(resolved.outputLabel);
44707
44764
  const outputUnit = str(resolved.outputUnit);
44708
44765
  return /* @__PURE__ */ jsx(
@@ -44722,41 +44779,43 @@ function SimulatorBoard({
44722
44779
  ] }) }),
44723
44780
  /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", children: [
44724
44781
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("simulator.parameters") }),
44725
- parameters.map((param) => /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
44726
- /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "center", children: [
44727
- /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "medium", children: param.label }),
44728
- /* @__PURE__ */ jsxs(Badge, { size: "sm", children: [
44729
- values[param.id],
44730
- " ",
44731
- param.unit
44732
- ] })
44733
- ] }),
44734
- /* @__PURE__ */ jsx(
44735
- "input",
44736
- {
44737
- type: "range",
44738
- min: param.min,
44739
- max: param.max,
44740
- step: param.step,
44741
- value: values[param.id],
44742
- onChange: (e) => handleParameterChange(param.id, Number(e.target.value)),
44743
- disabled: submitted,
44744
- className: "w-full accent-foreground"
44745
- }
44746
- ),
44747
- /* @__PURE__ */ jsxs(HStack, { justify: "between", children: [
44748
- /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
44749
- param.min,
44750
- " ",
44751
- param.unit
44782
+ [paramAValue, paramBValue].map(
44783
+ (param, index) => param ? /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
44784
+ /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "center", children: [
44785
+ /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "medium", children: param.label }),
44786
+ /* @__PURE__ */ jsxs(Badge, { size: "sm", children: [
44787
+ sliderValues[index],
44788
+ " ",
44789
+ param.unit
44790
+ ] })
44752
44791
  ] }),
44753
- /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
44754
- param.max,
44755
- " ",
44756
- param.unit
44792
+ /* @__PURE__ */ jsx(
44793
+ "input",
44794
+ {
44795
+ type: "range",
44796
+ min: param.min,
44797
+ max: param.max,
44798
+ step: param.step,
44799
+ value: sliderValues[index],
44800
+ onChange: (e) => handleParameterChange(index, Number(e.target.value)),
44801
+ disabled: isComplete,
44802
+ className: "w-full accent-foreground"
44803
+ }
44804
+ ),
44805
+ /* @__PURE__ */ jsxs(HStack, { justify: "between", children: [
44806
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
44807
+ param.min,
44808
+ " ",
44809
+ param.unit
44810
+ ] }),
44811
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
44812
+ param.max,
44813
+ " ",
44814
+ param.unit
44815
+ ] })
44757
44816
  ] })
44758
- ] })
44759
- ] }, param.id))
44817
+ ] }, param.id ?? index) : null
44818
+ )
44760
44819
  ] }) }),
44761
44820
  /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
44762
44821
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: outputLabel }),
@@ -44765,9 +44824,9 @@ function SimulatorBoard({
44765
44824
  " ",
44766
44825
  outputUnit
44767
44826
  ] }),
44768
- submitted && /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
44769
- /* @__PURE__ */ jsx(Icon, { icon: isCorrect ? CheckCircle : XCircle, size: "sm", className: isCorrect ? "text-success" : "text-error" }),
44770
- /* @__PURE__ */ jsx(Typography, { variant: "body", className: isCorrect ? "text-success" : "text-error", children: isCorrect ? str(resolved.successMessage) || t("simulator.correct") : str(resolved.failMessage) || t("simulator.incorrect") })
44827
+ isComplete && /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
44828
+ /* @__PURE__ */ jsx(Icon, { icon: isWin ? CheckCircle : XCircle, size: "sm", className: isWin ? "text-success" : "text-error" }),
44829
+ /* @__PURE__ */ jsx(Typography, { variant: "body", className: isWin ? "text-success" : "text-error", children: isWin ? str(resolved.successMessage) || t("simulator.correct") : str(resolved.failMessage) || t("simulator.incorrect") })
44771
44830
  ] }),
44772
44831
  /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
44773
44832
  t("simulator.target"),
@@ -44782,11 +44841,11 @@ function SimulatorBoard({
44782
44841
  ] }) }),
44783
44842
  showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
44784
44843
  /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
44785
- !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, children: [
44844
+ !isComplete ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleCheck, children: [
44786
44845
  /* @__PURE__ */ jsx(Icon, { icon: Play, size: "sm" }),
44787
44846
  t("simulator.simulate")
44788
- ] }) : !isCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("simulator.tryAgain") }) : null,
44789
- /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handleFullReset, children: [
44847
+ ] }) : null,
44848
+ /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handlePlayAgain, children: [
44790
44849
  /* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
44791
44850
  t("simulator.reset")
44792
44851
  ] })