@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 { clsx } from 'clsx';
7
7
  import { twMerge } from 'tailwind-merge';
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 } from '@almadar/ui/hooks';
15
12
  import { evaluate, createMinimalContext } from '@almadar/evaluator';
@@ -793,6 +790,41 @@ function kebabToPascal(name) {
793
790
  return part.charAt(0).toUpperCase() + part.slice(1);
794
791
  }).join("");
795
792
  }
793
+ function loadLib(key, importer) {
794
+ let p2 = libPromises.get(key);
795
+ if (!p2) {
796
+ p2 = importer().then((m) => m);
797
+ libPromises.set(key, p2);
798
+ }
799
+ return p2;
800
+ }
801
+ function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
802
+ const Lazy = React83__default.lazy(async () => {
803
+ const lib = await loadLib(libKey, importer);
804
+ const Comp = pick(lib);
805
+ if (!Comp) {
806
+ warnFallback(fallbackName, family);
807
+ return { default: makeLucideAdapter(fallbackName, true) };
808
+ }
809
+ return { default: Comp };
810
+ });
811
+ const Wrapped = (props) => /* @__PURE__ */ jsx(
812
+ React83__default.Suspense,
813
+ {
814
+ fallback: /* @__PURE__ */ jsx(
815
+ "span",
816
+ {
817
+ "aria-hidden": true,
818
+ className: props.className,
819
+ style: { display: "inline-block", ...props.style }
820
+ }
821
+ ),
822
+ children: /* @__PURE__ */ jsx(Lazy, { ...props })
823
+ }
824
+ );
825
+ Wrapped.displayName = `Lazy.${libKey}.${fallbackName}`;
826
+ return Wrapped;
827
+ }
796
828
  function resolveLucide(name) {
797
829
  if (lucideAliases[name]) return lucideAliases[name];
798
830
  const pascal = kebabToPascal(name);
@@ -803,60 +835,81 @@ function resolveLucide(name) {
803
835
  if (asIs && typeof asIs === "object") return asIs;
804
836
  return LucideIcons2.HelpCircle;
805
837
  }
806
- function resolvePhosphor(name, weight) {
838
+ function resolvePhosphor(name, weight, family) {
807
839
  const target = phosphorAliases[name] ?? kebabToPascal(name);
808
- const map = PhosphorIcons;
809
- const PhosphorComp = map[target];
810
- if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
811
- const Component = PhosphorComp;
812
- const Adapter = (props) => /* @__PURE__ */ jsx(
813
- Component,
814
- {
815
- weight,
816
- className: props.className,
817
- style: props.style,
818
- size: props.size ?? "1em"
819
- }
840
+ return lazyFamilyIcon(
841
+ "phosphor",
842
+ () => import('@phosphor-icons/react'),
843
+ (lib) => {
844
+ const PhosphorComp = lib[target];
845
+ if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
846
+ const Component = PhosphorComp;
847
+ const Adapter = (props) => /* @__PURE__ */ jsx(
848
+ Component,
849
+ {
850
+ weight,
851
+ className: props.className,
852
+ style: props.style,
853
+ size: props.size ?? "1em"
854
+ }
855
+ );
856
+ Adapter.displayName = `Phosphor.${target}.${weight}`;
857
+ return Adapter;
858
+ },
859
+ name,
860
+ family
820
861
  );
821
- Adapter.displayName = `Phosphor.${target}.${weight}`;
822
- return Adapter;
823
862
  }
824
- function resolveTabler(name) {
863
+ function resolveTabler(name, family) {
825
864
  const suffix = tablerAliases[name] ?? kebabToPascal(name);
826
865
  const target = `Icon${suffix}`;
827
- const map = TablerIcons;
828
- const TablerComp = map[target];
829
- if (!TablerComp || typeof TablerComp !== "object") return null;
830
- const Component = TablerComp;
831
- const Adapter = (props) => /* @__PURE__ */ jsx(
832
- Component,
833
- {
834
- stroke: props.strokeWidth ?? 1.5,
835
- className: props.className,
836
- style: props.style,
837
- size: props.size ?? 24
838
- }
866
+ return lazyFamilyIcon(
867
+ "tabler",
868
+ () => import('@tabler/icons-react'),
869
+ (lib) => {
870
+ const TablerComp = lib[target];
871
+ if (!TablerComp || typeof TablerComp !== "object") return null;
872
+ const Component = TablerComp;
873
+ const Adapter = (props) => /* @__PURE__ */ jsx(
874
+ Component,
875
+ {
876
+ stroke: props.strokeWidth ?? 1.5,
877
+ className: props.className,
878
+ style: props.style,
879
+ size: props.size ?? 24
880
+ }
881
+ );
882
+ Adapter.displayName = `Tabler.${target}`;
883
+ return Adapter;
884
+ },
885
+ name,
886
+ family
839
887
  );
840
- Adapter.displayName = `Tabler.${target}`;
841
- return Adapter;
842
888
  }
843
- function resolveFa(name) {
889
+ function resolveFa(name, family) {
844
890
  const suffix = faAliases[name] ?? kebabToPascal(name);
845
891
  const target = `Fa${suffix}`;
846
- const map = FaIcons;
847
- const FaComp = map[target];
848
- if (!FaComp || typeof FaComp !== "function") return null;
849
- const Component = FaComp;
850
- const Adapter = (props) => /* @__PURE__ */ jsx(
851
- Component,
852
- {
853
- className: props.className,
854
- style: props.style,
855
- size: props.size ?? "1em"
856
- }
892
+ return lazyFamilyIcon(
893
+ "fa",
894
+ () => import('react-icons/fa'),
895
+ (lib) => {
896
+ const FaComp = lib[target];
897
+ if (!FaComp || typeof FaComp !== "function") return null;
898
+ const Component = FaComp;
899
+ const Adapter = (props) => /* @__PURE__ */ jsx(
900
+ Component,
901
+ {
902
+ className: props.className,
903
+ style: props.style,
904
+ size: props.size ?? "1em"
905
+ }
906
+ );
907
+ Adapter.displayName = `Fa.${target}`;
908
+ return Adapter;
909
+ },
910
+ name,
911
+ family
857
912
  );
858
- Adapter.displayName = `Fa.${target}`;
859
- return Adapter;
860
913
  }
861
914
  function warnFallback(name, family) {
862
915
  const key = `${family}::${name}`;
@@ -890,39 +943,22 @@ function resolveIconForFamily(name, family) {
890
943
  switch (family) {
891
944
  case "lucide":
892
945
  return makeLucideAdapter(name, false);
893
- case "phosphor-outline": {
894
- const p2 = resolvePhosphor(name, "regular");
895
- if (p2) return p2;
896
- warnFallback(name, family);
897
- return makeLucideAdapter(name, true);
898
- }
899
- case "phosphor-fill": {
900
- const p2 = resolvePhosphor(name, "fill");
901
- if (p2) return p2;
902
- warnFallback(name, family);
903
- return makeLucideAdapter(name, true);
904
- }
905
- case "phosphor-duotone": {
906
- const p2 = resolvePhosphor(name, "duotone");
907
- if (p2) return p2;
908
- warnFallback(name, family);
909
- return makeLucideAdapter(name, true);
910
- }
911
- case "tabler": {
912
- const t = resolveTabler(name);
913
- if (t) return t;
914
- warnFallback(name, family);
915
- return makeLucideAdapter(name, true);
916
- }
917
- case "fa-solid": {
918
- const f3 = resolveFa(name);
919
- if (f3) return f3;
920
- warnFallback(name, family);
921
- return makeLucideAdapter(name, true);
922
- }
923
- }
924
- }
925
- var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
946
+ // Non-lucide families resolve to a lazy, Suspense-wrapped component that
947
+ // dynamic-imports the library on first render and falls back to lucide
948
+ // internally when the family lacks the icon (see lazyFamilyIcon).
949
+ case "phosphor-outline":
950
+ return resolvePhosphor(name, "regular", family);
951
+ case "phosphor-fill":
952
+ return resolvePhosphor(name, "fill", family);
953
+ case "phosphor-duotone":
954
+ return resolvePhosphor(name, "duotone", family);
955
+ case "tabler":
956
+ return resolveTabler(name, family);
957
+ case "fa-solid":
958
+ return resolveFa(name, family);
959
+ }
960
+ }
961
+ var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, libPromises, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
926
962
  var init_iconFamily = __esm({
927
963
  "lib/iconFamily.tsx"() {
928
964
  "use client";
@@ -938,6 +974,7 @@ var init_iconFamily = __esm({
938
974
  cachedFamily = null;
939
975
  listeners = /* @__PURE__ */ new Set();
940
976
  observer = null;
977
+ libPromises = /* @__PURE__ */ new Map();
941
978
  lucideAliases = {
942
979
  close: LucideIcons2.X,
943
980
  trash: LucideIcons2.Trash2,
@@ -17372,61 +17409,53 @@ var init_Breadcrumb = __esm({
17372
17409
  function BuilderBoard({
17373
17410
  entity,
17374
17411
  completeEvent = "PUZZLE_COMPLETE",
17412
+ placeEvent,
17413
+ checkEvent,
17414
+ playAgainEvent,
17375
17415
  className
17376
17416
  }) {
17377
17417
  const { emit } = useEventBus();
17378
17418
  const { t } = useTranslate();
17379
17419
  const resolved = boardEntity(entity);
17380
- const [placements, setPlacements] = useState({});
17381
17420
  const [headerError, setHeaderError] = useState(false);
17382
- const [submitted, setSubmitted] = useState(false);
17383
- const [attempts, setAttempts] = useState(0);
17384
- const [showHint, setShowHint] = useState(false);
17421
+ const [selectedComponent, setSelectedComponent] = useState(null);
17385
17422
  const components = Array.isArray(resolved?.components) ? resolved.components : [];
17386
17423
  const slots = Array.isArray(resolved?.slots) ? resolved.slots : [];
17424
+ const placements = {};
17425
+ for (const slot of slots) {
17426
+ if (slot.placedComponentId) placements[slot.id] = slot.placedComponentId;
17427
+ }
17428
+ const attempts = num(resolved?.attempts);
17429
+ const result = str(resolved?.result) || "none";
17430
+ const submitted = result === "win";
17387
17431
  const usedComponentIds = new Set(Object.values(placements));
17388
17432
  const availableComponents = components.filter((c) => !usedComponentIds.has(c.id));
17389
- const [selectedComponent, setSelectedComponent] = useState(null);
17390
- const allPlaced = Object.keys(placements).length === slots.length;
17433
+ const allPlaced = slots.length > 0 && slots.every((s) => Boolean(placements[s.id]));
17391
17434
  const results = submitted ? slots.map((slot) => ({
17392
17435
  slot,
17393
17436
  placed: placements[slot.id],
17394
- correct: placements[slot.id] === slot.acceptsComponentId
17437
+ correct: placements[slot.id] === slot.requiredComponentId
17395
17438
  })) : [];
17396
- const allCorrect = results.length > 0 && results.every((r) => r.correct);
17439
+ const showHint = attempts >= 2 && Boolean(str(resolved?.hint));
17397
17440
  const handlePlaceComponent = (slotId) => {
17398
17441
  if (submitted || !selectedComponent) return;
17399
- setPlacements((prev) => ({ ...prev, [slotId]: selectedComponent }));
17442
+ if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: selectedComponent });
17400
17443
  setSelectedComponent(null);
17401
17444
  };
17402
17445
  const handleRemoveFromSlot = (slotId) => {
17403
17446
  if (submitted) return;
17404
- setPlacements((prev) => {
17405
- const next = { ...prev };
17406
- delete next[slotId];
17407
- return next;
17408
- });
17447
+ if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: "" });
17409
17448
  };
17410
- const handleSubmit = useCallback(() => {
17411
- setSubmitted(true);
17412
- setAttempts((a) => a + 1);
17413
- const correct = slots.every((slot) => placements[slot.id] === slot.acceptsComponentId);
17414
- if (correct) {
17449
+ const handleSubmit = () => {
17450
+ if (checkEvent) emit(`UI:${checkEvent}`, {});
17451
+ const solved = slots.length > 0 && slots.every((s) => placements[s.id] === s.requiredComponentId);
17452
+ if (solved && completeEvent) {
17415
17453
  emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
17416
17454
  }
17417
- }, [slots, placements, attempts, completeEvent, emit]);
17418
- const handleReset = () => {
17419
- setSubmitted(false);
17420
- if (attempts >= 2 && str(resolved?.hint)) {
17421
- setShowHint(true);
17422
- }
17423
17455
  };
17424
- const handleFullReset = () => {
17425
- setPlacements({});
17426
- setSubmitted(false);
17456
+ const handlePlayAgain = () => {
17427
17457
  setSelectedComponent(null);
17428
- setAttempts(0);
17429
- setShowHint(false);
17458
+ if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
17430
17459
  };
17431
17460
  const getComponentById = (id) => components.find((c) => c.id === id);
17432
17461
  if (!resolved) return null;
@@ -17476,13 +17505,13 @@ function BuilderBoard({
17476
17505
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("builder.blueprint") }),
17477
17506
  /* @__PURE__ */ jsx(VStack, { gap: "sm", children: slots.map((slot) => {
17478
17507
  const placedComp = placements[slot.id] ? getComponentById(placements[slot.id]) : null;
17479
- const result = results.find((r) => r.slot.id === slot.id);
17508
+ const result2 = results.find((r) => r.slot.id === slot.id);
17480
17509
  return /* @__PURE__ */ jsxs(
17481
17510
  HStack,
17482
17511
  {
17483
17512
  gap: "sm",
17484
17513
  align: "center",
17485
- className: `p-3 border-2 rounded ${result ? result.correct ? "border-success" : "border-error" : selectedComponent ? "border-dashed border-foreground cursor-pointer" : "border-border"}`,
17514
+ className: `p-3 border-2 rounded ${result2 ? result2.correct ? "border-success" : "border-error" : selectedComponent ? "border-dashed border-foreground cursor-pointer" : "border-border"}`,
17486
17515
  onClick: () => handlePlaceComponent(slot.id),
17487
17516
  children: [
17488
17517
  /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "flex-1", children: [
@@ -17497,7 +17526,7 @@ function BuilderBoard({
17497
17526
  ] }) : null,
17498
17527
  placedComp.label
17499
17528
  ] }),
17500
- result && /* @__PURE__ */ jsx(Icon, { icon: result.correct ? CheckCircle : XCircle, size: "sm", className: result.correct ? "text-success" : "text-error" })
17529
+ result2 && /* @__PURE__ */ jsx(Icon, { icon: result2.correct ? CheckCircle : XCircle, size: "sm", className: result2.correct ? "text-success" : "text-error" })
17501
17530
  ] }) : /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("builder.empty") })
17502
17531
  ]
17503
17532
  },
@@ -17506,16 +17535,16 @@ function BuilderBoard({
17506
17535
  }) })
17507
17536
  ] }) }),
17508
17537
  submitted && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
17509
- /* @__PURE__ */ jsx(Icon, { icon: allCorrect ? CheckCircle : XCircle, size: "lg", className: allCorrect ? "text-success" : "text-error" }),
17510
- /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("builder.success") : str(resolved.failMessage) || t("builder.incorrect") })
17538
+ /* @__PURE__ */ jsx(Icon, { icon: CheckCircle, size: "lg", className: "text-success" }),
17539
+ /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: str(resolved.successMessage) || t("builder.success") })
17511
17540
  ] }) }),
17512
17541
  showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
17513
17542
  /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
17514
- !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
17543
+ !submitted && /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
17515
17544
  /* @__PURE__ */ jsx(Icon, { icon: Wrench, size: "sm" }),
17516
17545
  t("builder.build")
17517
- ] }) : !allCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("builder.tryAgain") }) : null,
17518
- /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handleFullReset, children: [
17546
+ ] }),
17547
+ /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handlePlayAgain, children: [
17519
17548
  /* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
17520
17549
  t("builder.reset")
17521
17550
  ] })
@@ -20971,57 +21000,84 @@ var init_ChartLegend = __esm({
20971
21000
  function ClassifierBoard({
20972
21001
  entity,
20973
21002
  completeEvent = "PUZZLE_COMPLETE",
21003
+ assignEvent,
21004
+ checkEvent,
21005
+ playAgainEvent,
20974
21006
  className
20975
21007
  }) {
20976
21008
  const { emit } = useEventBus();
20977
21009
  const { t } = useTranslate();
20978
21010
  const resolved = boardEntity(entity);
20979
- const [assignments, setAssignments] = useState({});
21011
+ const [localAssignments, setLocalAssignments] = useState({});
20980
21012
  const [headerError, setHeaderError] = useState(false);
20981
- const [submitted, setSubmitted] = useState(false);
20982
- const [attempts, setAttempts] = useState(0);
21013
+ const [localSubmitted, setLocalSubmitted] = useState(false);
21014
+ const [localAttempts, setLocalAttempts] = useState(0);
20983
21015
  const [showHint, setShowHint] = useState(false);
20984
21016
  const items = Array.isArray(resolved?.items) ? resolved.items : [];
20985
21017
  const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
21018
+ const entityResult = str(resolved?.result);
21019
+ const entityDrivesResult = entityResult.length > 0;
21020
+ const entityHasAssignments = items.some((item) => item.assignedCategory != null);
21021
+ const assignments = entityHasAssignments ? items.reduce((acc, item) => {
21022
+ if (item.assignedCategory != null) acc[item.id] = item.assignedCategory;
21023
+ return acc;
21024
+ }, {}) : localAssignments;
21025
+ const attempts = entityDrivesResult ? num(resolved?.attempts) : localAttempts;
21026
+ const submitted = entityDrivesResult || localSubmitted;
20986
21027
  const unassignedItems = items.filter((item) => !assignments[item.id]);
20987
- const allAssigned = Object.keys(assignments).length === items.length;
21028
+ const allAssigned = items.length > 0 && Object.keys(assignments).length === items.length;
20988
21029
  const results = submitted ? items.map((item) => ({
20989
21030
  item,
20990
21031
  assigned: assignments[item.id],
20991
21032
  correct: assignments[item.id] === item.correctCategory
20992
21033
  })) : [];
20993
- const allCorrect = results.length > 0 && results.every((r) => r.correct);
21034
+ const allCorrect = entityDrivesResult ? entityResult === "success" : results.length > 0 && results.every((r) => r.correct);
20994
21035
  const correctCount = results.filter((r) => r.correct).length;
20995
21036
  const handleAssign = (itemId, categoryId) => {
20996
21037
  if (submitted) return;
20997
- setAssignments((prev) => ({ ...prev, [itemId]: categoryId }));
21038
+ if (assignEvent) {
21039
+ emit(`UI:${assignEvent}`, { itemId, categoryId });
21040
+ }
21041
+ if (!entityHasAssignments) {
21042
+ setLocalAssignments((prev) => ({ ...prev, [itemId]: categoryId }));
21043
+ }
20998
21044
  };
20999
21045
  const handleUnassign = (itemId) => {
21000
21046
  if (submitted) return;
21001
- setAssignments((prev) => {
21002
- const next = { ...prev };
21003
- delete next[itemId];
21004
- return next;
21005
- });
21047
+ if (!entityHasAssignments) {
21048
+ setLocalAssignments((prev) => {
21049
+ const next = { ...prev };
21050
+ delete next[itemId];
21051
+ return next;
21052
+ });
21053
+ }
21006
21054
  };
21007
21055
  const handleSubmit = useCallback(() => {
21008
- setSubmitted(true);
21009
- setAttempts((a) => a + 1);
21010
- const correct = items.every((item) => assignments[item.id] === item.correctCategory);
21011
- if (correct) {
21012
- emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
21056
+ if (checkEvent) {
21057
+ emit(`UI:${checkEvent}`, {});
21058
+ }
21059
+ if (!entityDrivesResult) {
21060
+ setLocalSubmitted(true);
21061
+ setLocalAttempts((a) => a + 1);
21062
+ const correct = items.every((item) => assignments[item.id] === item.correctCategory);
21063
+ if (correct) {
21064
+ emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
21065
+ }
21013
21066
  }
21014
- }, [items, assignments, attempts, completeEvent, emit]);
21067
+ }, [checkEvent, entityDrivesResult, items, assignments, attempts, completeEvent, emit]);
21015
21068
  const handleReset = () => {
21016
- setSubmitted(false);
21069
+ if (!entityDrivesResult) setLocalSubmitted(false);
21017
21070
  if (attempts >= 2 && str(resolved?.hint)) {
21018
21071
  setShowHint(true);
21019
21072
  }
21020
21073
  };
21021
21074
  const handleFullReset = () => {
21022
- setAssignments({});
21023
- setSubmitted(false);
21024
- setAttempts(0);
21075
+ if (playAgainEvent) {
21076
+ emit(`UI:${playAgainEvent}`, {});
21077
+ }
21078
+ setLocalAssignments({});
21079
+ setLocalSubmitted(false);
21080
+ setLocalAttempts(0);
21025
21081
  setShowHint(false);
21026
21082
  };
21027
21083
  if (!resolved) return null;
@@ -28904,13 +28960,13 @@ var init_MapView = __esm({
28904
28960
  shadowSize: [41, 41]
28905
28961
  });
28906
28962
  L.Marker.prototype.options.icon = defaultIcon;
28907
- const { useEffect: useEffect72, useRef: useRef67, useCallback: useCallback113, useState: useState104 } = React83__default;
28963
+ const { useEffect: useEffect73, useRef: useRef68, useCallback: useCallback111, useState: useState104 } = React83__default;
28908
28964
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
28909
28965
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
28910
28966
  function MapUpdater({ centerLat, centerLng, zoom }) {
28911
28967
  const map = useMap();
28912
- const prevRef = useRef67({ centerLat, centerLng, zoom });
28913
- useEffect72(() => {
28968
+ const prevRef = useRef68({ centerLat, centerLng, zoom });
28969
+ useEffect73(() => {
28914
28970
  const prev = prevRef.current;
28915
28971
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
28916
28972
  map.setView([centerLat, centerLng], zoom);
@@ -28921,7 +28977,7 @@ var init_MapView = __esm({
28921
28977
  }
28922
28978
  function MapClickHandler({ onMapClick }) {
28923
28979
  const map = useMap();
28924
- useEffect72(() => {
28980
+ useEffect73(() => {
28925
28981
  if (!onMapClick) return;
28926
28982
  const handler = (e) => {
28927
28983
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -28950,7 +29006,7 @@ var init_MapView = __esm({
28950
29006
  }) {
28951
29007
  const eventBus = useEventBus2();
28952
29008
  const [clickedPosition, setClickedPosition] = useState104(null);
28953
- const handleMapClick = useCallback113((lat, lng) => {
29009
+ const handleMapClick = useCallback111((lat, lng) => {
28954
29010
  if (showClickedPin) {
28955
29011
  setClickedPosition({ lat, lng });
28956
29012
  }
@@ -28959,7 +29015,7 @@ var init_MapView = __esm({
28959
29015
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
28960
29016
  }
28961
29017
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
28962
- const handleMarkerClick = useCallback113((marker) => {
29018
+ const handleMarkerClick = useCallback111((marker) => {
28963
29019
  onMarkerClick?.(marker);
28964
29020
  if (markerClickEvent) {
28965
29021
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -38181,51 +38237,52 @@ var init_DataTable = __esm({
38181
38237
  function DebuggerBoard({
38182
38238
  entity,
38183
38239
  completeEvent = "PUZZLE_COMPLETE",
38240
+ toggleFlagEvent,
38241
+ checkEvent,
38242
+ playAgainEvent,
38184
38243
  className
38185
38244
  }) {
38186
38245
  const { emit } = useEventBus();
38187
38246
  const { t } = useTranslate();
38188
38247
  const resolved = boardEntity(entity);
38189
- const [flaggedLines, setFlaggedLines] = useState(/* @__PURE__ */ new Set());
38190
38248
  const [headerError, setHeaderError] = useState(false);
38191
- const [submitted, setSubmitted] = useState(false);
38192
- const [attempts, setAttempts] = useState(0);
38193
38249
  const [showHint, setShowHint] = useState(false);
38250
+ const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
38251
+ const result = resolved?.result ?? null;
38252
+ const attempts = num(resolved?.attempts);
38253
+ const submitted = result != null;
38254
+ const bugLines = lines.filter((l) => l.isBug);
38255
+ const flaggedLines = lines.filter((l) => l.isFlagged);
38256
+ const correctFlags = lines.filter((l) => l.isBug && l.isFlagged);
38257
+ const falseFlags = lines.filter((l) => !l.isBug && l.isFlagged);
38258
+ const allCorrect = result === "win";
38194
38259
  const toggleLine = (lineId) => {
38195
38260
  if (submitted) return;
38196
- setFlaggedLines((prev) => {
38197
- const next = new Set(prev);
38198
- if (next.has(lineId)) {
38199
- next.delete(lineId);
38200
- } else {
38201
- next.add(lineId);
38202
- }
38203
- return next;
38204
- });
38261
+ if (toggleFlagEvent) {
38262
+ emit(`UI:${toggleFlagEvent}`, { lineId });
38263
+ }
38205
38264
  };
38206
- const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
38207
- const bugLines = lines.filter((l) => l.isBug);
38208
- const correctFlags = lines.filter((l) => l.isBug && flaggedLines.has(l.id));
38209
- const falseFlags = lines.filter((l) => !l.isBug && flaggedLines.has(l.id));
38210
- const allCorrect = submitted && correctFlags.length === bugLines.length && falseFlags.length === 0;
38211
38265
  const handleSubmit = useCallback(() => {
38212
- setSubmitted(true);
38213
- setAttempts((a) => a + 1);
38266
+ if (checkEvent) {
38267
+ emit(`UI:${checkEvent}`, {});
38268
+ }
38214
38269
  const correct = correctFlags.length === bugLines.length && falseFlags.length === 0;
38215
38270
  if (correct) {
38216
38271
  emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
38217
38272
  }
38218
- }, [correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
38273
+ }, [checkEvent, correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
38219
38274
  const handleReset = () => {
38220
- setSubmitted(false);
38275
+ if (playAgainEvent) {
38276
+ emit(`UI:${playAgainEvent}`, {});
38277
+ }
38221
38278
  if (attempts >= 2 && str(resolved?.hint)) {
38222
38279
  setShowHint(true);
38223
38280
  }
38224
38281
  };
38225
38282
  const handleFullReset = () => {
38226
- setFlaggedLines(/* @__PURE__ */ new Set());
38227
- setSubmitted(false);
38228
- setAttempts(0);
38283
+ if (playAgainEvent) {
38284
+ emit(`UI:${playAgainEvent}`, {});
38285
+ }
38229
38286
  setShowHint(false);
38230
38287
  };
38231
38288
  if (!resolved) return null;
@@ -38253,7 +38310,7 @@ function DebuggerBoard({
38253
38310
  /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(num(resolved.bugCount)) }) })
38254
38311
  ] }) }),
38255
38312
  /* @__PURE__ */ jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsx(VStack, { gap: "none", children: lines.map((line, i) => {
38256
- const isFlagged = flaggedLines.has(line.id);
38313
+ const isFlagged = !!line.isFlagged;
38257
38314
  let lineStyle = "";
38258
38315
  if (submitted) {
38259
38316
  if (line.isBug && isFlagged) lineStyle = "bg-success/10";
@@ -38287,9 +38344,9 @@ function DebuggerBoard({
38287
38344
  /* @__PURE__ */ jsx(
38288
38345
  Icon,
38289
38346
  {
38290
- icon: flaggedLines.has(line.id) ? CheckCircle : XCircle,
38347
+ icon: line.isFlagged ? CheckCircle : XCircle,
38291
38348
  size: "xs",
38292
- className: flaggedLines.has(line.id) ? "text-success mt-0.5" : "text-warning mt-0.5"
38349
+ className: line.isFlagged ? "text-success mt-0.5" : "text-warning mt-0.5"
38293
38350
  }
38294
38351
  ),
38295
38352
  /* @__PURE__ */ jsxs(VStack, { gap: "none", children: [
@@ -38300,7 +38357,7 @@ function DebuggerBoard({
38300
38357
  ] }) }),
38301
38358
  showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
38302
38359
  /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
38303
- !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.size === 0, children: [
38360
+ !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.length === 0, children: [
38304
38361
  /* @__PURE__ */ jsx(Icon, { icon: Send, size: "sm" }),
38305
38362
  t("debugger.submit")
38306
38363
  ] }) : !allCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("debugger.tryAgain") }) : null,
@@ -42064,6 +42121,9 @@ function getOpponentAction(strategy, actions, history) {
42064
42121
  function NegotiatorBoard({
42065
42122
  entity,
42066
42123
  completeEvent = "PUZZLE_COMPLETE",
42124
+ playRoundEvent,
42125
+ finishEvent,
42126
+ playAgainEvent,
42067
42127
  className
42068
42128
  }) {
42069
42129
  const { emit } = useEventBus();
@@ -42072,13 +42132,14 @@ function NegotiatorBoard({
42072
42132
  const [history, setHistory] = useState([]);
42073
42133
  const [headerError, setHeaderError] = useState(false);
42074
42134
  const [showHint, setShowHint] = useState(false);
42075
- const totalRounds = num(resolved?.totalRounds);
42135
+ const totalRounds = num(resolved?.maxRounds);
42076
42136
  const targetScore = num(resolved?.targetScore);
42077
- const currentRound = history.length;
42078
- const isComplete = currentRound >= totalRounds;
42079
- const playerTotal = history.reduce((s, r) => s + r.playerPayoff, 0);
42137
+ const currentRound = num(resolved?.round);
42138
+ const result = str(resolved?.result) || "none";
42139
+ const playerTotal = num(resolved?.score);
42140
+ const isComplete = result !== "none" || totalRounds > 0 && currentRound >= totalRounds;
42141
+ const won = result === "win";
42080
42142
  const opponentTotal = history.reduce((s, r) => s + r.opponentPayoff, 0);
42081
- const won = isComplete && playerTotal >= targetScore;
42082
42143
  const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
42083
42144
  const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
42084
42145
  const handleAction = useCallback((actionId) => {
@@ -42087,29 +42148,45 @@ function NegotiatorBoard({
42087
42148
  const payoff = payoffMatrix.find(
42088
42149
  (p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
42089
42150
  );
42090
- const result = {
42091
- round: currentRound + 1,
42092
- playerAction: actionId,
42093
- opponentAction,
42094
- playerPayoff: payoff?.playerPayoff ?? 0,
42095
- opponentPayoff: payoff?.opponentPayoff ?? 0
42096
- };
42097
- const newHistory = [...history, result];
42098
- setHistory(newHistory);
42099
- if (newHistory.length >= totalRounds) {
42100
- const total = newHistory.reduce((s, r) => s + r.playerPayoff, 0);
42101
- if (total >= targetScore) {
42102
- emit(`UI:${completeEvent}`, { success: true, score: total });
42103
- }
42104
- if (newHistory.length >= 3 && str(resolved?.hint)) {
42151
+ const playerPayoff = payoff?.playerPayoff ?? 0;
42152
+ setHistory((prev) => [
42153
+ ...prev,
42154
+ {
42155
+ round: prev.length + 1,
42156
+ playerAction: actionId,
42157
+ opponentAction,
42158
+ playerPayoff,
42159
+ opponentPayoff: payoff?.opponentPayoff ?? 0
42160
+ }
42161
+ ]);
42162
+ if (playRoundEvent) {
42163
+ emit(`UI:${playRoundEvent}`, { playerAction: actionId, payoff: playerPayoff });
42164
+ }
42165
+ if (totalRounds > 0 && currentRound + 1 >= totalRounds) {
42166
+ if (finishEvent) {
42167
+ emit(`UI:${finishEvent}`, {});
42168
+ }
42169
+ if (str(resolved?.hint)) {
42105
42170
  setShowHint(true);
42106
42171
  }
42107
42172
  }
42108
- }, [isComplete, resolved, totalRounds, targetScore, actions, payoffMatrix, history, currentRound, completeEvent, emit]);
42109
- const handleReset = () => {
42173
+ }, [isComplete, resolved, totalRounds, currentRound, actions, payoffMatrix, history, playRoundEvent, finishEvent, emit]);
42174
+ const handleReset = useCallback(() => {
42110
42175
  setHistory([]);
42111
42176
  setShowHint(false);
42112
- };
42177
+ if (playAgainEvent) {
42178
+ emit(`UI:${playAgainEvent}`, {});
42179
+ }
42180
+ }, [playAgainEvent, emit]);
42181
+ const completedRef = useRef(false);
42182
+ useEffect(() => {
42183
+ if (result === "win" && !completedRef.current) {
42184
+ completedRef.current = true;
42185
+ emit(`UI:${completeEvent}`, { success: true, score: playerTotal });
42186
+ } else if (result === "none") {
42187
+ completedRef.current = false;
42188
+ }
42189
+ }, [result, playerTotal, completeEvent, emit]);
42113
42190
  const getActionLabel = (id) => actions.find((a) => a.id === id)?.label ?? id;
42114
42191
  if (!resolved) return null;
42115
42192
  const theme = resolved.theme ?? void 0;
@@ -45056,67 +45133,47 @@ var init_SimulationGraph = __esm({
45056
45133
  function SimulatorBoard({
45057
45134
  entity,
45058
45135
  completeEvent = "PUZZLE_COMPLETE",
45136
+ setAEvent,
45137
+ setBEvent,
45138
+ checkEvent,
45139
+ playAgainEvent,
45059
45140
  className
45060
45141
  }) {
45061
45142
  const { emit } = useEventBus();
45062
45143
  const { t } = useTranslate();
45063
45144
  const resolved = boardEntity(entity);
45064
45145
  const parameters = Array.isArray(resolved?.parameters) ? resolved.parameters : [];
45065
- const [values, setValues] = useState(() => {
45066
- const init = {};
45067
- for (const p2 of parameters) {
45068
- init[p2.id] = p2.initial;
45069
- }
45070
- return init;
45071
- });
45072
45146
  const [headerError, setHeaderError] = useState(false);
45073
- const [submitted, setSubmitted] = useState(false);
45074
- const [attempts, setAttempts] = useState(0);
45075
- const [showHint, setShowHint] = useState(false);
45076
- const computeOutput = useCallback((params) => {
45077
- try {
45078
- const fn = new Function("params", `return (${str(resolved?.computeExpression)})`);
45079
- return fn(params);
45080
- } catch {
45081
- return 0;
45082
- }
45083
- }, [resolved?.computeExpression]);
45084
- const output = useMemo(() => computeOutput(values) ?? 0, [computeOutput, values]);
45085
- const targetValue = num(resolved?.targetValue);
45086
- const targetTolerance = num(resolved?.targetTolerance);
45087
- const isCorrect = Math.abs(output - targetValue) <= targetTolerance;
45088
- const handleParameterChange = (id, value) => {
45089
- if (submitted) return;
45090
- setValues((prev) => ({ ...prev, [id]: value }));
45091
- };
45092
- const handleSubmit = () => {
45093
- setSubmitted(true);
45094
- setAttempts((a) => a + 1);
45095
- if (isCorrect) {
45096
- emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
45097
- }
45147
+ if (!resolved) return null;
45148
+ const paramA = num(resolved.paramA);
45149
+ const paramB = num(resolved.paramB);
45150
+ const output = num(resolved.output);
45151
+ const targetValue = num(resolved.target);
45152
+ const targetTolerance = num(resolved.tolerance);
45153
+ const attempts = num(resolved.attempts);
45154
+ const result = str(resolved.result);
45155
+ const isWin = result === "win";
45156
+ const isComplete = result !== "none" && result !== "";
45157
+ const paramAValue = parameters[0];
45158
+ const paramBValue = parameters[1];
45159
+ const sliderValues = [paramA, paramB];
45160
+ const sliderEvents = [setAEvent, setBEvent];
45161
+ const handleParameterChange = (index, value) => {
45162
+ if (isComplete) return;
45163
+ const ev = sliderEvents[index];
45164
+ if (ev) emit(`UI:${ev}`, { value });
45098
45165
  };
45099
- const handleReset = () => {
45100
- setSubmitted(false);
45101
- if (attempts >= 2 && str(resolved?.hint)) {
45102
- setShowHint(true);
45103
- }
45166
+ const handleCheck = () => {
45167
+ if (checkEvent) emit(`UI:${checkEvent}`, {});
45104
45168
  };
45105
- const handleFullReset = () => {
45106
- const init = {};
45107
- for (const p2 of parameters) {
45108
- init[p2.id] = p2.initial;
45109
- }
45110
- setValues(init);
45111
- setSubmitted(false);
45112
- setAttempts(0);
45113
- setShowHint(false);
45169
+ const handlePlayAgain = () => {
45170
+ if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
45114
45171
  };
45115
- if (!resolved) return null;
45116
45172
  const theme = resolved.theme ?? void 0;
45117
45173
  const themeBackground = theme?.background;
45118
45174
  const headerImage = str(resolved.headerImage);
45119
45175
  const hint = str(resolved.hint);
45176
+ const showHint = isComplete && !isWin && attempts >= 2 && Boolean(hint);
45120
45177
  const outputLabel = str(resolved.outputLabel);
45121
45178
  const outputUnit = str(resolved.outputUnit);
45122
45179
  return /* @__PURE__ */ jsx(
@@ -45136,41 +45193,43 @@ function SimulatorBoard({
45136
45193
  ] }) }),
45137
45194
  /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", children: [
45138
45195
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("simulator.parameters") }),
45139
- parameters.map((param) => /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
45140
- /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "center", children: [
45141
- /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "medium", children: param.label }),
45142
- /* @__PURE__ */ jsxs(Badge, { size: "sm", children: [
45143
- values[param.id],
45144
- " ",
45145
- param.unit
45146
- ] })
45147
- ] }),
45148
- /* @__PURE__ */ jsx(
45149
- "input",
45150
- {
45151
- type: "range",
45152
- min: param.min,
45153
- max: param.max,
45154
- step: param.step,
45155
- value: values[param.id],
45156
- onChange: (e) => handleParameterChange(param.id, Number(e.target.value)),
45157
- disabled: submitted,
45158
- className: "w-full accent-foreground"
45159
- }
45160
- ),
45161
- /* @__PURE__ */ jsxs(HStack, { justify: "between", children: [
45162
- /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
45163
- param.min,
45164
- " ",
45165
- param.unit
45196
+ [paramAValue, paramBValue].map(
45197
+ (param, index) => param ? /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
45198
+ /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "center", children: [
45199
+ /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "medium", children: param.label }),
45200
+ /* @__PURE__ */ jsxs(Badge, { size: "sm", children: [
45201
+ sliderValues[index],
45202
+ " ",
45203
+ param.unit
45204
+ ] })
45166
45205
  ] }),
45167
- /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
45168
- param.max,
45169
- " ",
45170
- param.unit
45206
+ /* @__PURE__ */ jsx(
45207
+ "input",
45208
+ {
45209
+ type: "range",
45210
+ min: param.min,
45211
+ max: param.max,
45212
+ step: param.step,
45213
+ value: sliderValues[index],
45214
+ onChange: (e) => handleParameterChange(index, Number(e.target.value)),
45215
+ disabled: isComplete,
45216
+ className: "w-full accent-foreground"
45217
+ }
45218
+ ),
45219
+ /* @__PURE__ */ jsxs(HStack, { justify: "between", children: [
45220
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
45221
+ param.min,
45222
+ " ",
45223
+ param.unit
45224
+ ] }),
45225
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
45226
+ param.max,
45227
+ " ",
45228
+ param.unit
45229
+ ] })
45171
45230
  ] })
45172
- ] })
45173
- ] }, param.id))
45231
+ ] }, param.id ?? index) : null
45232
+ )
45174
45233
  ] }) }),
45175
45234
  /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
45176
45235
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: outputLabel }),
@@ -45179,9 +45238,9 @@ function SimulatorBoard({
45179
45238
  " ",
45180
45239
  outputUnit
45181
45240
  ] }),
45182
- submitted && /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
45183
- /* @__PURE__ */ jsx(Icon, { icon: isCorrect ? CheckCircle : XCircle, size: "sm", className: isCorrect ? "text-success" : "text-error" }),
45184
- /* @__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") })
45241
+ isComplete && /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
45242
+ /* @__PURE__ */ jsx(Icon, { icon: isWin ? CheckCircle : XCircle, size: "sm", className: isWin ? "text-success" : "text-error" }),
45243
+ /* @__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") })
45185
45244
  ] }),
45186
45245
  /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
45187
45246
  t("simulator.target"),
@@ -45196,11 +45255,11 @@ function SimulatorBoard({
45196
45255
  ] }) }),
45197
45256
  showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
45198
45257
  /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
45199
- !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, children: [
45258
+ !isComplete ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleCheck, children: [
45200
45259
  /* @__PURE__ */ jsx(Icon, { icon: Play, size: "sm" }),
45201
45260
  t("simulator.simulate")
45202
- ] }) : !isCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("simulator.tryAgain") }) : null,
45203
- /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handleFullReset, children: [
45261
+ ] }) : null,
45262
+ /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handlePlayAgain, children: [
45204
45263
  /* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
45205
45264
  t("simulator.reset")
45206
45265
  ] })