@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.cjs +341 -285
- package/dist/avl/index.js +341 -282
- package/dist/components/game/organisms/puzzles/builder/BuilderBoard.d.ts +18 -5
- package/dist/components/game/organisms/puzzles/classifier/ClassifierBoard.d.ts +21 -3
- package/dist/components/game/organisms/puzzles/debugger/DebuggerBoard.d.ts +12 -2
- package/dist/components/game/organisms/puzzles/negotiator/NegotiatorBoard.d.ts +13 -3
- package/dist/components/game/organisms/puzzles/simulator/SimulatorBoard.d.ts +22 -7
- package/dist/components/index.cjs +348 -288
- package/dist/components/index.js +348 -285
- package/dist/docs/index.cjs +115 -81
- package/dist/docs/index.js +115 -78
- package/dist/marketing/index.cjs +114 -80
- package/dist/marketing/index.js +114 -77
- package/dist/providers/index.cjs +341 -285
- package/dist/providers/index.js +341 -282
- package/dist/runtime/index.cjs +341 -285
- package/dist/runtime/index.js +341 -282
- package/package.json +1 -1
|
@@ -7,9 +7,6 @@ var tailwindMerge = require('tailwind-merge');
|
|
|
7
7
|
var providers = require('@almadar/ui/providers');
|
|
8
8
|
var logger = require('@almadar/logger');
|
|
9
9
|
var LucideIcons2 = require('lucide-react');
|
|
10
|
-
var PhosphorIcons = require('@phosphor-icons/react');
|
|
11
|
-
var TablerIcons = require('@tabler/icons-react');
|
|
12
|
-
var FaIcons = require('react-icons/fa');
|
|
13
10
|
var hooks = require('@almadar/ui/hooks');
|
|
14
11
|
var evaluator = require('@almadar/evaluator');
|
|
15
12
|
var reactDom = require('react-dom');
|
|
@@ -68,9 +65,6 @@ function _interopNamespace(e) {
|
|
|
68
65
|
|
|
69
66
|
var React77__namespace = /*#__PURE__*/_interopNamespace(React77);
|
|
70
67
|
var LucideIcons2__namespace = /*#__PURE__*/_interopNamespace(LucideIcons2);
|
|
71
|
-
var PhosphorIcons__namespace = /*#__PURE__*/_interopNamespace(PhosphorIcons);
|
|
72
|
-
var TablerIcons__namespace = /*#__PURE__*/_interopNamespace(TablerIcons);
|
|
73
|
-
var FaIcons__namespace = /*#__PURE__*/_interopNamespace(FaIcons);
|
|
74
68
|
var ELK__default = /*#__PURE__*/_interopDefault(ELK);
|
|
75
69
|
var SyntaxHighlighter__default = /*#__PURE__*/_interopDefault(SyntaxHighlighter);
|
|
76
70
|
var dark__default = /*#__PURE__*/_interopDefault(dark);
|
|
@@ -1274,6 +1268,41 @@ function kebabToPascal(name) {
|
|
|
1274
1268
|
return part.charAt(0).toUpperCase() + part.slice(1);
|
|
1275
1269
|
}).join("");
|
|
1276
1270
|
}
|
|
1271
|
+
function loadLib(key, importer) {
|
|
1272
|
+
let p2 = libPromises.get(key);
|
|
1273
|
+
if (!p2) {
|
|
1274
|
+
p2 = importer().then((m) => m);
|
|
1275
|
+
libPromises.set(key, p2);
|
|
1276
|
+
}
|
|
1277
|
+
return p2;
|
|
1278
|
+
}
|
|
1279
|
+
function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
|
|
1280
|
+
const Lazy = React77__namespace.default.lazy(async () => {
|
|
1281
|
+
const lib = await loadLib(libKey, importer);
|
|
1282
|
+
const Comp = pick(lib);
|
|
1283
|
+
if (!Comp) {
|
|
1284
|
+
warnFallback(fallbackName, family);
|
|
1285
|
+
return { default: makeLucideAdapter(fallbackName, true) };
|
|
1286
|
+
}
|
|
1287
|
+
return { default: Comp };
|
|
1288
|
+
});
|
|
1289
|
+
const Wrapped = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1290
|
+
React77__namespace.default.Suspense,
|
|
1291
|
+
{
|
|
1292
|
+
fallback: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1293
|
+
"span",
|
|
1294
|
+
{
|
|
1295
|
+
"aria-hidden": true,
|
|
1296
|
+
className: props.className,
|
|
1297
|
+
style: { display: "inline-block", ...props.style }
|
|
1298
|
+
}
|
|
1299
|
+
),
|
|
1300
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Lazy, { ...props })
|
|
1301
|
+
}
|
|
1302
|
+
);
|
|
1303
|
+
Wrapped.displayName = `Lazy.${libKey}.${fallbackName}`;
|
|
1304
|
+
return Wrapped;
|
|
1305
|
+
}
|
|
1277
1306
|
function resolveLucide(name) {
|
|
1278
1307
|
if (lucideAliases[name]) return lucideAliases[name];
|
|
1279
1308
|
const pascal = kebabToPascal(name);
|
|
@@ -1284,60 +1313,81 @@ function resolveLucide(name) {
|
|
|
1284
1313
|
if (asIs && typeof asIs === "object") return asIs;
|
|
1285
1314
|
return LucideIcons2__namespace.HelpCircle;
|
|
1286
1315
|
}
|
|
1287
|
-
function resolvePhosphor(name, weight) {
|
|
1316
|
+
function resolvePhosphor(name, weight, family) {
|
|
1288
1317
|
const target = phosphorAliases[name] ?? kebabToPascal(name);
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1318
|
+
return lazyFamilyIcon(
|
|
1319
|
+
"phosphor",
|
|
1320
|
+
() => import('@phosphor-icons/react'),
|
|
1321
|
+
(lib) => {
|
|
1322
|
+
const PhosphorComp = lib[target];
|
|
1323
|
+
if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
|
|
1324
|
+
const Component = PhosphorComp;
|
|
1325
|
+
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1326
|
+
Component,
|
|
1327
|
+
{
|
|
1328
|
+
weight,
|
|
1329
|
+
className: props.className,
|
|
1330
|
+
style: props.style,
|
|
1331
|
+
size: props.size ?? "1em"
|
|
1332
|
+
}
|
|
1333
|
+
);
|
|
1334
|
+
Adapter.displayName = `Phosphor.${target}.${weight}`;
|
|
1335
|
+
return Adapter;
|
|
1336
|
+
},
|
|
1337
|
+
name,
|
|
1338
|
+
family
|
|
1301
1339
|
);
|
|
1302
|
-
Adapter.displayName = `Phosphor.${target}.${weight}`;
|
|
1303
|
-
return Adapter;
|
|
1304
1340
|
}
|
|
1305
|
-
function resolveTabler(name) {
|
|
1341
|
+
function resolveTabler(name, family) {
|
|
1306
1342
|
const suffix = tablerAliases[name] ?? kebabToPascal(name);
|
|
1307
1343
|
const target = `Icon${suffix}`;
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1344
|
+
return lazyFamilyIcon(
|
|
1345
|
+
"tabler",
|
|
1346
|
+
() => import('@tabler/icons-react'),
|
|
1347
|
+
(lib) => {
|
|
1348
|
+
const TablerComp = lib[target];
|
|
1349
|
+
if (!TablerComp || typeof TablerComp !== "object") return null;
|
|
1350
|
+
const Component = TablerComp;
|
|
1351
|
+
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1352
|
+
Component,
|
|
1353
|
+
{
|
|
1354
|
+
stroke: props.strokeWidth ?? 1.5,
|
|
1355
|
+
className: props.className,
|
|
1356
|
+
style: props.style,
|
|
1357
|
+
size: props.size ?? 24
|
|
1358
|
+
}
|
|
1359
|
+
);
|
|
1360
|
+
Adapter.displayName = `Tabler.${target}`;
|
|
1361
|
+
return Adapter;
|
|
1362
|
+
},
|
|
1363
|
+
name,
|
|
1364
|
+
family
|
|
1320
1365
|
);
|
|
1321
|
-
Adapter.displayName = `Tabler.${target}`;
|
|
1322
|
-
return Adapter;
|
|
1323
1366
|
}
|
|
1324
|
-
function resolveFa(name) {
|
|
1367
|
+
function resolveFa(name, family) {
|
|
1325
1368
|
const suffix = faAliases[name] ?? kebabToPascal(name);
|
|
1326
1369
|
const target = `Fa${suffix}`;
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1370
|
+
return lazyFamilyIcon(
|
|
1371
|
+
"fa",
|
|
1372
|
+
() => import('react-icons/fa'),
|
|
1373
|
+
(lib) => {
|
|
1374
|
+
const FaComp = lib[target];
|
|
1375
|
+
if (!FaComp || typeof FaComp !== "function") return null;
|
|
1376
|
+
const Component = FaComp;
|
|
1377
|
+
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1378
|
+
Component,
|
|
1379
|
+
{
|
|
1380
|
+
className: props.className,
|
|
1381
|
+
style: props.style,
|
|
1382
|
+
size: props.size ?? "1em"
|
|
1383
|
+
}
|
|
1384
|
+
);
|
|
1385
|
+
Adapter.displayName = `Fa.${target}`;
|
|
1386
|
+
return Adapter;
|
|
1387
|
+
},
|
|
1388
|
+
name,
|
|
1389
|
+
family
|
|
1338
1390
|
);
|
|
1339
|
-
Adapter.displayName = `Fa.${target}`;
|
|
1340
|
-
return Adapter;
|
|
1341
1391
|
}
|
|
1342
1392
|
function warnFallback(name, family) {
|
|
1343
1393
|
const key = `${family}::${name}`;
|
|
@@ -1371,39 +1421,22 @@ function resolveIconForFamily(name, family) {
|
|
|
1371
1421
|
switch (family) {
|
|
1372
1422
|
case "lucide":
|
|
1373
1423
|
return makeLucideAdapter(name, false);
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
return
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
return
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
return makeLucideAdapter(name, true);
|
|
1391
|
-
}
|
|
1392
|
-
case "tabler": {
|
|
1393
|
-
const t = resolveTabler(name);
|
|
1394
|
-
if (t) return t;
|
|
1395
|
-
warnFallback(name, family);
|
|
1396
|
-
return makeLucideAdapter(name, true);
|
|
1397
|
-
}
|
|
1398
|
-
case "fa-solid": {
|
|
1399
|
-
const f3 = resolveFa(name);
|
|
1400
|
-
if (f3) return f3;
|
|
1401
|
-
warnFallback(name, family);
|
|
1402
|
-
return makeLucideAdapter(name, true);
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
}
|
|
1406
|
-
var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
|
|
1424
|
+
// Non-lucide families resolve to a lazy, Suspense-wrapped component that
|
|
1425
|
+
// dynamic-imports the library on first render and falls back to lucide
|
|
1426
|
+
// internally when the family lacks the icon (see lazyFamilyIcon).
|
|
1427
|
+
case "phosphor-outline":
|
|
1428
|
+
return resolvePhosphor(name, "regular", family);
|
|
1429
|
+
case "phosphor-fill":
|
|
1430
|
+
return resolvePhosphor(name, "fill", family);
|
|
1431
|
+
case "phosphor-duotone":
|
|
1432
|
+
return resolvePhosphor(name, "duotone", family);
|
|
1433
|
+
case "tabler":
|
|
1434
|
+
return resolveTabler(name, family);
|
|
1435
|
+
case "fa-solid":
|
|
1436
|
+
return resolveFa(name, family);
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, libPromises, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
|
|
1407
1440
|
var init_iconFamily = __esm({
|
|
1408
1441
|
"lib/iconFamily.tsx"() {
|
|
1409
1442
|
"use client";
|
|
@@ -1419,6 +1452,7 @@ var init_iconFamily = __esm({
|
|
|
1419
1452
|
cachedFamily = null;
|
|
1420
1453
|
listeners = /* @__PURE__ */ new Set();
|
|
1421
1454
|
observer = null;
|
|
1455
|
+
libPromises = /* @__PURE__ */ new Map();
|
|
1422
1456
|
lucideAliases = {
|
|
1423
1457
|
close: LucideIcons2__namespace.X,
|
|
1424
1458
|
trash: LucideIcons2__namespace.Trash2,
|
|
@@ -15977,61 +16011,53 @@ var init_Breadcrumb = __esm({
|
|
|
15977
16011
|
function BuilderBoard({
|
|
15978
16012
|
entity,
|
|
15979
16013
|
completeEvent = "PUZZLE_COMPLETE",
|
|
16014
|
+
placeEvent,
|
|
16015
|
+
checkEvent,
|
|
16016
|
+
playAgainEvent,
|
|
15980
16017
|
className
|
|
15981
16018
|
}) {
|
|
15982
16019
|
const { emit } = useEventBus();
|
|
15983
16020
|
const { t } = hooks.useTranslate();
|
|
15984
16021
|
const resolved = boardEntity(entity);
|
|
15985
|
-
const [placements, setPlacements] = React77.useState({});
|
|
15986
16022
|
const [headerError, setHeaderError] = React77.useState(false);
|
|
15987
|
-
const [
|
|
15988
|
-
const [attempts, setAttempts] = React77.useState(0);
|
|
15989
|
-
const [showHint, setShowHint] = React77.useState(false);
|
|
16023
|
+
const [selectedComponent, setSelectedComponent] = React77.useState(null);
|
|
15990
16024
|
const components = Array.isArray(resolved?.components) ? resolved.components : [];
|
|
15991
16025
|
const slots = Array.isArray(resolved?.slots) ? resolved.slots : [];
|
|
16026
|
+
const placements = {};
|
|
16027
|
+
for (const slot of slots) {
|
|
16028
|
+
if (slot.placedComponentId) placements[slot.id] = slot.placedComponentId;
|
|
16029
|
+
}
|
|
16030
|
+
const attempts = num(resolved?.attempts);
|
|
16031
|
+
const result = str(resolved?.result) || "none";
|
|
16032
|
+
const submitted = result === "win";
|
|
15992
16033
|
const usedComponentIds = new Set(Object.values(placements));
|
|
15993
16034
|
const availableComponents = components.filter((c) => !usedComponentIds.has(c.id));
|
|
15994
|
-
const
|
|
15995
|
-
const allPlaced = Object.keys(placements).length === slots.length;
|
|
16035
|
+
const allPlaced = slots.length > 0 && slots.every((s) => Boolean(placements[s.id]));
|
|
15996
16036
|
const results = submitted ? slots.map((slot) => ({
|
|
15997
16037
|
slot,
|
|
15998
16038
|
placed: placements[slot.id],
|
|
15999
|
-
correct: placements[slot.id] === slot.
|
|
16039
|
+
correct: placements[slot.id] === slot.requiredComponentId
|
|
16000
16040
|
})) : [];
|
|
16001
|
-
const
|
|
16041
|
+
const showHint = attempts >= 2 && Boolean(str(resolved?.hint));
|
|
16002
16042
|
const handlePlaceComponent = (slotId) => {
|
|
16003
16043
|
if (submitted || !selectedComponent) return;
|
|
16004
|
-
|
|
16044
|
+
if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: selectedComponent });
|
|
16005
16045
|
setSelectedComponent(null);
|
|
16006
16046
|
};
|
|
16007
16047
|
const handleRemoveFromSlot = (slotId) => {
|
|
16008
16048
|
if (submitted) return;
|
|
16009
|
-
|
|
16010
|
-
const next = { ...prev };
|
|
16011
|
-
delete next[slotId];
|
|
16012
|
-
return next;
|
|
16013
|
-
});
|
|
16049
|
+
if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: "" });
|
|
16014
16050
|
};
|
|
16015
|
-
const handleSubmit =
|
|
16016
|
-
|
|
16017
|
-
|
|
16018
|
-
|
|
16019
|
-
if (correct) {
|
|
16051
|
+
const handleSubmit = () => {
|
|
16052
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
16053
|
+
const solved = slots.length > 0 && slots.every((s) => placements[s.id] === s.requiredComponentId);
|
|
16054
|
+
if (solved && completeEvent) {
|
|
16020
16055
|
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
16021
16056
|
}
|
|
16022
|
-
}, [slots, placements, attempts, completeEvent, emit]);
|
|
16023
|
-
const handleReset = () => {
|
|
16024
|
-
setSubmitted(false);
|
|
16025
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
16026
|
-
setShowHint(true);
|
|
16027
|
-
}
|
|
16028
16057
|
};
|
|
16029
|
-
const
|
|
16030
|
-
setPlacements({});
|
|
16031
|
-
setSubmitted(false);
|
|
16058
|
+
const handlePlayAgain = () => {
|
|
16032
16059
|
setSelectedComponent(null);
|
|
16033
|
-
|
|
16034
|
-
setShowHint(false);
|
|
16060
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
16035
16061
|
};
|
|
16036
16062
|
const getComponentById = (id) => components.find((c) => c.id === id);
|
|
16037
16063
|
if (!resolved) return null;
|
|
@@ -16081,13 +16107,13 @@ function BuilderBoard({
|
|
|
16081
16107
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("builder.blueprint") }),
|
|
16082
16108
|
/* @__PURE__ */ jsxRuntime.jsx(exports.VStack, { gap: "sm", children: slots.map((slot) => {
|
|
16083
16109
|
const placedComp = placements[slot.id] ? getComponentById(placements[slot.id]) : null;
|
|
16084
|
-
const
|
|
16110
|
+
const result2 = results.find((r) => r.slot.id === slot.id);
|
|
16085
16111
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
16086
16112
|
exports.HStack,
|
|
16087
16113
|
{
|
|
16088
16114
|
gap: "sm",
|
|
16089
16115
|
align: "center",
|
|
16090
|
-
className: `p-3 border-2 rounded ${
|
|
16116
|
+
className: `p-3 border-2 rounded ${result2 ? result2.correct ? "border-success" : "border-error" : selectedComponent ? "border-dashed border-foreground cursor-pointer" : "border-border"}`,
|
|
16091
16117
|
onClick: () => handlePlaceComponent(slot.id),
|
|
16092
16118
|
children: [
|
|
16093
16119
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "none", className: "flex-1", children: [
|
|
@@ -16102,7 +16128,7 @@ function BuilderBoard({
|
|
|
16102
16128
|
] }) : null,
|
|
16103
16129
|
placedComp.label
|
|
16104
16130
|
] }),
|
|
16105
|
-
|
|
16131
|
+
result2 && /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon: result2.correct ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "sm", className: result2.correct ? "text-success" : "text-error" })
|
|
16106
16132
|
] }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", className: "text-muted-foreground", children: t("builder.empty") })
|
|
16107
16133
|
]
|
|
16108
16134
|
},
|
|
@@ -16111,16 +16137,16 @@ function BuilderBoard({
|
|
|
16111
16137
|
}) })
|
|
16112
16138
|
] }) }),
|
|
16113
16139
|
submitted && /* @__PURE__ */ jsxRuntime.jsx(exports.Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "sm", align: "center", children: [
|
|
16114
|
-
/* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon:
|
|
16115
|
-
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", weight: "bold", children:
|
|
16140
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon: LucideIcons2.CheckCircle, size: "lg", className: "text-success" }),
|
|
16141
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", weight: "bold", children: str(resolved.successMessage) || t("builder.success") })
|
|
16116
16142
|
] }) }),
|
|
16117
16143
|
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(exports.Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", children: hint }) }),
|
|
16118
16144
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", justify: "center", children: [
|
|
16119
|
-
!submitted
|
|
16145
|
+
!submitted && /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
|
|
16120
16146
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon: LucideIcons2.Wrench, size: "sm" }),
|
|
16121
16147
|
t("builder.build")
|
|
16122
|
-
] })
|
|
16123
|
-
/* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { variant: "secondary", onClick:
|
|
16148
|
+
] }),
|
|
16149
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { variant: "secondary", onClick: handlePlayAgain, children: [
|
|
16124
16150
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon: LucideIcons2.RotateCcw, size: "sm" }),
|
|
16125
16151
|
t("builder.reset")
|
|
16126
16152
|
] })
|
|
@@ -19622,57 +19648,84 @@ var init_ChoiceButton = __esm({
|
|
|
19622
19648
|
function ClassifierBoard({
|
|
19623
19649
|
entity,
|
|
19624
19650
|
completeEvent = "PUZZLE_COMPLETE",
|
|
19651
|
+
assignEvent,
|
|
19652
|
+
checkEvent,
|
|
19653
|
+
playAgainEvent,
|
|
19625
19654
|
className
|
|
19626
19655
|
}) {
|
|
19627
19656
|
const { emit } = useEventBus();
|
|
19628
19657
|
const { t } = hooks.useTranslate();
|
|
19629
19658
|
const resolved = boardEntity(entity);
|
|
19630
|
-
const [
|
|
19659
|
+
const [localAssignments, setLocalAssignments] = React77.useState({});
|
|
19631
19660
|
const [headerError, setHeaderError] = React77.useState(false);
|
|
19632
|
-
const [
|
|
19633
|
-
const [
|
|
19661
|
+
const [localSubmitted, setLocalSubmitted] = React77.useState(false);
|
|
19662
|
+
const [localAttempts, setLocalAttempts] = React77.useState(0);
|
|
19634
19663
|
const [showHint, setShowHint] = React77.useState(false);
|
|
19635
19664
|
const items = Array.isArray(resolved?.items) ? resolved.items : [];
|
|
19636
19665
|
const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
|
|
19666
|
+
const entityResult = str(resolved?.result);
|
|
19667
|
+
const entityDrivesResult = entityResult.length > 0;
|
|
19668
|
+
const entityHasAssignments = items.some((item) => item.assignedCategory != null);
|
|
19669
|
+
const assignments = entityHasAssignments ? items.reduce((acc, item) => {
|
|
19670
|
+
if (item.assignedCategory != null) acc[item.id] = item.assignedCategory;
|
|
19671
|
+
return acc;
|
|
19672
|
+
}, {}) : localAssignments;
|
|
19673
|
+
const attempts = entityDrivesResult ? num(resolved?.attempts) : localAttempts;
|
|
19674
|
+
const submitted = entityDrivesResult || localSubmitted;
|
|
19637
19675
|
const unassignedItems = items.filter((item) => !assignments[item.id]);
|
|
19638
|
-
const allAssigned = Object.keys(assignments).length === items.length;
|
|
19676
|
+
const allAssigned = items.length > 0 && Object.keys(assignments).length === items.length;
|
|
19639
19677
|
const results = submitted ? items.map((item) => ({
|
|
19640
19678
|
item,
|
|
19641
19679
|
assigned: assignments[item.id],
|
|
19642
19680
|
correct: assignments[item.id] === item.correctCategory
|
|
19643
19681
|
})) : [];
|
|
19644
|
-
const allCorrect = results.length > 0 && results.every((r) => r.correct);
|
|
19682
|
+
const allCorrect = entityDrivesResult ? entityResult === "success" : results.length > 0 && results.every((r) => r.correct);
|
|
19645
19683
|
const correctCount = results.filter((r) => r.correct).length;
|
|
19646
19684
|
const handleAssign = (itemId, categoryId) => {
|
|
19647
19685
|
if (submitted) return;
|
|
19648
|
-
|
|
19686
|
+
if (assignEvent) {
|
|
19687
|
+
emit(`UI:${assignEvent}`, { itemId, categoryId });
|
|
19688
|
+
}
|
|
19689
|
+
if (!entityHasAssignments) {
|
|
19690
|
+
setLocalAssignments((prev) => ({ ...prev, [itemId]: categoryId }));
|
|
19691
|
+
}
|
|
19649
19692
|
};
|
|
19650
19693
|
const handleUnassign = (itemId) => {
|
|
19651
19694
|
if (submitted) return;
|
|
19652
|
-
|
|
19653
|
-
|
|
19654
|
-
|
|
19655
|
-
|
|
19656
|
-
|
|
19695
|
+
if (!entityHasAssignments) {
|
|
19696
|
+
setLocalAssignments((prev) => {
|
|
19697
|
+
const next = { ...prev };
|
|
19698
|
+
delete next[itemId];
|
|
19699
|
+
return next;
|
|
19700
|
+
});
|
|
19701
|
+
}
|
|
19657
19702
|
};
|
|
19658
19703
|
const handleSubmit = React77.useCallback(() => {
|
|
19659
|
-
|
|
19660
|
-
|
|
19661
|
-
|
|
19662
|
-
if (
|
|
19663
|
-
|
|
19704
|
+
if (checkEvent) {
|
|
19705
|
+
emit(`UI:${checkEvent}`, {});
|
|
19706
|
+
}
|
|
19707
|
+
if (!entityDrivesResult) {
|
|
19708
|
+
setLocalSubmitted(true);
|
|
19709
|
+
setLocalAttempts((a) => a + 1);
|
|
19710
|
+
const correct = items.every((item) => assignments[item.id] === item.correctCategory);
|
|
19711
|
+
if (correct) {
|
|
19712
|
+
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
19713
|
+
}
|
|
19664
19714
|
}
|
|
19665
|
-
}, [items, assignments, attempts, completeEvent, emit]);
|
|
19715
|
+
}, [checkEvent, entityDrivesResult, items, assignments, attempts, completeEvent, emit]);
|
|
19666
19716
|
const handleReset = () => {
|
|
19667
|
-
|
|
19717
|
+
if (!entityDrivesResult) setLocalSubmitted(false);
|
|
19668
19718
|
if (attempts >= 2 && str(resolved?.hint)) {
|
|
19669
19719
|
setShowHint(true);
|
|
19670
19720
|
}
|
|
19671
19721
|
};
|
|
19672
19722
|
const handleFullReset = () => {
|
|
19673
|
-
|
|
19674
|
-
|
|
19675
|
-
|
|
19723
|
+
if (playAgainEvent) {
|
|
19724
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
19725
|
+
}
|
|
19726
|
+
setLocalAssignments({});
|
|
19727
|
+
setLocalSubmitted(false);
|
|
19728
|
+
setLocalAttempts(0);
|
|
19676
19729
|
setShowHint(false);
|
|
19677
19730
|
};
|
|
19678
19731
|
if (!resolved) return null;
|
|
@@ -23324,7 +23377,7 @@ var init_FormSection = __esm({
|
|
|
23324
23377
|
exports.FormActions.displayName = "FormActions";
|
|
23325
23378
|
}
|
|
23326
23379
|
});
|
|
23327
|
-
var ALL_CATEGORY; exports.GridPicker = void 0;
|
|
23380
|
+
var ALL_CATEGORY, MAX_RENDERED; exports.GridPicker = void 0;
|
|
23328
23381
|
var init_GridPicker = __esm({
|
|
23329
23382
|
"components/core/molecules/GridPicker.tsx"() {
|
|
23330
23383
|
"use client";
|
|
@@ -23333,6 +23386,7 @@ var init_GridPicker = __esm({
|
|
|
23333
23386
|
init_Badge();
|
|
23334
23387
|
init_Stack();
|
|
23335
23388
|
ALL_CATEGORY = "__all__";
|
|
23389
|
+
MAX_RENDERED = 300;
|
|
23336
23390
|
exports.GridPicker = ({
|
|
23337
23391
|
items,
|
|
23338
23392
|
value,
|
|
@@ -23362,6 +23416,8 @@ var init_GridPicker = __esm({
|
|
|
23362
23416
|
return matchesCategory && matchesSearch;
|
|
23363
23417
|
});
|
|
23364
23418
|
}, [items, search, activeCategory]);
|
|
23419
|
+
const visible = React77.useMemo(() => filtered.slice(0, MAX_RENDERED), [filtered]);
|
|
23420
|
+
const truncated = filtered.length - visible.length;
|
|
23365
23421
|
const select = React77.useCallback(
|
|
23366
23422
|
(item) => {
|
|
23367
23423
|
onChange(item.id);
|
|
@@ -23463,7 +23519,7 @@ var init_GridPicker = __esm({
|
|
|
23463
23519
|
style: {
|
|
23464
23520
|
gridTemplateColumns: `repeat(auto-fill, minmax(${cellSize}px, 1fr))`
|
|
23465
23521
|
},
|
|
23466
|
-
children:
|
|
23522
|
+
children: visible.map((item, index) => {
|
|
23467
23523
|
const selected = item.id === value;
|
|
23468
23524
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
23469
23525
|
"button",
|
|
@@ -23490,7 +23546,8 @@ var init_GridPicker = __esm({
|
|
|
23490
23546
|
);
|
|
23491
23547
|
})
|
|
23492
23548
|
}
|
|
23493
|
-
)
|
|
23549
|
+
),
|
|
23550
|
+
truncated > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-1 text-xs text-muted-foreground", children: `+${truncated} more \u2014 refine your search` })
|
|
23494
23551
|
] });
|
|
23495
23552
|
};
|
|
23496
23553
|
exports.GridPicker.displayName = "GridPicker";
|
|
@@ -29211,13 +29268,13 @@ var init_MapView = __esm({
|
|
|
29211
29268
|
shadowSize: [41, 41]
|
|
29212
29269
|
});
|
|
29213
29270
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
29214
|
-
const { useEffect:
|
|
29271
|
+
const { useEffect: useEffect73, useRef: useRef70, useCallback: useCallback113, useState: useState105 } = React77__namespace.default;
|
|
29215
29272
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
29216
29273
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
29217
29274
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
29218
29275
|
const map = useMap();
|
|
29219
|
-
const prevRef =
|
|
29220
|
-
|
|
29276
|
+
const prevRef = useRef70({ centerLat, centerLng, zoom });
|
|
29277
|
+
useEffect73(() => {
|
|
29221
29278
|
const prev = prevRef.current;
|
|
29222
29279
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
29223
29280
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -29228,7 +29285,7 @@ var init_MapView = __esm({
|
|
|
29228
29285
|
}
|
|
29229
29286
|
function MapClickHandler({ onMapClick }) {
|
|
29230
29287
|
const map = useMap();
|
|
29231
|
-
|
|
29288
|
+
useEffect73(() => {
|
|
29232
29289
|
if (!onMapClick) return;
|
|
29233
29290
|
const handler = (e) => {
|
|
29234
29291
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -29257,7 +29314,7 @@ var init_MapView = __esm({
|
|
|
29257
29314
|
}) {
|
|
29258
29315
|
const eventBus = useEventBus2();
|
|
29259
29316
|
const [clickedPosition, setClickedPosition] = useState105(null);
|
|
29260
|
-
const handleMapClick =
|
|
29317
|
+
const handleMapClick = useCallback113((lat, lng) => {
|
|
29261
29318
|
if (showClickedPin) {
|
|
29262
29319
|
setClickedPosition({ lat, lng });
|
|
29263
29320
|
}
|
|
@@ -29266,7 +29323,7 @@ var init_MapView = __esm({
|
|
|
29266
29323
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
29267
29324
|
}
|
|
29268
29325
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
29269
|
-
const handleMarkerClick =
|
|
29326
|
+
const handleMarkerClick = useCallback113((marker) => {
|
|
29270
29327
|
onMarkerClick?.(marker);
|
|
29271
29328
|
if (markerClickEvent) {
|
|
29272
29329
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -38700,51 +38757,52 @@ var init_DataTable = __esm({
|
|
|
38700
38757
|
function DebuggerBoard({
|
|
38701
38758
|
entity,
|
|
38702
38759
|
completeEvent = "PUZZLE_COMPLETE",
|
|
38760
|
+
toggleFlagEvent,
|
|
38761
|
+
checkEvent,
|
|
38762
|
+
playAgainEvent,
|
|
38703
38763
|
className
|
|
38704
38764
|
}) {
|
|
38705
38765
|
const { emit } = useEventBus();
|
|
38706
38766
|
const { t } = hooks.useTranslate();
|
|
38707
38767
|
const resolved = boardEntity(entity);
|
|
38708
|
-
const [flaggedLines, setFlaggedLines] = React77.useState(/* @__PURE__ */ new Set());
|
|
38709
38768
|
const [headerError, setHeaderError] = React77.useState(false);
|
|
38710
|
-
const [submitted, setSubmitted] = React77.useState(false);
|
|
38711
|
-
const [attempts, setAttempts] = React77.useState(0);
|
|
38712
38769
|
const [showHint, setShowHint] = React77.useState(false);
|
|
38770
|
+
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
38771
|
+
const result = resolved?.result ?? null;
|
|
38772
|
+
const attempts = num(resolved?.attempts);
|
|
38773
|
+
const submitted = result != null;
|
|
38774
|
+
const bugLines = lines.filter((l) => l.isBug);
|
|
38775
|
+
const flaggedLines = lines.filter((l) => l.isFlagged);
|
|
38776
|
+
const correctFlags = lines.filter((l) => l.isBug && l.isFlagged);
|
|
38777
|
+
const falseFlags = lines.filter((l) => !l.isBug && l.isFlagged);
|
|
38778
|
+
const allCorrect = result === "win";
|
|
38713
38779
|
const toggleLine = (lineId) => {
|
|
38714
38780
|
if (submitted) return;
|
|
38715
|
-
|
|
38716
|
-
|
|
38717
|
-
|
|
38718
|
-
next.delete(lineId);
|
|
38719
|
-
} else {
|
|
38720
|
-
next.add(lineId);
|
|
38721
|
-
}
|
|
38722
|
-
return next;
|
|
38723
|
-
});
|
|
38781
|
+
if (toggleFlagEvent) {
|
|
38782
|
+
emit(`UI:${toggleFlagEvent}`, { lineId });
|
|
38783
|
+
}
|
|
38724
38784
|
};
|
|
38725
|
-
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
38726
|
-
const bugLines = lines.filter((l) => l.isBug);
|
|
38727
|
-
const correctFlags = lines.filter((l) => l.isBug && flaggedLines.has(l.id));
|
|
38728
|
-
const falseFlags = lines.filter((l) => !l.isBug && flaggedLines.has(l.id));
|
|
38729
|
-
const allCorrect = submitted && correctFlags.length === bugLines.length && falseFlags.length === 0;
|
|
38730
38785
|
const handleSubmit = React77.useCallback(() => {
|
|
38731
|
-
|
|
38732
|
-
|
|
38786
|
+
if (checkEvent) {
|
|
38787
|
+
emit(`UI:${checkEvent}`, {});
|
|
38788
|
+
}
|
|
38733
38789
|
const correct = correctFlags.length === bugLines.length && falseFlags.length === 0;
|
|
38734
38790
|
if (correct) {
|
|
38735
38791
|
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
38736
38792
|
}
|
|
38737
|
-
}, [correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
38793
|
+
}, [checkEvent, correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
38738
38794
|
const handleReset = () => {
|
|
38739
|
-
|
|
38795
|
+
if (playAgainEvent) {
|
|
38796
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
38797
|
+
}
|
|
38740
38798
|
if (attempts >= 2 && str(resolved?.hint)) {
|
|
38741
38799
|
setShowHint(true);
|
|
38742
38800
|
}
|
|
38743
38801
|
};
|
|
38744
38802
|
const handleFullReset = () => {
|
|
38745
|
-
|
|
38746
|
-
|
|
38747
|
-
|
|
38803
|
+
if (playAgainEvent) {
|
|
38804
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
38805
|
+
}
|
|
38748
38806
|
setShowHint(false);
|
|
38749
38807
|
};
|
|
38750
38808
|
if (!resolved) return null;
|
|
@@ -38772,7 +38830,7 @@ function DebuggerBoard({
|
|
|
38772
38830
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(num(resolved.bugCount)) }) })
|
|
38773
38831
|
] }) }),
|
|
38774
38832
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(exports.VStack, { gap: "none", children: lines.map((line, i) => {
|
|
38775
|
-
const isFlagged =
|
|
38833
|
+
const isFlagged = !!line.isFlagged;
|
|
38776
38834
|
let lineStyle = "";
|
|
38777
38835
|
if (submitted) {
|
|
38778
38836
|
if (line.isBug && isFlagged) lineStyle = "bg-success/10";
|
|
@@ -38806,9 +38864,9 @@ function DebuggerBoard({
|
|
|
38806
38864
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
38807
38865
|
exports.Icon,
|
|
38808
38866
|
{
|
|
38809
|
-
icon:
|
|
38867
|
+
icon: line.isFlagged ? LucideIcons2.CheckCircle : LucideIcons2.XCircle,
|
|
38810
38868
|
size: "xs",
|
|
38811
|
-
className:
|
|
38869
|
+
className: line.isFlagged ? "text-success mt-0.5" : "text-warning mt-0.5"
|
|
38812
38870
|
}
|
|
38813
38871
|
),
|
|
38814
38872
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "none", children: [
|
|
@@ -38819,7 +38877,7 @@ function DebuggerBoard({
|
|
|
38819
38877
|
] }) }),
|
|
38820
38878
|
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(exports.Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", children: hint }) }),
|
|
38821
38879
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", justify: "center", children: [
|
|
38822
|
-
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.
|
|
38880
|
+
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.length === 0, children: [
|
|
38823
38881
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon: LucideIcons2.Send, size: "sm" }),
|
|
38824
38882
|
t("debugger.submit")
|
|
38825
38883
|
] }) : !allCorrect ? /* @__PURE__ */ jsxRuntime.jsx(exports.Button, { variant: "primary", onClick: handleReset, children: t("debugger.tryAgain") }) : null,
|
|
@@ -42779,6 +42837,9 @@ function getOpponentAction(strategy, actions, history) {
|
|
|
42779
42837
|
function NegotiatorBoard({
|
|
42780
42838
|
entity,
|
|
42781
42839
|
completeEvent = "PUZZLE_COMPLETE",
|
|
42840
|
+
playRoundEvent,
|
|
42841
|
+
finishEvent,
|
|
42842
|
+
playAgainEvent,
|
|
42782
42843
|
className
|
|
42783
42844
|
}) {
|
|
42784
42845
|
const { emit } = useEventBus();
|
|
@@ -42787,13 +42848,14 @@ function NegotiatorBoard({
|
|
|
42787
42848
|
const [history, setHistory] = React77.useState([]);
|
|
42788
42849
|
const [headerError, setHeaderError] = React77.useState(false);
|
|
42789
42850
|
const [showHint, setShowHint] = React77.useState(false);
|
|
42790
|
-
const totalRounds = num(resolved?.
|
|
42851
|
+
const totalRounds = num(resolved?.maxRounds);
|
|
42791
42852
|
const targetScore = num(resolved?.targetScore);
|
|
42792
|
-
const currentRound =
|
|
42793
|
-
const
|
|
42794
|
-
const playerTotal =
|
|
42853
|
+
const currentRound = num(resolved?.round);
|
|
42854
|
+
const result = str(resolved?.result) || "none";
|
|
42855
|
+
const playerTotal = num(resolved?.score);
|
|
42856
|
+
const isComplete = result !== "none" || totalRounds > 0 && currentRound >= totalRounds;
|
|
42857
|
+
const won = result === "win";
|
|
42795
42858
|
const opponentTotal = history.reduce((s, r) => s + r.opponentPayoff, 0);
|
|
42796
|
-
const won = isComplete && playerTotal >= targetScore;
|
|
42797
42859
|
const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
|
|
42798
42860
|
const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
|
|
42799
42861
|
const handleAction = React77.useCallback((actionId) => {
|
|
@@ -42802,29 +42864,45 @@ function NegotiatorBoard({
|
|
|
42802
42864
|
const payoff = payoffMatrix.find(
|
|
42803
42865
|
(p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
|
|
42804
42866
|
);
|
|
42805
|
-
const
|
|
42806
|
-
|
|
42807
|
-
|
|
42808
|
-
|
|
42809
|
-
|
|
42810
|
-
|
|
42811
|
-
|
|
42812
|
-
|
|
42813
|
-
|
|
42814
|
-
|
|
42815
|
-
|
|
42816
|
-
|
|
42817
|
-
|
|
42818
|
-
|
|
42819
|
-
|
|
42867
|
+
const playerPayoff = payoff?.playerPayoff ?? 0;
|
|
42868
|
+
setHistory((prev) => [
|
|
42869
|
+
...prev,
|
|
42870
|
+
{
|
|
42871
|
+
round: prev.length + 1,
|
|
42872
|
+
playerAction: actionId,
|
|
42873
|
+
opponentAction,
|
|
42874
|
+
playerPayoff,
|
|
42875
|
+
opponentPayoff: payoff?.opponentPayoff ?? 0
|
|
42876
|
+
}
|
|
42877
|
+
]);
|
|
42878
|
+
if (playRoundEvent) {
|
|
42879
|
+
emit(`UI:${playRoundEvent}`, { playerAction: actionId, payoff: playerPayoff });
|
|
42880
|
+
}
|
|
42881
|
+
if (totalRounds > 0 && currentRound + 1 >= totalRounds) {
|
|
42882
|
+
if (finishEvent) {
|
|
42883
|
+
emit(`UI:${finishEvent}`, {});
|
|
42884
|
+
}
|
|
42885
|
+
if (str(resolved?.hint)) {
|
|
42820
42886
|
setShowHint(true);
|
|
42821
42887
|
}
|
|
42822
42888
|
}
|
|
42823
|
-
}, [isComplete, resolved, totalRounds,
|
|
42824
|
-
const handleReset = () => {
|
|
42889
|
+
}, [isComplete, resolved, totalRounds, currentRound, actions, payoffMatrix, history, playRoundEvent, finishEvent, emit]);
|
|
42890
|
+
const handleReset = React77.useCallback(() => {
|
|
42825
42891
|
setHistory([]);
|
|
42826
42892
|
setShowHint(false);
|
|
42827
|
-
|
|
42893
|
+
if (playAgainEvent) {
|
|
42894
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
42895
|
+
}
|
|
42896
|
+
}, [playAgainEvent, emit]);
|
|
42897
|
+
const completedRef = React77.useRef(false);
|
|
42898
|
+
React77.useEffect(() => {
|
|
42899
|
+
if (result === "win" && !completedRef.current) {
|
|
42900
|
+
completedRef.current = true;
|
|
42901
|
+
emit(`UI:${completeEvent}`, { success: true, score: playerTotal });
|
|
42902
|
+
} else if (result === "none") {
|
|
42903
|
+
completedRef.current = false;
|
|
42904
|
+
}
|
|
42905
|
+
}, [result, playerTotal, completeEvent, emit]);
|
|
42828
42906
|
const getActionLabel = (id) => actions.find((a) => a.id === id)?.label ?? id;
|
|
42829
42907
|
if (!resolved) return null;
|
|
42830
42908
|
const theme = resolved.theme ?? void 0;
|
|
@@ -45825,67 +45903,47 @@ var init_SimulationGraph = __esm({
|
|
|
45825
45903
|
function SimulatorBoard({
|
|
45826
45904
|
entity,
|
|
45827
45905
|
completeEvent = "PUZZLE_COMPLETE",
|
|
45906
|
+
setAEvent,
|
|
45907
|
+
setBEvent,
|
|
45908
|
+
checkEvent,
|
|
45909
|
+
playAgainEvent,
|
|
45828
45910
|
className
|
|
45829
45911
|
}) {
|
|
45830
45912
|
const { emit } = useEventBus();
|
|
45831
45913
|
const { t } = hooks.useTranslate();
|
|
45832
45914
|
const resolved = boardEntity(entity);
|
|
45833
45915
|
const parameters = Array.isArray(resolved?.parameters) ? resolved.parameters : [];
|
|
45834
|
-
const [values, setValues] = React77.useState(() => {
|
|
45835
|
-
const init = {};
|
|
45836
|
-
for (const p2 of parameters) {
|
|
45837
|
-
init[p2.id] = p2.initial;
|
|
45838
|
-
}
|
|
45839
|
-
return init;
|
|
45840
|
-
});
|
|
45841
45916
|
const [headerError, setHeaderError] = React77.useState(false);
|
|
45842
|
-
|
|
45843
|
-
const
|
|
45844
|
-
const
|
|
45845
|
-
const
|
|
45846
|
-
|
|
45847
|
-
|
|
45848
|
-
|
|
45849
|
-
|
|
45850
|
-
|
|
45851
|
-
|
|
45852
|
-
|
|
45853
|
-
const
|
|
45854
|
-
const
|
|
45855
|
-
const
|
|
45856
|
-
const
|
|
45857
|
-
|
|
45858
|
-
|
|
45859
|
-
|
|
45860
|
-
};
|
|
45861
|
-
const handleSubmit = () => {
|
|
45862
|
-
setSubmitted(true);
|
|
45863
|
-
setAttempts((a) => a + 1);
|
|
45864
|
-
if (isCorrect) {
|
|
45865
|
-
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
45866
|
-
}
|
|
45917
|
+
if (!resolved) return null;
|
|
45918
|
+
const paramA = num(resolved.paramA);
|
|
45919
|
+
const paramB = num(resolved.paramB);
|
|
45920
|
+
const output = num(resolved.output);
|
|
45921
|
+
const targetValue = num(resolved.target);
|
|
45922
|
+
const targetTolerance = num(resolved.tolerance);
|
|
45923
|
+
const attempts = num(resolved.attempts);
|
|
45924
|
+
const result = str(resolved.result);
|
|
45925
|
+
const isWin = result === "win";
|
|
45926
|
+
const isComplete = result !== "none" && result !== "";
|
|
45927
|
+
const paramAValue = parameters[0];
|
|
45928
|
+
const paramBValue = parameters[1];
|
|
45929
|
+
const sliderValues = [paramA, paramB];
|
|
45930
|
+
const sliderEvents = [setAEvent, setBEvent];
|
|
45931
|
+
const handleParameterChange = (index, value) => {
|
|
45932
|
+
if (isComplete) return;
|
|
45933
|
+
const ev = sliderEvents[index];
|
|
45934
|
+
if (ev) emit(`UI:${ev}`, { value });
|
|
45867
45935
|
};
|
|
45868
|
-
const
|
|
45869
|
-
|
|
45870
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
45871
|
-
setShowHint(true);
|
|
45872
|
-
}
|
|
45936
|
+
const handleCheck = () => {
|
|
45937
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
45873
45938
|
};
|
|
45874
|
-
const
|
|
45875
|
-
|
|
45876
|
-
for (const p2 of parameters) {
|
|
45877
|
-
init[p2.id] = p2.initial;
|
|
45878
|
-
}
|
|
45879
|
-
setValues(init);
|
|
45880
|
-
setSubmitted(false);
|
|
45881
|
-
setAttempts(0);
|
|
45882
|
-
setShowHint(false);
|
|
45939
|
+
const handlePlayAgain = () => {
|
|
45940
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
45883
45941
|
};
|
|
45884
|
-
if (!resolved) return null;
|
|
45885
45942
|
const theme = resolved.theme ?? void 0;
|
|
45886
45943
|
const themeBackground = theme?.background;
|
|
45887
45944
|
const headerImage = str(resolved.headerImage);
|
|
45888
45945
|
const hint = str(resolved.hint);
|
|
45946
|
+
const showHint = isComplete && !isWin && attempts >= 2 && Boolean(hint);
|
|
45889
45947
|
const outputLabel = str(resolved.outputLabel);
|
|
45890
45948
|
const outputUnit = str(resolved.outputUnit);
|
|
45891
45949
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -45905,41 +45963,43 @@ function SimulatorBoard({
|
|
|
45905
45963
|
] }) }),
|
|
45906
45964
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "md", children: [
|
|
45907
45965
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("simulator.parameters") }),
|
|
45908
|
-
|
|
45909
|
-
/* @__PURE__ */ jsxRuntime.jsxs(exports.
|
|
45910
|
-
/* @__PURE__ */ jsxRuntime.
|
|
45911
|
-
|
|
45912
|
-
|
|
45913
|
-
|
|
45914
|
-
|
|
45915
|
-
|
|
45916
|
-
|
|
45917
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
45918
|
-
"input",
|
|
45919
|
-
{
|
|
45920
|
-
type: "range",
|
|
45921
|
-
min: param.min,
|
|
45922
|
-
max: param.max,
|
|
45923
|
-
step: param.step,
|
|
45924
|
-
value: values[param.id],
|
|
45925
|
-
onChange: (e) => handleParameterChange(param.id, Number(e.target.value)),
|
|
45926
|
-
disabled: submitted,
|
|
45927
|
-
className: "w-full accent-foreground"
|
|
45928
|
-
}
|
|
45929
|
-
),
|
|
45930
|
-
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { justify: "between", children: [
|
|
45931
|
-
/* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
45932
|
-
param.min,
|
|
45933
|
-
" ",
|
|
45934
|
-
param.unit
|
|
45966
|
+
[paramAValue, paramBValue].map(
|
|
45967
|
+
(param, index) => param ? /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "xs", children: [
|
|
45968
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { justify: "between", align: "center", children: [
|
|
45969
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", weight: "medium", children: param.label }),
|
|
45970
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.Badge, { size: "sm", children: [
|
|
45971
|
+
sliderValues[index],
|
|
45972
|
+
" ",
|
|
45973
|
+
param.unit
|
|
45974
|
+
] })
|
|
45935
45975
|
] }),
|
|
45936
|
-
/* @__PURE__ */ jsxRuntime.
|
|
45937
|
-
|
|
45938
|
-
|
|
45939
|
-
|
|
45976
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
45977
|
+
"input",
|
|
45978
|
+
{
|
|
45979
|
+
type: "range",
|
|
45980
|
+
min: param.min,
|
|
45981
|
+
max: param.max,
|
|
45982
|
+
step: param.step,
|
|
45983
|
+
value: sliderValues[index],
|
|
45984
|
+
onChange: (e) => handleParameterChange(index, Number(e.target.value)),
|
|
45985
|
+
disabled: isComplete,
|
|
45986
|
+
className: "w-full accent-foreground"
|
|
45987
|
+
}
|
|
45988
|
+
),
|
|
45989
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { justify: "between", children: [
|
|
45990
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
45991
|
+
param.min,
|
|
45992
|
+
" ",
|
|
45993
|
+
param.unit
|
|
45994
|
+
] }),
|
|
45995
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
45996
|
+
param.max,
|
|
45997
|
+
" ",
|
|
45998
|
+
param.unit
|
|
45999
|
+
] })
|
|
45940
46000
|
] })
|
|
45941
|
-
] })
|
|
45942
|
-
|
|
46001
|
+
] }, param.id ?? index) : null
|
|
46002
|
+
)
|
|
45943
46003
|
] }) }),
|
|
45944
46004
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "sm", align: "center", children: [
|
|
45945
46005
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: outputLabel }),
|
|
@@ -45948,9 +46008,9 @@ function SimulatorBoard({
|
|
|
45948
46008
|
" ",
|
|
45949
46009
|
outputUnit
|
|
45950
46010
|
] }),
|
|
45951
|
-
|
|
45952
|
-
/* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon:
|
|
45953
|
-
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", className:
|
|
46011
|
+
isComplete && /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "xs", align: "center", children: [
|
|
46012
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon: isWin ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "sm", className: isWin ? "text-success" : "text-error" }),
|
|
46013
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", className: isWin ? "text-success" : "text-error", children: isWin ? str(resolved.successMessage) || t("simulator.correct") : str(resolved.failMessage) || t("simulator.incorrect") })
|
|
45954
46014
|
] }),
|
|
45955
46015
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
45956
46016
|
t("simulator.target"),
|
|
@@ -45965,11 +46025,11 @@ function SimulatorBoard({
|
|
|
45965
46025
|
] }) }),
|
|
45966
46026
|
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(exports.Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", children: hint }) }),
|
|
45967
46027
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", justify: "center", children: [
|
|
45968
|
-
!
|
|
46028
|
+
!isComplete ? /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { variant: "primary", onClick: handleCheck, children: [
|
|
45969
46029
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon: LucideIcons2.Play, size: "sm" }),
|
|
45970
46030
|
t("simulator.simulate")
|
|
45971
|
-
] }) :
|
|
45972
|
-
/* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { variant: "secondary", onClick:
|
|
46031
|
+
] }) : null,
|
|
46032
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { variant: "secondary", onClick: handlePlayAgain, children: [
|
|
45973
46033
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon: LucideIcons2.RotateCcw, size: "sm" }),
|
|
45974
46034
|
t("simulator.reset")
|
|
45975
46035
|
] })
|