@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.
package/dist/avl/index.js CHANGED
@@ -8,9 +8,6 @@ import { MarkerType, useReactFlow, Handle, Position, getBezierPath, EdgeLabelRen
8
8
  import { useTranslate, useEventBus as useEventBus$1 } from '@almadar/ui/hooks';
9
9
  import * as LucideIcons2 from 'lucide-react';
10
10
  import { Loader2, X, Code, FileText, WrapText, Check, Copy, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, 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';
11
- import * as PhosphorIcons from '@phosphor-icons/react';
12
- import * as TablerIcons from '@tabler/icons-react';
13
- import * as FaIcons from 'react-icons/fa';
14
11
  import { createPortal } from 'react-dom';
15
12
  import { evaluate, createMinimalContext } from '@almadar/evaluator';
16
13
  import { UISlotProvider, useUISlots } from '@almadar/ui/context';
@@ -4473,6 +4470,41 @@ function kebabToPascal(name) {
4473
4470
  return part.charAt(0).toUpperCase() + part.slice(1);
4474
4471
  }).join("");
4475
4472
  }
4473
+ function loadLib(key, importer) {
4474
+ let p2 = libPromises.get(key);
4475
+ if (!p2) {
4476
+ p2 = importer().then((m) => m);
4477
+ libPromises.set(key, p2);
4478
+ }
4479
+ return p2;
4480
+ }
4481
+ function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
4482
+ const Lazy = React91__default.lazy(async () => {
4483
+ const lib = await loadLib(libKey, importer);
4484
+ const Comp = pick(lib);
4485
+ if (!Comp) {
4486
+ warnFallback(fallbackName, family);
4487
+ return { default: makeLucideAdapter(fallbackName, true) };
4488
+ }
4489
+ return { default: Comp };
4490
+ });
4491
+ const Wrapped = (props) => /* @__PURE__ */ jsx(
4492
+ React91__default.Suspense,
4493
+ {
4494
+ fallback: /* @__PURE__ */ jsx(
4495
+ "span",
4496
+ {
4497
+ "aria-hidden": true,
4498
+ className: props.className,
4499
+ style: { display: "inline-block", ...props.style }
4500
+ }
4501
+ ),
4502
+ children: /* @__PURE__ */ jsx(Lazy, { ...props })
4503
+ }
4504
+ );
4505
+ Wrapped.displayName = `Lazy.${libKey}.${fallbackName}`;
4506
+ return Wrapped;
4507
+ }
4476
4508
  function resolveLucide(name) {
4477
4509
  if (lucideAliases[name]) return lucideAliases[name];
4478
4510
  const pascal = kebabToPascal(name);
@@ -4483,60 +4515,81 @@ function resolveLucide(name) {
4483
4515
  if (asIs && typeof asIs === "object") return asIs;
4484
4516
  return LucideIcons2.HelpCircle;
4485
4517
  }
4486
- function resolvePhosphor(name, weight) {
4518
+ function resolvePhosphor(name, weight, family) {
4487
4519
  const target = phosphorAliases[name] ?? kebabToPascal(name);
4488
- const map = PhosphorIcons;
4489
- const PhosphorComp = map[target];
4490
- if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
4491
- const Component = PhosphorComp;
4492
- const Adapter = (props) => /* @__PURE__ */ jsx(
4493
- Component,
4494
- {
4495
- weight,
4496
- className: props.className,
4497
- style: props.style,
4498
- size: props.size ?? "1em"
4499
- }
4520
+ return lazyFamilyIcon(
4521
+ "phosphor",
4522
+ () => import('@phosphor-icons/react'),
4523
+ (lib) => {
4524
+ const PhosphorComp = lib[target];
4525
+ if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
4526
+ const Component = PhosphorComp;
4527
+ const Adapter = (props) => /* @__PURE__ */ jsx(
4528
+ Component,
4529
+ {
4530
+ weight,
4531
+ className: props.className,
4532
+ style: props.style,
4533
+ size: props.size ?? "1em"
4534
+ }
4535
+ );
4536
+ Adapter.displayName = `Phosphor.${target}.${weight}`;
4537
+ return Adapter;
4538
+ },
4539
+ name,
4540
+ family
4500
4541
  );
4501
- Adapter.displayName = `Phosphor.${target}.${weight}`;
4502
- return Adapter;
4503
4542
  }
4504
- function resolveTabler(name) {
4543
+ function resolveTabler(name, family) {
4505
4544
  const suffix = tablerAliases[name] ?? kebabToPascal(name);
4506
4545
  const target = `Icon${suffix}`;
4507
- const map = TablerIcons;
4508
- const TablerComp = map[target];
4509
- if (!TablerComp || typeof TablerComp !== "object") return null;
4510
- const Component = TablerComp;
4511
- const Adapter = (props) => /* @__PURE__ */ jsx(
4512
- Component,
4513
- {
4514
- stroke: props.strokeWidth ?? 1.5,
4515
- className: props.className,
4516
- style: props.style,
4517
- size: props.size ?? 24
4518
- }
4546
+ return lazyFamilyIcon(
4547
+ "tabler",
4548
+ () => import('@tabler/icons-react'),
4549
+ (lib) => {
4550
+ const TablerComp = lib[target];
4551
+ if (!TablerComp || typeof TablerComp !== "object") return null;
4552
+ const Component = TablerComp;
4553
+ const Adapter = (props) => /* @__PURE__ */ jsx(
4554
+ Component,
4555
+ {
4556
+ stroke: props.strokeWidth ?? 1.5,
4557
+ className: props.className,
4558
+ style: props.style,
4559
+ size: props.size ?? 24
4560
+ }
4561
+ );
4562
+ Adapter.displayName = `Tabler.${target}`;
4563
+ return Adapter;
4564
+ },
4565
+ name,
4566
+ family
4519
4567
  );
4520
- Adapter.displayName = `Tabler.${target}`;
4521
- return Adapter;
4522
4568
  }
4523
- function resolveFa(name) {
4569
+ function resolveFa(name, family) {
4524
4570
  const suffix = faAliases[name] ?? kebabToPascal(name);
4525
4571
  const target = `Fa${suffix}`;
4526
- const map = FaIcons;
4527
- const FaComp = map[target];
4528
- if (!FaComp || typeof FaComp !== "function") return null;
4529
- const Component = FaComp;
4530
- const Adapter = (props) => /* @__PURE__ */ jsx(
4531
- Component,
4532
- {
4533
- className: props.className,
4534
- style: props.style,
4535
- size: props.size ?? "1em"
4536
- }
4572
+ return lazyFamilyIcon(
4573
+ "fa",
4574
+ () => import('react-icons/fa'),
4575
+ (lib) => {
4576
+ const FaComp = lib[target];
4577
+ if (!FaComp || typeof FaComp !== "function") return null;
4578
+ const Component = FaComp;
4579
+ const Adapter = (props) => /* @__PURE__ */ jsx(
4580
+ Component,
4581
+ {
4582
+ className: props.className,
4583
+ style: props.style,
4584
+ size: props.size ?? "1em"
4585
+ }
4586
+ );
4587
+ Adapter.displayName = `Fa.${target}`;
4588
+ return Adapter;
4589
+ },
4590
+ name,
4591
+ family
4537
4592
  );
4538
- Adapter.displayName = `Fa.${target}`;
4539
- return Adapter;
4540
4593
  }
4541
4594
  function warnFallback(name, family) {
4542
4595
  const key = `${family}::${name}`;
@@ -4570,39 +4623,22 @@ function resolveIconForFamily(name, family) {
4570
4623
  switch (family) {
4571
4624
  case "lucide":
4572
4625
  return makeLucideAdapter(name, false);
4573
- case "phosphor-outline": {
4574
- const p2 = resolvePhosphor(name, "regular");
4575
- if (p2) return p2;
4576
- warnFallback(name, family);
4577
- return makeLucideAdapter(name, true);
4578
- }
4579
- case "phosphor-fill": {
4580
- const p2 = resolvePhosphor(name, "fill");
4581
- if (p2) return p2;
4582
- warnFallback(name, family);
4583
- return makeLucideAdapter(name, true);
4584
- }
4585
- case "phosphor-duotone": {
4586
- const p2 = resolvePhosphor(name, "duotone");
4587
- if (p2) return p2;
4588
- warnFallback(name, family);
4589
- return makeLucideAdapter(name, true);
4590
- }
4591
- case "tabler": {
4592
- const t = resolveTabler(name);
4593
- if (t) return t;
4594
- warnFallback(name, family);
4595
- return makeLucideAdapter(name, true);
4596
- }
4597
- case "fa-solid": {
4598
- const f3 = resolveFa(name);
4599
- if (f3) return f3;
4600
- warnFallback(name, family);
4601
- return makeLucideAdapter(name, true);
4602
- }
4603
- }
4604
- }
4605
- var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
4626
+ // Non-lucide families resolve to a lazy, Suspense-wrapped component that
4627
+ // dynamic-imports the library on first render and falls back to lucide
4628
+ // internally when the family lacks the icon (see lazyFamilyIcon).
4629
+ case "phosphor-outline":
4630
+ return resolvePhosphor(name, "regular", family);
4631
+ case "phosphor-fill":
4632
+ return resolvePhosphor(name, "fill", family);
4633
+ case "phosphor-duotone":
4634
+ return resolvePhosphor(name, "duotone", family);
4635
+ case "tabler":
4636
+ return resolveTabler(name, family);
4637
+ case "fa-solid":
4638
+ return resolveFa(name, family);
4639
+ }
4640
+ }
4641
+ var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, libPromises, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
4606
4642
  var init_iconFamily = __esm({
4607
4643
  "lib/iconFamily.tsx"() {
4608
4644
  "use client";
@@ -4618,6 +4654,7 @@ var init_iconFamily = __esm({
4618
4654
  cachedFamily = null;
4619
4655
  listeners = /* @__PURE__ */ new Set();
4620
4656
  observer = null;
4657
+ libPromises = /* @__PURE__ */ new Map();
4621
4658
  lucideAliases = {
4622
4659
  close: LucideIcons2.X,
4623
4660
  trash: LucideIcons2.Trash2,
@@ -19849,61 +19886,53 @@ var init_Breadcrumb = __esm({
19849
19886
  function BuilderBoard({
19850
19887
  entity,
19851
19888
  completeEvent = "PUZZLE_COMPLETE",
19889
+ placeEvent,
19890
+ checkEvent,
19891
+ playAgainEvent,
19852
19892
  className
19853
19893
  }) {
19854
19894
  const { emit } = useEventBus();
19855
19895
  const { t } = useTranslate();
19856
19896
  const resolved = boardEntity(entity);
19857
- const [placements, setPlacements] = useState({});
19858
19897
  const [headerError, setHeaderError] = useState(false);
19859
- const [submitted, setSubmitted] = useState(false);
19860
- const [attempts, setAttempts] = useState(0);
19861
- const [showHint, setShowHint] = useState(false);
19898
+ const [selectedComponent, setSelectedComponent] = useState(null);
19862
19899
  const components = Array.isArray(resolved?.components) ? resolved.components : [];
19863
19900
  const slots = Array.isArray(resolved?.slots) ? resolved.slots : [];
19901
+ const placements = {};
19902
+ for (const slot of slots) {
19903
+ if (slot.placedComponentId) placements[slot.id] = slot.placedComponentId;
19904
+ }
19905
+ const attempts = num(resolved?.attempts);
19906
+ const result = str(resolved?.result) || "none";
19907
+ const submitted = result === "win";
19864
19908
  const usedComponentIds = new Set(Object.values(placements));
19865
19909
  const availableComponents = components.filter((c) => !usedComponentIds.has(c.id));
19866
- const [selectedComponent, setSelectedComponent] = useState(null);
19867
- const allPlaced = Object.keys(placements).length === slots.length;
19910
+ const allPlaced = slots.length > 0 && slots.every((s) => Boolean(placements[s.id]));
19868
19911
  const results = submitted ? slots.map((slot) => ({
19869
19912
  slot,
19870
19913
  placed: placements[slot.id],
19871
- correct: placements[slot.id] === slot.acceptsComponentId
19914
+ correct: placements[slot.id] === slot.requiredComponentId
19872
19915
  })) : [];
19873
- const allCorrect = results.length > 0 && results.every((r2) => r2.correct);
19916
+ const showHint = attempts >= 2 && Boolean(str(resolved?.hint));
19874
19917
  const handlePlaceComponent = (slotId) => {
19875
19918
  if (submitted || !selectedComponent) return;
19876
- setPlacements((prev) => ({ ...prev, [slotId]: selectedComponent }));
19919
+ if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: selectedComponent });
19877
19920
  setSelectedComponent(null);
19878
19921
  };
19879
19922
  const handleRemoveFromSlot = (slotId) => {
19880
19923
  if (submitted) return;
19881
- setPlacements((prev) => {
19882
- const next = { ...prev };
19883
- delete next[slotId];
19884
- return next;
19885
- });
19924
+ if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: "" });
19886
19925
  };
19887
- const handleSubmit = useCallback(() => {
19888
- setSubmitted(true);
19889
- setAttempts((a) => a + 1);
19890
- const correct = slots.every((slot) => placements[slot.id] === slot.acceptsComponentId);
19891
- if (correct) {
19926
+ const handleSubmit = () => {
19927
+ if (checkEvent) emit(`UI:${checkEvent}`, {});
19928
+ const solved = slots.length > 0 && slots.every((s) => placements[s.id] === s.requiredComponentId);
19929
+ if (solved && completeEvent) {
19892
19930
  emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
19893
19931
  }
19894
- }, [slots, placements, attempts, completeEvent, emit]);
19895
- const handleReset = () => {
19896
- setSubmitted(false);
19897
- if (attempts >= 2 && str(resolved?.hint)) {
19898
- setShowHint(true);
19899
- }
19900
19932
  };
19901
- const handleFullReset = () => {
19902
- setPlacements({});
19903
- setSubmitted(false);
19933
+ const handlePlayAgain = () => {
19904
19934
  setSelectedComponent(null);
19905
- setAttempts(0);
19906
- setShowHint(false);
19935
+ if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
19907
19936
  };
19908
19937
  const getComponentById = (id) => components.find((c) => c.id === id);
19909
19938
  if (!resolved) return null;
@@ -19953,13 +19982,13 @@ function BuilderBoard({
19953
19982
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("builder.blueprint") }),
19954
19983
  /* @__PURE__ */ jsx(VStack, { gap: "sm", children: slots.map((slot) => {
19955
19984
  const placedComp = placements[slot.id] ? getComponentById(placements[slot.id]) : null;
19956
- const result = results.find((r2) => r2.slot.id === slot.id);
19985
+ const result2 = results.find((r2) => r2.slot.id === slot.id);
19957
19986
  return /* @__PURE__ */ jsxs(
19958
19987
  HStack,
19959
19988
  {
19960
19989
  gap: "sm",
19961
19990
  align: "center",
19962
- className: `p-3 border-2 rounded ${result ? result.correct ? "border-success" : "border-error" : selectedComponent ? "border-dashed border-foreground cursor-pointer" : "border-border"}`,
19991
+ className: `p-3 border-2 rounded ${result2 ? result2.correct ? "border-success" : "border-error" : selectedComponent ? "border-dashed border-foreground cursor-pointer" : "border-border"}`,
19963
19992
  onClick: () => handlePlaceComponent(slot.id),
19964
19993
  children: [
19965
19994
  /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "flex-1", children: [
@@ -19974,7 +20003,7 @@ function BuilderBoard({
19974
20003
  ] }) : null,
19975
20004
  placedComp.label
19976
20005
  ] }),
19977
- result && /* @__PURE__ */ jsx(Icon, { icon: result.correct ? CheckCircle : XCircle, size: "sm", className: result.correct ? "text-success" : "text-error" })
20006
+ result2 && /* @__PURE__ */ jsx(Icon, { icon: result2.correct ? CheckCircle : XCircle, size: "sm", className: result2.correct ? "text-success" : "text-error" })
19978
20007
  ] }) : /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("builder.empty") })
19979
20008
  ]
19980
20009
  },
@@ -19983,16 +20012,16 @@ function BuilderBoard({
19983
20012
  }) })
19984
20013
  ] }) }),
19985
20014
  submitted && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
19986
- /* @__PURE__ */ jsx(Icon, { icon: allCorrect ? CheckCircle : XCircle, size: "lg", className: allCorrect ? "text-success" : "text-error" }),
19987
- /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("builder.success") : str(resolved.failMessage) || t("builder.incorrect") })
20015
+ /* @__PURE__ */ jsx(Icon, { icon: CheckCircle, size: "lg", className: "text-success" }),
20016
+ /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: str(resolved.successMessage) || t("builder.success") })
19988
20017
  ] }) }),
19989
20018
  showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
19990
20019
  /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
19991
- !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
20020
+ !submitted && /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
19992
20021
  /* @__PURE__ */ jsx(Icon, { icon: Wrench, size: "sm" }),
19993
20022
  t("builder.build")
19994
- ] }) : !allCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("builder.tryAgain") }) : null,
19995
- /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handleFullReset, children: [
20023
+ ] }),
20024
+ /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handlePlayAgain, children: [
19996
20025
  /* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
19997
20026
  t("builder.reset")
19998
20027
  ] })
@@ -23448,57 +23477,84 @@ var init_ChartLegend = __esm({
23448
23477
  function ClassifierBoard({
23449
23478
  entity,
23450
23479
  completeEvent = "PUZZLE_COMPLETE",
23480
+ assignEvent,
23481
+ checkEvent,
23482
+ playAgainEvent,
23451
23483
  className
23452
23484
  }) {
23453
23485
  const { emit } = useEventBus();
23454
23486
  const { t } = useTranslate();
23455
23487
  const resolved = boardEntity(entity);
23456
- const [assignments, setAssignments] = useState({});
23488
+ const [localAssignments, setLocalAssignments] = useState({});
23457
23489
  const [headerError, setHeaderError] = useState(false);
23458
- const [submitted, setSubmitted] = useState(false);
23459
- const [attempts, setAttempts] = useState(0);
23490
+ const [localSubmitted, setLocalSubmitted] = useState(false);
23491
+ const [localAttempts, setLocalAttempts] = useState(0);
23460
23492
  const [showHint, setShowHint] = useState(false);
23461
23493
  const items = Array.isArray(resolved?.items) ? resolved.items : [];
23462
23494
  const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
23495
+ const entityResult = str(resolved?.result);
23496
+ const entityDrivesResult = entityResult.length > 0;
23497
+ const entityHasAssignments = items.some((item) => item.assignedCategory != null);
23498
+ const assignments = entityHasAssignments ? items.reduce((acc, item) => {
23499
+ if (item.assignedCategory != null) acc[item.id] = item.assignedCategory;
23500
+ return acc;
23501
+ }, {}) : localAssignments;
23502
+ const attempts = entityDrivesResult ? num(resolved?.attempts) : localAttempts;
23503
+ const submitted = entityDrivesResult || localSubmitted;
23463
23504
  const unassignedItems = items.filter((item) => !assignments[item.id]);
23464
- const allAssigned = Object.keys(assignments).length === items.length;
23505
+ const allAssigned = items.length > 0 && Object.keys(assignments).length === items.length;
23465
23506
  const results = submitted ? items.map((item) => ({
23466
23507
  item,
23467
23508
  assigned: assignments[item.id],
23468
23509
  correct: assignments[item.id] === item.correctCategory
23469
23510
  })) : [];
23470
- const allCorrect = results.length > 0 && results.every((r2) => r2.correct);
23511
+ const allCorrect = entityDrivesResult ? entityResult === "success" : results.length > 0 && results.every((r2) => r2.correct);
23471
23512
  const correctCount = results.filter((r2) => r2.correct).length;
23472
23513
  const handleAssign = (itemId, categoryId) => {
23473
23514
  if (submitted) return;
23474
- setAssignments((prev) => ({ ...prev, [itemId]: categoryId }));
23515
+ if (assignEvent) {
23516
+ emit(`UI:${assignEvent}`, { itemId, categoryId });
23517
+ }
23518
+ if (!entityHasAssignments) {
23519
+ setLocalAssignments((prev) => ({ ...prev, [itemId]: categoryId }));
23520
+ }
23475
23521
  };
23476
23522
  const handleUnassign = (itemId) => {
23477
23523
  if (submitted) return;
23478
- setAssignments((prev) => {
23479
- const next = { ...prev };
23480
- delete next[itemId];
23481
- return next;
23482
- });
23524
+ if (!entityHasAssignments) {
23525
+ setLocalAssignments((prev) => {
23526
+ const next = { ...prev };
23527
+ delete next[itemId];
23528
+ return next;
23529
+ });
23530
+ }
23483
23531
  };
23484
23532
  const handleSubmit = useCallback(() => {
23485
- setSubmitted(true);
23486
- setAttempts((a) => a + 1);
23487
- const correct = items.every((item) => assignments[item.id] === item.correctCategory);
23488
- if (correct) {
23489
- emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
23533
+ if (checkEvent) {
23534
+ emit(`UI:${checkEvent}`, {});
23490
23535
  }
23491
- }, [items, assignments, attempts, completeEvent, emit]);
23536
+ if (!entityDrivesResult) {
23537
+ setLocalSubmitted(true);
23538
+ setLocalAttempts((a) => a + 1);
23539
+ const correct = items.every((item) => assignments[item.id] === item.correctCategory);
23540
+ if (correct) {
23541
+ emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
23542
+ }
23543
+ }
23544
+ }, [checkEvent, entityDrivesResult, items, assignments, attempts, completeEvent, emit]);
23492
23545
  const handleReset = () => {
23493
- setSubmitted(false);
23546
+ if (!entityDrivesResult) setLocalSubmitted(false);
23494
23547
  if (attempts >= 2 && str(resolved?.hint)) {
23495
23548
  setShowHint(true);
23496
23549
  }
23497
23550
  };
23498
23551
  const handleFullReset = () => {
23499
- setAssignments({});
23500
- setSubmitted(false);
23501
- setAttempts(0);
23552
+ if (playAgainEvent) {
23553
+ emit(`UI:${playAgainEvent}`, {});
23554
+ }
23555
+ setLocalAssignments({});
23556
+ setLocalSubmitted(false);
23557
+ setLocalAttempts(0);
23502
23558
  setShowHint(false);
23503
23559
  };
23504
23560
  if (!resolved) return null;
@@ -31381,13 +31437,13 @@ var init_MapView = __esm({
31381
31437
  shadowSize: [41, 41]
31382
31438
  });
31383
31439
  L.Marker.prototype.options.icon = defaultIcon;
31384
- const { useEffect: useEffect77, useRef: useRef69, useCallback: useCallback119, useState: useState115 } = React91__default;
31440
+ const { useEffect: useEffect78, useRef: useRef70, useCallback: useCallback117, useState: useState115 } = React91__default;
31385
31441
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
31386
31442
  const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
31387
31443
  function MapUpdater({ centerLat, centerLng, zoom }) {
31388
31444
  const map = useMap();
31389
- const prevRef = useRef69({ centerLat, centerLng, zoom });
31390
- useEffect77(() => {
31445
+ const prevRef = useRef70({ centerLat, centerLng, zoom });
31446
+ useEffect78(() => {
31391
31447
  const prev = prevRef.current;
31392
31448
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
31393
31449
  map.setView([centerLat, centerLng], zoom);
@@ -31398,7 +31454,7 @@ var init_MapView = __esm({
31398
31454
  }
31399
31455
  function MapClickHandler({ onMapClick }) {
31400
31456
  const map = useMap();
31401
- useEffect77(() => {
31457
+ useEffect78(() => {
31402
31458
  if (!onMapClick) return;
31403
31459
  const handler = (e) => {
31404
31460
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -31427,7 +31483,7 @@ var init_MapView = __esm({
31427
31483
  }) {
31428
31484
  const eventBus = useEventBus3();
31429
31485
  const [clickedPosition, setClickedPosition] = useState115(null);
31430
- const handleMapClick = useCallback119((lat, lng) => {
31486
+ const handleMapClick = useCallback117((lat, lng) => {
31431
31487
  if (showClickedPin) {
31432
31488
  setClickedPosition({ lat, lng });
31433
31489
  }
@@ -31436,7 +31492,7 @@ var init_MapView = __esm({
31436
31492
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
31437
31493
  }
31438
31494
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
31439
- const handleMarkerClick = useCallback119((marker) => {
31495
+ const handleMarkerClick = useCallback117((marker) => {
31440
31496
  onMarkerClick?.(marker);
31441
31497
  if (markerClickEvent) {
31442
31498
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -40249,51 +40305,52 @@ var init_DataTable = __esm({
40249
40305
  function DebuggerBoard({
40250
40306
  entity,
40251
40307
  completeEvent = "PUZZLE_COMPLETE",
40308
+ toggleFlagEvent,
40309
+ checkEvent,
40310
+ playAgainEvent,
40252
40311
  className
40253
40312
  }) {
40254
40313
  const { emit } = useEventBus();
40255
40314
  const { t } = useTranslate();
40256
40315
  const resolved = boardEntity(entity);
40257
- const [flaggedLines, setFlaggedLines] = useState(/* @__PURE__ */ new Set());
40258
40316
  const [headerError, setHeaderError] = useState(false);
40259
- const [submitted, setSubmitted] = useState(false);
40260
- const [attempts, setAttempts] = useState(0);
40261
40317
  const [showHint, setShowHint] = useState(false);
40318
+ const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
40319
+ const result = resolved?.result ?? null;
40320
+ const attempts = num(resolved?.attempts);
40321
+ const submitted = result != null;
40322
+ const bugLines = lines.filter((l) => l.isBug);
40323
+ const flaggedLines = lines.filter((l) => l.isFlagged);
40324
+ const correctFlags = lines.filter((l) => l.isBug && l.isFlagged);
40325
+ const falseFlags = lines.filter((l) => !l.isBug && l.isFlagged);
40326
+ const allCorrect = result === "win";
40262
40327
  const toggleLine = (lineId) => {
40263
40328
  if (submitted) return;
40264
- setFlaggedLines((prev) => {
40265
- const next = new Set(prev);
40266
- if (next.has(lineId)) {
40267
- next.delete(lineId);
40268
- } else {
40269
- next.add(lineId);
40270
- }
40271
- return next;
40272
- });
40329
+ if (toggleFlagEvent) {
40330
+ emit(`UI:${toggleFlagEvent}`, { lineId });
40331
+ }
40273
40332
  };
40274
- const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
40275
- const bugLines = lines.filter((l) => l.isBug);
40276
- const correctFlags = lines.filter((l) => l.isBug && flaggedLines.has(l.id));
40277
- const falseFlags = lines.filter((l) => !l.isBug && flaggedLines.has(l.id));
40278
- const allCorrect = submitted && correctFlags.length === bugLines.length && falseFlags.length === 0;
40279
40333
  const handleSubmit = useCallback(() => {
40280
- setSubmitted(true);
40281
- setAttempts((a) => a + 1);
40334
+ if (checkEvent) {
40335
+ emit(`UI:${checkEvent}`, {});
40336
+ }
40282
40337
  const correct = correctFlags.length === bugLines.length && falseFlags.length === 0;
40283
40338
  if (correct) {
40284
40339
  emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
40285
40340
  }
40286
- }, [correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
40341
+ }, [checkEvent, correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
40287
40342
  const handleReset = () => {
40288
- setSubmitted(false);
40343
+ if (playAgainEvent) {
40344
+ emit(`UI:${playAgainEvent}`, {});
40345
+ }
40289
40346
  if (attempts >= 2 && str(resolved?.hint)) {
40290
40347
  setShowHint(true);
40291
40348
  }
40292
40349
  };
40293
40350
  const handleFullReset = () => {
40294
- setFlaggedLines(/* @__PURE__ */ new Set());
40295
- setSubmitted(false);
40296
- setAttempts(0);
40351
+ if (playAgainEvent) {
40352
+ emit(`UI:${playAgainEvent}`, {});
40353
+ }
40297
40354
  setShowHint(false);
40298
40355
  };
40299
40356
  if (!resolved) return null;
@@ -40321,7 +40378,7 @@ function DebuggerBoard({
40321
40378
  /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(num(resolved.bugCount)) }) })
40322
40379
  ] }) }),
40323
40380
  /* @__PURE__ */ jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsx(VStack, { gap: "none", children: lines.map((line, i) => {
40324
- const isFlagged = flaggedLines.has(line.id);
40381
+ const isFlagged = !!line.isFlagged;
40325
40382
  let lineStyle = "";
40326
40383
  if (submitted) {
40327
40384
  if (line.isBug && isFlagged) lineStyle = "bg-success/10";
@@ -40355,9 +40412,9 @@ function DebuggerBoard({
40355
40412
  /* @__PURE__ */ jsx(
40356
40413
  Icon,
40357
40414
  {
40358
- icon: flaggedLines.has(line.id) ? CheckCircle : XCircle,
40415
+ icon: line.isFlagged ? CheckCircle : XCircle,
40359
40416
  size: "xs",
40360
- className: flaggedLines.has(line.id) ? "text-success mt-0.5" : "text-warning mt-0.5"
40417
+ className: line.isFlagged ? "text-success mt-0.5" : "text-warning mt-0.5"
40361
40418
  }
40362
40419
  ),
40363
40420
  /* @__PURE__ */ jsxs(VStack, { gap: "none", children: [
@@ -40368,7 +40425,7 @@ function DebuggerBoard({
40368
40425
  ] }) }),
40369
40426
  showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
40370
40427
  /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
40371
- !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.size === 0, children: [
40428
+ !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.length === 0, children: [
40372
40429
  /* @__PURE__ */ jsx(Icon, { icon: Send, size: "sm" }),
40373
40430
  t("debugger.submit")
40374
40431
  ] }) : !allCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("debugger.tryAgain") }) : null,
@@ -44132,6 +44189,9 @@ function getOpponentAction(strategy, actions, history) {
44132
44189
  function NegotiatorBoard({
44133
44190
  entity,
44134
44191
  completeEvent = "PUZZLE_COMPLETE",
44192
+ playRoundEvent,
44193
+ finishEvent,
44194
+ playAgainEvent,
44135
44195
  className
44136
44196
  }) {
44137
44197
  const { emit } = useEventBus();
@@ -44140,13 +44200,14 @@ function NegotiatorBoard({
44140
44200
  const [history, setHistory] = useState([]);
44141
44201
  const [headerError, setHeaderError] = useState(false);
44142
44202
  const [showHint, setShowHint] = useState(false);
44143
- const totalRounds = num(resolved?.totalRounds);
44203
+ const totalRounds = num(resolved?.maxRounds);
44144
44204
  const targetScore = num(resolved?.targetScore);
44145
- const currentRound = history.length;
44146
- const isComplete = currentRound >= totalRounds;
44147
- const playerTotal = history.reduce((s, r2) => s + r2.playerPayoff, 0);
44205
+ const currentRound = num(resolved?.round);
44206
+ const result = str(resolved?.result) || "none";
44207
+ const playerTotal = num(resolved?.score);
44208
+ const isComplete = result !== "none" || totalRounds > 0 && currentRound >= totalRounds;
44209
+ const won = result === "win";
44148
44210
  const opponentTotal = history.reduce((s, r2) => s + r2.opponentPayoff, 0);
44149
- const won = isComplete && playerTotal >= targetScore;
44150
44211
  const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
44151
44212
  const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
44152
44213
  const handleAction = useCallback((actionId) => {
@@ -44155,29 +44216,45 @@ function NegotiatorBoard({
44155
44216
  const payoff = payoffMatrix.find(
44156
44217
  (p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
44157
44218
  );
44158
- const result = {
44159
- round: currentRound + 1,
44160
- playerAction: actionId,
44161
- opponentAction,
44162
- playerPayoff: payoff?.playerPayoff ?? 0,
44163
- opponentPayoff: payoff?.opponentPayoff ?? 0
44164
- };
44165
- const newHistory = [...history, result];
44166
- setHistory(newHistory);
44167
- if (newHistory.length >= totalRounds) {
44168
- const total = newHistory.reduce((s, r2) => s + r2.playerPayoff, 0);
44169
- if (total >= targetScore) {
44170
- emit(`UI:${completeEvent}`, { success: true, score: total });
44171
- }
44172
- if (newHistory.length >= 3 && str(resolved?.hint)) {
44219
+ const playerPayoff = payoff?.playerPayoff ?? 0;
44220
+ setHistory((prev) => [
44221
+ ...prev,
44222
+ {
44223
+ round: prev.length + 1,
44224
+ playerAction: actionId,
44225
+ opponentAction,
44226
+ playerPayoff,
44227
+ opponentPayoff: payoff?.opponentPayoff ?? 0
44228
+ }
44229
+ ]);
44230
+ if (playRoundEvent) {
44231
+ emit(`UI:${playRoundEvent}`, { playerAction: actionId, payoff: playerPayoff });
44232
+ }
44233
+ if (totalRounds > 0 && currentRound + 1 >= totalRounds) {
44234
+ if (finishEvent) {
44235
+ emit(`UI:${finishEvent}`, {});
44236
+ }
44237
+ if (str(resolved?.hint)) {
44173
44238
  setShowHint(true);
44174
44239
  }
44175
44240
  }
44176
- }, [isComplete, resolved, totalRounds, targetScore, actions, payoffMatrix, history, currentRound, completeEvent, emit]);
44177
- const handleReset = () => {
44241
+ }, [isComplete, resolved, totalRounds, currentRound, actions, payoffMatrix, history, playRoundEvent, finishEvent, emit]);
44242
+ const handleReset = useCallback(() => {
44178
44243
  setHistory([]);
44179
44244
  setShowHint(false);
44180
- };
44245
+ if (playAgainEvent) {
44246
+ emit(`UI:${playAgainEvent}`, {});
44247
+ }
44248
+ }, [playAgainEvent, emit]);
44249
+ const completedRef = useRef(false);
44250
+ useEffect(() => {
44251
+ if (result === "win" && !completedRef.current) {
44252
+ completedRef.current = true;
44253
+ emit(`UI:${completeEvent}`, { success: true, score: playerTotal });
44254
+ } else if (result === "none") {
44255
+ completedRef.current = false;
44256
+ }
44257
+ }, [result, playerTotal, completeEvent, emit]);
44181
44258
  const getActionLabel = (id) => actions.find((a) => a.id === id)?.label ?? id;
44182
44259
  if (!resolved) return null;
44183
44260
  const theme = resolved.theme ?? void 0;
@@ -47143,67 +47220,47 @@ var init_SimulationGraph = __esm({
47143
47220
  function SimulatorBoard({
47144
47221
  entity,
47145
47222
  completeEvent = "PUZZLE_COMPLETE",
47223
+ setAEvent,
47224
+ setBEvent,
47225
+ checkEvent,
47226
+ playAgainEvent,
47146
47227
  className
47147
47228
  }) {
47148
47229
  const { emit } = useEventBus();
47149
47230
  const { t } = useTranslate();
47150
47231
  const resolved = boardEntity(entity);
47151
47232
  const parameters = Array.isArray(resolved?.parameters) ? resolved.parameters : [];
47152
- const [values, setValues] = useState(() => {
47153
- const init = {};
47154
- for (const p2 of parameters) {
47155
- init[p2.id] = p2.initial;
47156
- }
47157
- return init;
47158
- });
47159
47233
  const [headerError, setHeaderError] = useState(false);
47160
- const [submitted, setSubmitted] = useState(false);
47161
- const [attempts, setAttempts] = useState(0);
47162
- const [showHint, setShowHint] = useState(false);
47163
- const computeOutput = useCallback((params) => {
47164
- try {
47165
- const fn = new Function("params", `return (${str(resolved?.computeExpression)})`);
47166
- return fn(params);
47167
- } catch {
47168
- return 0;
47169
- }
47170
- }, [resolved?.computeExpression]);
47171
- const output = useMemo(() => computeOutput(values) ?? 0, [computeOutput, values]);
47172
- const targetValue = num(resolved?.targetValue);
47173
- const targetTolerance = num(resolved?.targetTolerance);
47174
- const isCorrect = Math.abs(output - targetValue) <= targetTolerance;
47175
- const handleParameterChange = (id, value) => {
47176
- if (submitted) return;
47177
- setValues((prev) => ({ ...prev, [id]: value }));
47178
- };
47179
- const handleSubmit = () => {
47180
- setSubmitted(true);
47181
- setAttempts((a) => a + 1);
47182
- if (isCorrect) {
47183
- emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
47184
- }
47234
+ if (!resolved) return null;
47235
+ const paramA = num(resolved.paramA);
47236
+ const paramB = num(resolved.paramB);
47237
+ const output = num(resolved.output);
47238
+ const targetValue = num(resolved.target);
47239
+ const targetTolerance = num(resolved.tolerance);
47240
+ const attempts = num(resolved.attempts);
47241
+ const result = str(resolved.result);
47242
+ const isWin = result === "win";
47243
+ const isComplete = result !== "none" && result !== "";
47244
+ const paramAValue = parameters[0];
47245
+ const paramBValue = parameters[1];
47246
+ const sliderValues = [paramA, paramB];
47247
+ const sliderEvents = [setAEvent, setBEvent];
47248
+ const handleParameterChange = (index, value) => {
47249
+ if (isComplete) return;
47250
+ const ev = sliderEvents[index];
47251
+ if (ev) emit(`UI:${ev}`, { value });
47185
47252
  };
47186
- const handleReset = () => {
47187
- setSubmitted(false);
47188
- if (attempts >= 2 && str(resolved?.hint)) {
47189
- setShowHint(true);
47190
- }
47253
+ const handleCheck = () => {
47254
+ if (checkEvent) emit(`UI:${checkEvent}`, {});
47191
47255
  };
47192
- const handleFullReset = () => {
47193
- const init = {};
47194
- for (const p2 of parameters) {
47195
- init[p2.id] = p2.initial;
47196
- }
47197
- setValues(init);
47198
- setSubmitted(false);
47199
- setAttempts(0);
47200
- setShowHint(false);
47256
+ const handlePlayAgain = () => {
47257
+ if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
47201
47258
  };
47202
- if (!resolved) return null;
47203
47259
  const theme = resolved.theme ?? void 0;
47204
47260
  const themeBackground = theme?.background;
47205
47261
  const headerImage = str(resolved.headerImage);
47206
47262
  const hint = str(resolved.hint);
47263
+ const showHint = isComplete && !isWin && attempts >= 2 && Boolean(hint);
47207
47264
  const outputLabel = str(resolved.outputLabel);
47208
47265
  const outputUnit = str(resolved.outputUnit);
47209
47266
  return /* @__PURE__ */ jsx(
@@ -47223,41 +47280,43 @@ function SimulatorBoard({
47223
47280
  ] }) }),
47224
47281
  /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", children: [
47225
47282
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("simulator.parameters") }),
47226
- parameters.map((param) => /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
47227
- /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "center", children: [
47228
- /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "medium", children: param.label }),
47229
- /* @__PURE__ */ jsxs(Badge, { size: "sm", children: [
47230
- values[param.id],
47231
- " ",
47232
- param.unit
47233
- ] })
47234
- ] }),
47235
- /* @__PURE__ */ jsx(
47236
- "input",
47237
- {
47238
- type: "range",
47239
- min: param.min,
47240
- max: param.max,
47241
- step: param.step,
47242
- value: values[param.id],
47243
- onChange: (e) => handleParameterChange(param.id, Number(e.target.value)),
47244
- disabled: submitted,
47245
- className: "w-full accent-foreground"
47246
- }
47247
- ),
47248
- /* @__PURE__ */ jsxs(HStack, { justify: "between", children: [
47249
- /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
47250
- param.min,
47251
- " ",
47252
- param.unit
47283
+ [paramAValue, paramBValue].map(
47284
+ (param, index) => param ? /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
47285
+ /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "center", children: [
47286
+ /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "medium", children: param.label }),
47287
+ /* @__PURE__ */ jsxs(Badge, { size: "sm", children: [
47288
+ sliderValues[index],
47289
+ " ",
47290
+ param.unit
47291
+ ] })
47253
47292
  ] }),
47254
- /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
47255
- param.max,
47256
- " ",
47257
- param.unit
47293
+ /* @__PURE__ */ jsx(
47294
+ "input",
47295
+ {
47296
+ type: "range",
47297
+ min: param.min,
47298
+ max: param.max,
47299
+ step: param.step,
47300
+ value: sliderValues[index],
47301
+ onChange: (e) => handleParameterChange(index, Number(e.target.value)),
47302
+ disabled: isComplete,
47303
+ className: "w-full accent-foreground"
47304
+ }
47305
+ ),
47306
+ /* @__PURE__ */ jsxs(HStack, { justify: "between", children: [
47307
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
47308
+ param.min,
47309
+ " ",
47310
+ param.unit
47311
+ ] }),
47312
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
47313
+ param.max,
47314
+ " ",
47315
+ param.unit
47316
+ ] })
47258
47317
  ] })
47259
- ] })
47260
- ] }, param.id))
47318
+ ] }, param.id ?? index) : null
47319
+ )
47261
47320
  ] }) }),
47262
47321
  /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
47263
47322
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: outputLabel }),
@@ -47266,9 +47325,9 @@ function SimulatorBoard({
47266
47325
  " ",
47267
47326
  outputUnit
47268
47327
  ] }),
47269
- submitted && /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
47270
- /* @__PURE__ */ jsx(Icon, { icon: isCorrect ? CheckCircle : XCircle, size: "sm", className: isCorrect ? "text-success" : "text-error" }),
47271
- /* @__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") })
47328
+ isComplete && /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
47329
+ /* @__PURE__ */ jsx(Icon, { icon: isWin ? CheckCircle : XCircle, size: "sm", className: isWin ? "text-success" : "text-error" }),
47330
+ /* @__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") })
47272
47331
  ] }),
47273
47332
  /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
47274
47333
  t("simulator.target"),
@@ -47283,11 +47342,11 @@ function SimulatorBoard({
47283
47342
  ] }) }),
47284
47343
  showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
47285
47344
  /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
47286
- !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, children: [
47345
+ !isComplete ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleCheck, children: [
47287
47346
  /* @__PURE__ */ jsx(Icon, { icon: Play, size: "sm" }),
47288
47347
  t("simulator.simulate")
47289
- ] }) : !isCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("simulator.tryAgain") }) : null,
47290
- /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handleFullReset, children: [
47348
+ ] }) : null,
47349
+ /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handlePlayAgain, children: [
47291
47350
  /* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
47292
47351
  t("simulator.reset")
47293
47352
  ] })