@almadar/ui 5.146.2 → 5.147.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.
@@ -26224,7 +26224,12 @@ function daysAgo(n) {
26224
26224
  d.setDate(d.getDate() - n);
26225
26225
  return d;
26226
26226
  }
26227
- var DEFAULT_PRESETS, DateRangePicker;
26227
+ function resolvePresetRange(preset) {
26228
+ if (typeof preset.range === "function") return preset.range();
26229
+ if (preset.range) return preset.range;
26230
+ return TOKEN_RANGES[preset.value]?.() ?? null;
26231
+ }
26232
+ var TOKEN_RANGES, DEFAULT_PRESETS, DateRangePicker;
26228
26233
  var init_DateRangePicker = __esm({
26229
26234
  "components/core/molecules/DateRangePicker.tsx"() {
26230
26235
  "use client";
@@ -26234,32 +26239,19 @@ var init_DateRangePicker = __esm({
26234
26239
  init_Stack();
26235
26240
  init_Typography();
26236
26241
  init_useEventBus();
26242
+ TOKEN_RANGES = {
26243
+ "7d": () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) }),
26244
+ "30d": () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) }),
26245
+ month: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) }),
26246
+ quarter: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) }),
26247
+ ytd: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
26248
+ };
26237
26249
  DEFAULT_PRESETS = [
26238
- {
26239
- label: "Last 7 days",
26240
- value: "7d",
26241
- range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
26242
- },
26243
- {
26244
- label: "Last 30 days",
26245
- value: "30d",
26246
- range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
26247
- },
26248
- {
26249
- label: "This Month",
26250
- value: "month",
26251
- range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
26252
- },
26253
- {
26254
- label: "This Quarter",
26255
- value: "quarter",
26256
- range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
26257
- },
26258
- {
26259
- label: "YTD",
26260
- value: "ytd",
26261
- range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
26262
- }
26250
+ { label: "Last 7 days", value: "7d" },
26251
+ { label: "Last 30 days", value: "30d" },
26252
+ { label: "This Month", value: "month" },
26253
+ { label: "This Quarter", value: "quarter" },
26254
+ { label: "YTD", value: "ytd" }
26263
26255
  ];
26264
26256
  DateRangePicker = ({
26265
26257
  from: fromProp,
@@ -26300,7 +26292,8 @@ var init_DateRangePicker = __esm({
26300
26292
  );
26301
26293
  const handlePreset = useCallback(
26302
26294
  (preset) => {
26303
- const range = preset.range();
26295
+ const range = resolvePresetRange(preset);
26296
+ if (range === null) return;
26304
26297
  setFrom(range.from);
26305
26298
  setTo(range.to);
26306
26299
  setActivePreset(preset.value);
@@ -26308,8 +26301,12 @@ var init_DateRangePicker = __esm({
26308
26301
  },
26309
26302
  [emit]
26310
26303
  );
26304
+ const renderablePresets = useMemo(
26305
+ () => presets.filter((p) => p.range !== void 0 || TOKEN_RANGES[p.value] !== void 0),
26306
+ [presets]
26307
+ );
26311
26308
  const presetButtons = useMemo(
26312
- () => presets.map((preset) => /* @__PURE__ */ jsx(
26309
+ () => renderablePresets.map((preset) => /* @__PURE__ */ jsx(
26313
26310
  Button,
26314
26311
  {
26315
26312
  variant: activePreset === preset.value ? "primary" : "ghost",
@@ -26319,7 +26316,7 @@ var init_DateRangePicker = __esm({
26319
26316
  },
26320
26317
  preset.value
26321
26318
  )),
26322
- [presets, activePreset, handlePreset]
26319
+ [renderablePresets, activePreset, handlePreset]
26323
26320
  );
26324
26321
  return /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: cn(className), children: [
26325
26322
  /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "end", children: [
@@ -26346,7 +26343,7 @@ var init_DateRangePicker = __esm({
26346
26343
  )
26347
26344
  ] })
26348
26345
  ] }),
26349
- presets.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
26346
+ renderablePresets.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
26350
26347
  ] });
26351
26348
  };
26352
26349
  DateRangePicker.displayName = "DateRangePicker";
@@ -29222,6 +29219,208 @@ var init_PhysicsCanvas = __esm({
29222
29219
  };
29223
29220
  }
29224
29221
  });
29222
+
29223
+ // lib/graphViewLayouts.ts
29224
+ function buildAdjacency(nodeIds, edges) {
29225
+ const known = new Set(nodeIds);
29226
+ const out = /* @__PURE__ */ new Map();
29227
+ const inMap = /* @__PURE__ */ new Map();
29228
+ for (const id of nodeIds) {
29229
+ out.set(id, []);
29230
+ inMap.set(id, []);
29231
+ }
29232
+ for (const edge of edges) {
29233
+ if (!known.has(edge.source) || !known.has(edge.target)) continue;
29234
+ out.get(edge.source)?.push(edge.target);
29235
+ inMap.get(edge.target)?.push(edge.source);
29236
+ }
29237
+ return { out, in: inMap };
29238
+ }
29239
+ function findRoots(nodeIds, adjacency) {
29240
+ return nodeIds.filter((id) => (adjacency.in.get(id)?.length ?? 0) === 0);
29241
+ }
29242
+ function assignLayers(nodeIds, adjacency, roots) {
29243
+ const layer = new Map(nodeIds.map((id) => [id, 0]));
29244
+ const onStack = /* @__PURE__ */ new Set();
29245
+ const visit = (id) => {
29246
+ onStack.add(id);
29247
+ const currentLayer = layer.get(id) ?? 0;
29248
+ for (const next of adjacency.out.get(id) ?? []) {
29249
+ if (onStack.has(next)) continue;
29250
+ const candidate = currentLayer + 1;
29251
+ if (candidate > (layer.get(next) ?? 0)) {
29252
+ layer.set(next, candidate);
29253
+ }
29254
+ visit(next);
29255
+ }
29256
+ onStack.delete(id);
29257
+ };
29258
+ for (const root of roots) visit(root);
29259
+ return layer;
29260
+ }
29261
+ function computeVisitOrder(nodeIds, adjacency, roots) {
29262
+ const order = /* @__PURE__ */ new Map();
29263
+ const visited = /* @__PURE__ */ new Set();
29264
+ let counter = 0;
29265
+ const visit = (id) => {
29266
+ if (visited.has(id)) return;
29267
+ visited.add(id);
29268
+ order.set(id, counter++);
29269
+ for (const next of adjacency.out.get(id) ?? []) visit(next);
29270
+ };
29271
+ for (const root of roots) visit(root);
29272
+ for (const id of nodeIds) {
29273
+ if (!visited.has(id)) order.set(id, counter++);
29274
+ }
29275
+ return order;
29276
+ }
29277
+ function bfsDepthAndOrder(nodeIds, adjacency, roots) {
29278
+ const depth = new Map(nodeIds.map((id) => [id, 0]));
29279
+ const visitOrder = /* @__PURE__ */ new Map();
29280
+ const visited = /* @__PURE__ */ new Set();
29281
+ const queue = [];
29282
+ let counter = 0;
29283
+ for (const root of roots) {
29284
+ if (visited.has(root)) continue;
29285
+ visited.add(root);
29286
+ depth.set(root, 0);
29287
+ visitOrder.set(root, counter++);
29288
+ queue.push(root);
29289
+ }
29290
+ let head = 0;
29291
+ while (head < queue.length) {
29292
+ const id = queue[head++];
29293
+ const d = depth.get(id) ?? 0;
29294
+ for (const next of adjacency.out.get(id) ?? []) {
29295
+ if (visited.has(next)) continue;
29296
+ visited.add(next);
29297
+ depth.set(next, d + 1);
29298
+ visitOrder.set(next, counter++);
29299
+ queue.push(next);
29300
+ }
29301
+ }
29302
+ for (const id of nodeIds) {
29303
+ if (!visited.has(id)) visitOrder.set(id, counter++);
29304
+ }
29305
+ return { depth, visitOrder };
29306
+ }
29307
+ function edgeWalkOrder(nodeIds, adjacency) {
29308
+ const visited = /* @__PURE__ */ new Set();
29309
+ const result = [];
29310
+ for (const start of nodeIds) {
29311
+ if (visited.has(start)) continue;
29312
+ let current = start;
29313
+ while (current !== void 0 && !visited.has(current)) {
29314
+ visited.add(current);
29315
+ result.push(current);
29316
+ const outs = adjacency.out.get(current) ?? [];
29317
+ current = outs.find((next) => !visited.has(next));
29318
+ }
29319
+ }
29320
+ return result;
29321
+ }
29322
+ function groupByTier(nodeIds, tierOf, maxTier) {
29323
+ const groups = Array.from({ length: maxTier + 1 }, () => []);
29324
+ for (const id of nodeIds) {
29325
+ groups[tierOf.get(id) ?? 0].push(id);
29326
+ }
29327
+ return groups;
29328
+ }
29329
+ function distributeAxis(count, start, end) {
29330
+ if (count <= 0) return [];
29331
+ const slot = (end - start) / count;
29332
+ return Array.from({ length: count }, (_, i) => start + slot * (i + 0.5));
29333
+ }
29334
+ function orderByParentPositionThenInput(group, adjacency, positioned, inputIndex) {
29335
+ const withKey = group.map((id) => {
29336
+ const parentValues = (adjacency.in.get(id) ?? []).map((p) => positioned.get(p)).filter((v) => v !== void 0);
29337
+ const avg = parentValues.length > 0 ? parentValues.reduce((a, b) => a + b, 0) / parentValues.length : Number.POSITIVE_INFINITY;
29338
+ return { id, avg, idx: inputIndex.get(id) ?? 0 };
29339
+ });
29340
+ withKey.sort((a, b) => a.avg !== b.avg ? a.avg - b.avg : a.idx - b.idx);
29341
+ return withKey.map((k) => k.id);
29342
+ }
29343
+ function layoutFlow(nodeIds, adjacency, roots, width, height, margin) {
29344
+ const inputIndex = new Map(nodeIds.map((id, i) => [id, i]));
29345
+ const layers = assignLayers(nodeIds, adjacency, roots);
29346
+ const maxLayer = Math.max(...Array.from(layers.values()));
29347
+ const layerGroups = groupByTier(nodeIds, layers, maxLayer);
29348
+ const positions = /* @__PURE__ */ new Map();
29349
+ const yById = /* @__PURE__ */ new Map();
29350
+ for (let l = 0; l <= maxLayer; l++) {
29351
+ const x = margin + l * (width - 2 * margin) / Math.max(1, maxLayer);
29352
+ const ordered2 = orderByParentPositionThenInput(layerGroups[l], adjacency, yById, inputIndex);
29353
+ const ys = distributeAxis(ordered2.length, margin, height - margin);
29354
+ ordered2.forEach((id, i) => {
29355
+ positions.set(id, { id, x, y: ys[i] });
29356
+ yById.set(id, ys[i]);
29357
+ });
29358
+ }
29359
+ return nodeIds.map((id) => positions.get(id));
29360
+ }
29361
+ function layoutTree(nodeIds, adjacency, roots, width, height, margin) {
29362
+ const effectiveRoots = roots.length > 0 ? roots : [nodeIds[0]];
29363
+ const layers = assignLayers(nodeIds, adjacency, effectiveRoots);
29364
+ const maxLayer = Math.max(...Array.from(layers.values()));
29365
+ const visitOrder = computeVisitOrder(nodeIds, adjacency, effectiveRoots);
29366
+ const layerGroups = groupByTier(nodeIds, layers, maxLayer);
29367
+ const positions = /* @__PURE__ */ new Map();
29368
+ for (let l = 0; l <= maxLayer; l++) {
29369
+ const ordered2 = [...layerGroups[l]].sort(
29370
+ (a, b) => (visitOrder.get(a) ?? 0) - (visitOrder.get(b) ?? 0)
29371
+ );
29372
+ const y = margin + l * (height - 2 * margin) / Math.max(1, maxLayer);
29373
+ const xs = distributeAxis(ordered2.length, margin, width - margin);
29374
+ ordered2.forEach((id, i) => positions.set(id, { id, x: xs[i], y }));
29375
+ }
29376
+ return nodeIds.map((id) => positions.get(id));
29377
+ }
29378
+ function layoutRadial(nodeIds, adjacency, roots, width, height, margin) {
29379
+ const cx = width / 2;
29380
+ const cy = height / 2;
29381
+ const maxRadius = Math.min(width, height) / 2 - margin;
29382
+ if (roots.length === 0) {
29383
+ const order = edgeWalkOrder(nodeIds, adjacency);
29384
+ const k = order.length;
29385
+ const positions2 = /* @__PURE__ */ new Map();
29386
+ order.forEach((id, i) => {
29387
+ const angle = i / k * 2 * Math.PI;
29388
+ positions2.set(id, { id, x: cx + maxRadius * Math.cos(angle), y: cy + maxRadius * Math.sin(angle) });
29389
+ });
29390
+ return nodeIds.map((id) => positions2.get(id));
29391
+ }
29392
+ const { depth, visitOrder } = bfsDepthAndOrder(nodeIds, adjacency, roots);
29393
+ const maxDepth = Math.max(...Array.from(depth.values()));
29394
+ const ringGroups = groupByTier(nodeIds, depth, maxDepth);
29395
+ const positions = /* @__PURE__ */ new Map();
29396
+ for (let d = 0; d <= maxDepth; d++) {
29397
+ const ordered2 = [...ringGroups[d]].sort(
29398
+ (a, b) => (visitOrder.get(a) ?? 0) - (visitOrder.get(b) ?? 0)
29399
+ );
29400
+ const radius = d * maxRadius / Math.max(1, maxDepth);
29401
+ const k = ordered2.length;
29402
+ ordered2.forEach((id, i) => {
29403
+ const angle = i / k * 2 * Math.PI;
29404
+ positions.set(id, { id, x: cx + radius * Math.cos(angle), y: cy + radius * Math.sin(angle) });
29405
+ });
29406
+ }
29407
+ return nodeIds.map((id) => positions.get(id));
29408
+ }
29409
+ function computeStaticLayout(mode, input) {
29410
+ const { nodeIds, edges, width, height } = input;
29411
+ const margin = input.margin ?? 40;
29412
+ if (nodeIds.length === 0) return [];
29413
+ if (nodeIds.length === 1) return [{ id: nodeIds[0], x: width / 2, y: height / 2 }];
29414
+ const adjacency = buildAdjacency(nodeIds, edges);
29415
+ const roots = findRoots(nodeIds, adjacency);
29416
+ if (mode === "flow") return layoutFlow(nodeIds, adjacency, roots, width, height, margin);
29417
+ if (mode === "tree") return layoutTree(nodeIds, adjacency, roots, width, height, margin);
29418
+ return layoutRadial(nodeIds, adjacency, roots, width, height, margin);
29419
+ }
29420
+ var init_graphViewLayouts = __esm({
29421
+ "lib/graphViewLayouts.ts"() {
29422
+ }
29423
+ });
29225
29424
  function resolveNodeColor(node, groups) {
29226
29425
  if (node.color) return node.color;
29227
29426
  if (node.group) {
@@ -29236,6 +29435,7 @@ var init_GraphView = __esm({
29236
29435
  "use client";
29237
29436
  init_cn();
29238
29437
  init_atoms();
29438
+ init_graphViewLayouts();
29239
29439
  GROUP_COLORS = [
29240
29440
  "#3b82f6",
29241
29441
  // blue-500
@@ -29266,11 +29466,13 @@ var init_GraphView = __esm({
29266
29466
  height: propHeight,
29267
29467
  className,
29268
29468
  showLabels = true,
29269
- zoomToFit = true
29469
+ zoomToFit = true,
29470
+ layout = "force"
29270
29471
  }) => {
29271
29472
  const { t } = useTranslate();
29272
29473
  const containerRef = useRef(null);
29273
29474
  const animRef = useRef(0);
29475
+ const arrowMarkerId = useId();
29274
29476
  const [simNodes, setSimNodes] = useState([]);
29275
29477
  const [settled, setSettled] = useState(false);
29276
29478
  const [hoveredId, setHoveredId] = useState(null);
@@ -29327,6 +29529,22 @@ var init_GraphView = __esm({
29327
29529
  fy: 0
29328
29530
  };
29329
29531
  });
29532
+ if (layout !== "force") {
29533
+ const points = computeStaticLayout(layout, {
29534
+ nodeIds: nodes.map((n) => n.id),
29535
+ edges,
29536
+ width: w,
29537
+ height: h
29538
+ });
29539
+ const pointById = new Map(points.map((p) => [p.id, p]));
29540
+ const laidOut = initialNodes.map((node) => {
29541
+ const point = pointById.get(node.id);
29542
+ return point ? { ...node, x: point.x, y: point.y } : node;
29543
+ });
29544
+ setSimNodes(laidOut);
29545
+ setSettled(true);
29546
+ return;
29547
+ }
29330
29548
  let iterations = 0;
29331
29549
  const maxIterations = 120;
29332
29550
  let currentNodes = initialNodes;
@@ -29395,7 +29613,7 @@ var init_GraphView = __esm({
29395
29613
  return () => {
29396
29614
  cancelAnimationFrame(animRef.current);
29397
29615
  };
29398
- }, [nodes, edges, w, h, groups]);
29616
+ }, [nodes, edges, w, h, groups, layout]);
29399
29617
  const viewBox = useMemo(() => {
29400
29618
  if (!zoomToFit || !settled || simNodes.length === 0) {
29401
29619
  return `0 0 ${w} ${h}`;
@@ -29470,6 +29688,19 @@ var init_GraphView = __esm({
29470
29688
  viewBox,
29471
29689
  preserveAspectRatio: "xMidYMid meet",
29472
29690
  children: [
29691
+ layout !== "force" && /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx(
29692
+ "marker",
29693
+ {
29694
+ id: arrowMarkerId,
29695
+ viewBox: "0 0 10 10",
29696
+ refX: "9",
29697
+ refY: "5",
29698
+ markerWidth: "6",
29699
+ markerHeight: "6",
29700
+ orient: "auto-start-reverse",
29701
+ children: /* @__PURE__ */ jsx("path", { d: "M0,0 L10,5 L0,10 z", fill: "currentColor" })
29702
+ }
29703
+ ) }),
29473
29704
  edges.map((edge, idx) => {
29474
29705
  const source = nodeMap.get(edge.source);
29475
29706
  const target = nodeMap.get(edge.target);
@@ -29484,8 +29715,10 @@ var init_GraphView = __esm({
29484
29715
  x2: target.x,
29485
29716
  y2: target.y,
29486
29717
  stroke: edge.color ?? DEFAULT_EDGE_COLOR,
29718
+ color: edge.color ?? DEFAULT_EDGE_COLOR,
29487
29719
  strokeWidth: 1.5,
29488
- opacity: isHighlighted ? 0.8 : 0.15
29720
+ opacity: isHighlighted ? 0.8 : 0.15,
29721
+ markerEnd: layout !== "force" ? `url(#${arrowMarkerId})` : void 0
29489
29722
  }
29490
29723
  ),
29491
29724
  showLabels && edge.label && /* @__PURE__ */ jsx(
@@ -39276,7 +39509,7 @@ function parseLessonSegments(lesson) {
39276
39509
  content = content.replace(connectResult.fullMatch, "").trim();
39277
39510
  }
39278
39511
  const tagRegex = new RegExp(
39279
- '(?<reflect><reflect>(?<reflectClosed>[\\s\\S]*?)<\\/reflect>)|(?<reflectUnclosed><reflect>(?<reflectOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<bloom><bloom\\s+level="(?<bloomLevel>remember|understand|apply|analyze|evaluate|create)">(?<bloomClosed>[\\s\\S]*?)<\\/bloom>)|(?<bloomUnclosed><bloom\\s+level="(?<bloomLevelUn>remember|understand|apply|analyze|evaluate|create)">(?<bloomOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<quiz><question>(?<quizQuestion>[\\s\\S]*?)<\\/question>\\s*<answer>(?<quizAnswer>[\\s\\S]*?)<\\/answer>)|(?<visualize><visualize\\s+type="(?<vizType>algorithms|math|physics|biology|chemistry|probability|freeform)"\\s+description="(?<vizDesc>[^"]*?)"\\s*\\/?>)',
39512
+ '(?<reflect><reflect>(?<reflectClosed>[\\s\\S]*?)<\\/reflect>)|(?<reflectUnclosed><reflect>(?<reflectOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<bloom><bloom\\s+level="(?<bloomLevel>remember|understand|apply|analyze|evaluate|create)">(?<bloomClosed>[\\s\\S]*?)<\\/bloom>)|(?<bloomUnclosed><bloom\\s+level="(?<bloomLevelUn>remember|understand|apply|analyze|evaluate|create)">(?<bloomOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<quiz><question>(?<quizQuestion>[\\s\\S]*?)<\\/question>\\s*<answer>(?<quizAnswer>[\\s\\S]*?)<\\/answer>)|(?<visualize><visualize\\s+type="(?<vizType>algorithms|math|physics|biology|chemistry|probability)"\\s+description="(?<vizDesc>[^"]*?)"\\s*\\/?>)',
39280
39513
  "gi"
39281
39514
  );
39282
39515
  let lastIndex = 0;
@@ -1638,6 +1638,109 @@ function parseContentSegments(content) {
1638
1638
  return segments;
1639
1639
  }
1640
1640
 
1641
+ // lib/lessonSegmentUtils.ts
1642
+ function parseMarkdownWithCodeBlocks2(content) {
1643
+ const segments = [];
1644
+ const codeBlockRegex = /```([^\n\r]*)\r?\n([\s\S]*?)```/g;
1645
+ let lastIndex = 0;
1646
+ let match;
1647
+ while ((match = codeBlockRegex.exec(content)) !== null) {
1648
+ const before = content.slice(lastIndex, match.index);
1649
+ if (before.trim()) {
1650
+ segments.push({ type: "markdown", content: before });
1651
+ }
1652
+ const tokens = match[1].trim().split(/\s+/).filter(Boolean);
1653
+ let rawLanguage = tokens[0] ?? "text";
1654
+ const suffixRunnable = rawLanguage.endsWith("-runnable");
1655
+ const runnable = suffixRunnable || tokens.includes("run");
1656
+ const baseLanguage = suffixRunnable ? rawLanguage.slice(0, -"-runnable".length) || "text" : rawLanguage;
1657
+ segments.push({ type: "code", language: baseLanguage, content: match[2].trim(), runnable });
1658
+ lastIndex = codeBlockRegex.lastIndex;
1659
+ }
1660
+ const remaining = content.slice(lastIndex);
1661
+ if (remaining.trim()) {
1662
+ segments.push({ type: "markdown", content: remaining });
1663
+ }
1664
+ return segments;
1665
+ }
1666
+
1667
+ // lib/parseLessonSegments.ts
1668
+ function extractTagContent(content, tagName) {
1669
+ const closedTagRegex = new RegExp(`<${tagName}>([\\s\\S]*?)<\\/${tagName}>`, "i");
1670
+ const closedMatch = content.match(closedTagRegex);
1671
+ if (closedMatch) {
1672
+ return { content: closedMatch[1].trim(), fullMatch: closedMatch[0] };
1673
+ }
1674
+ const unclosedTagRegex = new RegExp(
1675
+ `<${tagName}>([\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$)`,
1676
+ "i"
1677
+ );
1678
+ const unclosedMatch = content.match(unclosedTagRegex);
1679
+ if (unclosedMatch) {
1680
+ return { content: unclosedMatch[1].trim(), fullMatch: unclosedMatch[0] };
1681
+ }
1682
+ return null;
1683
+ }
1684
+ function parseLessonSegments(lesson) {
1685
+ if (!lesson) return [];
1686
+ let content = lesson.replace(/<prq>[\s\S]*?<\/prq>/gi, "").trim();
1687
+ const segments = [];
1688
+ const activateResult = extractTagContent(content, "activate");
1689
+ if (activateResult) {
1690
+ segments.push({ type: "activate", question: activateResult.content });
1691
+ content = content.replace(activateResult.fullMatch, "").trim();
1692
+ }
1693
+ const connectResult = extractTagContent(content, "connect");
1694
+ if (connectResult) {
1695
+ segments.push({ type: "connect", content: connectResult.content });
1696
+ content = content.replace(connectResult.fullMatch, "").trim();
1697
+ }
1698
+ const tagRegex = new RegExp(
1699
+ '(?<reflect><reflect>(?<reflectClosed>[\\s\\S]*?)<\\/reflect>)|(?<reflectUnclosed><reflect>(?<reflectOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<bloom><bloom\\s+level="(?<bloomLevel>remember|understand|apply|analyze|evaluate|create)">(?<bloomClosed>[\\s\\S]*?)<\\/bloom>)|(?<bloomUnclosed><bloom\\s+level="(?<bloomLevelUn>remember|understand|apply|analyze|evaluate|create)">(?<bloomOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<quiz><question>(?<quizQuestion>[\\s\\S]*?)<\\/question>\\s*<answer>(?<quizAnswer>[\\s\\S]*?)<\\/answer>)|(?<visualize><visualize\\s+type="(?<vizType>algorithms|math|physics|biology|chemistry|probability)"\\s+description="(?<vizDesc>[^"]*?)"\\s*\\/?>)',
1700
+ "gi"
1701
+ );
1702
+ let lastIndex = 0;
1703
+ let match;
1704
+ while ((match = tagRegex.exec(content)) !== null) {
1705
+ const before = content.slice(lastIndex, match.index);
1706
+ if (before.trim()) {
1707
+ segments.push(...parseMarkdownWithCodeBlocks2(before));
1708
+ }
1709
+ const g = match.groups ?? {};
1710
+ if (g.reflect || g.reflectUnclosed) {
1711
+ const prompt = (g.reflectClosed ?? g.reflectOpen ?? "").trim();
1712
+ if (prompt) segments.push({ type: "reflect", prompt });
1713
+ } else if (g.bloom || g.bloomUnclosed) {
1714
+ const level = g.bloomLevel ?? g.bloomLevelUn;
1715
+ const bloomContent = g.bloomClosed ?? g.bloomOpen ?? "";
1716
+ if (level && bloomContent) {
1717
+ const qMatch = bloomContent.match(/<question>([\s\S]*?)<\/question>/i);
1718
+ const aMatch = bloomContent.match(/<answer>([\s\S]*?)<\/answer>/i);
1719
+ if (qMatch && aMatch) {
1720
+ segments.push({ type: "bloom", level, question: qMatch[1].trim(), answer: aMatch[1].trim() });
1721
+ } else if (qMatch) {
1722
+ segments.push({ type: "bloom", level, question: qMatch[1].trim(), answer: "(Answer not provided)" });
1723
+ } else {
1724
+ const clean = bloomContent.replace(/^\*\*Question\s*\d*:?\*\*\s*/i, "").replace(/^\*\*Q\d*:?\*\*\s*/i, "").trim();
1725
+ if (clean) segments.push({ type: "bloom", level, question: clean, answer: "(See answers section below)" });
1726
+ }
1727
+ }
1728
+ } else if (g.quiz) {
1729
+ segments.push({ type: "quiz", question: g.quizQuestion.trim(), answer: g.quizAnswer.trim() });
1730
+ } else if (g.visualize) {
1731
+ segments.push({
1732
+ type: "visualization",
1733
+ visualizationType: g.vizType,
1734
+ description: g.vizDesc ?? ""
1735
+ });
1736
+ }
1737
+ lastIndex = tagRegex.lastIndex;
1738
+ }
1739
+ const remaining = content.slice(lastIndex);
1740
+ if (remaining.trim()) segments.push(...parseMarkdownWithCodeBlocks2(remaining));
1741
+ return segments;
1742
+ }
1743
+
1641
1744
  // lib/jazari/layout.ts
1642
1745
  var GEAR_RADIUS = 35;
1643
1746
  var GEAR_SPACING = 130;
@@ -2001,6 +2104,7 @@ exports.logStateChange = logStateChange;
2001
2104
  exports.logWarning = logWarning;
2002
2105
  exports.onDebugToggle = onDebugToggle;
2003
2106
  exports.parseContentSegments = parseContentSegments;
2107
+ exports.parseLessonSegments = parseLessonSegments;
2004
2108
  exports.parseMarkdownWithCodeBlocks = parseMarkdownWithCodeBlocks;
2005
2109
  exports.pipeIconPath = pipeIconPath;
2006
2110
  exports.recordGuardEvaluation = recordGuardEvaluation;
@@ -1,6 +1,7 @@
1
- export { C as ContentSegment, D as DEFAULT_CONFIG, a as DomEntityBox, b as DomLayoutData, c as DomOutputsBox, d as DomStateNode, e as DomTransitionLabel, f as DomTransitionPath, E as EntityDefinition, R as RenderOptions, S as StateDefinition, g as StateMachineDefinition, T as TraitSnapshotGetter, h as TransitionDefinition, V as VisualizerConfig, i as bindCanvasCapture, j as bindEventBus, k as bindLastDrawables, l as bindTraitStateGetter, m as clearVerification, n as cn, o as extractOutputsFromTransitions, p as extractStateMachine, q as formatGuard, r as getAllChecks, s as getBridgeHealth, t as getEffectSummary, u as getSnapshot, v as getSummary, w as getTraitSnapshots, x as getTransitions, y as getTransitionsForTrait, z as parseContentSegments, A as parseMarkdownWithCodeBlocks, B as recordServerResponse, F as recordTransition, G as registerCheck, H as registerTraitSnapshot, I as renderStateMachineToDomData, J as renderStateMachineToSvg, K as subscribeToVerification, L as updateAssetStatus, M as updateBridgeHealth, N as updateCheck, O as waitForTransition } from '../cn-BdGFhYe3.cjs';
1
+ export { C as ContentSegment, D as DEFAULT_CONFIG, a as DomEntityBox, b as DomLayoutData, c as DomOutputsBox, d as DomStateNode, e as DomTransitionLabel, f as DomTransitionPath, E as EntityDefinition, L as LessonSegment, R as RenderOptions, S as StateDefinition, g as StateMachineDefinition, T as TraitSnapshotGetter, h as TransitionDefinition, V as VisualizerConfig, i as bindCanvasCapture, j as bindEventBus, k as bindLastDrawables, l as bindTraitStateGetter, m as clearVerification, n as cn, o as extractOutputsFromTransitions, p as extractStateMachine, q as formatGuard, r as getAllChecks, s as getBridgeHealth, t as getEffectSummary, u as getSnapshot, v as getSummary, w as getTraitSnapshots, x as getTransitions, y as getTransitionsForTrait, z as parseContentSegments, A as parseLessonSegments, B as parseMarkdownWithCodeBlocks, F as recordServerResponse, G as recordTransition, H as registerCheck, I as registerTraitSnapshot, J as renderStateMachineToDomData, K as renderStateMachineToSvg, M as subscribeToVerification, N as updateAssetStatus, O as updateBridgeHealth, P as updateCheck, Q as waitForTransition } from '../cn-BAn68sNO.cjs';
2
2
  import { FieldValue, EntityRow, EventPayload } from '@almadar/core';
3
3
  export { AssetLoadStatus, BridgeHealth, CheckStatus, EffectTrace, EventLogEntry, OrbitalVerificationAPI, ServerResponseTrace, TraitStateSnapshot, TransitionTrace, VerificationCheck, VerificationSnapshot, VerificationSummary } from '@almadar/core';
4
+ import 'react';
4
5
  import '../paintDispatch-Cb_hQj4Y.cjs';
5
6
  import 'clsx';
6
7
 
@@ -1,6 +1,7 @@
1
- export { C as ContentSegment, D as DEFAULT_CONFIG, a as DomEntityBox, b as DomLayoutData, c as DomOutputsBox, d as DomStateNode, e as DomTransitionLabel, f as DomTransitionPath, E as EntityDefinition, R as RenderOptions, S as StateDefinition, g as StateMachineDefinition, T as TraitSnapshotGetter, h as TransitionDefinition, V as VisualizerConfig, i as bindCanvasCapture, j as bindEventBus, k as bindLastDrawables, l as bindTraitStateGetter, m as clearVerification, n as cn, o as extractOutputsFromTransitions, p as extractStateMachine, q as formatGuard, r as getAllChecks, s as getBridgeHealth, t as getEffectSummary, u as getSnapshot, v as getSummary, w as getTraitSnapshots, x as getTransitions, y as getTransitionsForTrait, z as parseContentSegments, A as parseMarkdownWithCodeBlocks, B as recordServerResponse, F as recordTransition, G as registerCheck, H as registerTraitSnapshot, I as renderStateMachineToDomData, J as renderStateMachineToSvg, K as subscribeToVerification, L as updateAssetStatus, M as updateBridgeHealth, N as updateCheck, O as waitForTransition } from '../cn-DNkqAWZK.js';
1
+ export { C as ContentSegment, D as DEFAULT_CONFIG, a as DomEntityBox, b as DomLayoutData, c as DomOutputsBox, d as DomStateNode, e as DomTransitionLabel, f as DomTransitionPath, E as EntityDefinition, L as LessonSegment, R as RenderOptions, S as StateDefinition, g as StateMachineDefinition, T as TraitSnapshotGetter, h as TransitionDefinition, V as VisualizerConfig, i as bindCanvasCapture, j as bindEventBus, k as bindLastDrawables, l as bindTraitStateGetter, m as clearVerification, n as cn, o as extractOutputsFromTransitions, p as extractStateMachine, q as formatGuard, r as getAllChecks, s as getBridgeHealth, t as getEffectSummary, u as getSnapshot, v as getSummary, w as getTraitSnapshots, x as getTransitions, y as getTransitionsForTrait, z as parseContentSegments, A as parseLessonSegments, B as parseMarkdownWithCodeBlocks, F as recordServerResponse, G as recordTransition, H as registerCheck, I as registerTraitSnapshot, J as renderStateMachineToDomData, K as renderStateMachineToSvg, M as subscribeToVerification, N as updateAssetStatus, O as updateBridgeHealth, P as updateCheck, Q as waitForTransition } from '../cn-CWxxLkri.js';
2
2
  import { FieldValue, EntityRow, EventPayload } from '@almadar/core';
3
3
  export { AssetLoadStatus, BridgeHealth, CheckStatus, EffectTrace, EventLogEntry, OrbitalVerificationAPI, ServerResponseTrace, TraitStateSnapshot, TransitionTrace, VerificationCheck, VerificationSnapshot, VerificationSummary } from '@almadar/core';
4
+ import 'react';
4
5
  import '../paintDispatch-Cb_hQj4Y.js';
5
6
  import 'clsx';
6
7
 
package/dist/lib/index.js CHANGED
@@ -1636,6 +1636,109 @@ function parseContentSegments(content) {
1636
1636
  return segments;
1637
1637
  }
1638
1638
 
1639
+ // lib/lessonSegmentUtils.ts
1640
+ function parseMarkdownWithCodeBlocks2(content) {
1641
+ const segments = [];
1642
+ const codeBlockRegex = /```([^\n\r]*)\r?\n([\s\S]*?)```/g;
1643
+ let lastIndex = 0;
1644
+ let match;
1645
+ while ((match = codeBlockRegex.exec(content)) !== null) {
1646
+ const before = content.slice(lastIndex, match.index);
1647
+ if (before.trim()) {
1648
+ segments.push({ type: "markdown", content: before });
1649
+ }
1650
+ const tokens = match[1].trim().split(/\s+/).filter(Boolean);
1651
+ let rawLanguage = tokens[0] ?? "text";
1652
+ const suffixRunnable = rawLanguage.endsWith("-runnable");
1653
+ const runnable = suffixRunnable || tokens.includes("run");
1654
+ const baseLanguage = suffixRunnable ? rawLanguage.slice(0, -"-runnable".length) || "text" : rawLanguage;
1655
+ segments.push({ type: "code", language: baseLanguage, content: match[2].trim(), runnable });
1656
+ lastIndex = codeBlockRegex.lastIndex;
1657
+ }
1658
+ const remaining = content.slice(lastIndex);
1659
+ if (remaining.trim()) {
1660
+ segments.push({ type: "markdown", content: remaining });
1661
+ }
1662
+ return segments;
1663
+ }
1664
+
1665
+ // lib/parseLessonSegments.ts
1666
+ function extractTagContent(content, tagName) {
1667
+ const closedTagRegex = new RegExp(`<${tagName}>([\\s\\S]*?)<\\/${tagName}>`, "i");
1668
+ const closedMatch = content.match(closedTagRegex);
1669
+ if (closedMatch) {
1670
+ return { content: closedMatch[1].trim(), fullMatch: closedMatch[0] };
1671
+ }
1672
+ const unclosedTagRegex = new RegExp(
1673
+ `<${tagName}>([\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$)`,
1674
+ "i"
1675
+ );
1676
+ const unclosedMatch = content.match(unclosedTagRegex);
1677
+ if (unclosedMatch) {
1678
+ return { content: unclosedMatch[1].trim(), fullMatch: unclosedMatch[0] };
1679
+ }
1680
+ return null;
1681
+ }
1682
+ function parseLessonSegments(lesson) {
1683
+ if (!lesson) return [];
1684
+ let content = lesson.replace(/<prq>[\s\S]*?<\/prq>/gi, "").trim();
1685
+ const segments = [];
1686
+ const activateResult = extractTagContent(content, "activate");
1687
+ if (activateResult) {
1688
+ segments.push({ type: "activate", question: activateResult.content });
1689
+ content = content.replace(activateResult.fullMatch, "").trim();
1690
+ }
1691
+ const connectResult = extractTagContent(content, "connect");
1692
+ if (connectResult) {
1693
+ segments.push({ type: "connect", content: connectResult.content });
1694
+ content = content.replace(connectResult.fullMatch, "").trim();
1695
+ }
1696
+ const tagRegex = new RegExp(
1697
+ '(?<reflect><reflect>(?<reflectClosed>[\\s\\S]*?)<\\/reflect>)|(?<reflectUnclosed><reflect>(?<reflectOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<bloom><bloom\\s+level="(?<bloomLevel>remember|understand|apply|analyze|evaluate|create)">(?<bloomClosed>[\\s\\S]*?)<\\/bloom>)|(?<bloomUnclosed><bloom\\s+level="(?<bloomLevelUn>remember|understand|apply|analyze|evaluate|create)">(?<bloomOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<quiz><question>(?<quizQuestion>[\\s\\S]*?)<\\/question>\\s*<answer>(?<quizAnswer>[\\s\\S]*?)<\\/answer>)|(?<visualize><visualize\\s+type="(?<vizType>algorithms|math|physics|biology|chemistry|probability)"\\s+description="(?<vizDesc>[^"]*?)"\\s*\\/?>)',
1698
+ "gi"
1699
+ );
1700
+ let lastIndex = 0;
1701
+ let match;
1702
+ while ((match = tagRegex.exec(content)) !== null) {
1703
+ const before = content.slice(lastIndex, match.index);
1704
+ if (before.trim()) {
1705
+ segments.push(...parseMarkdownWithCodeBlocks2(before));
1706
+ }
1707
+ const g = match.groups ?? {};
1708
+ if (g.reflect || g.reflectUnclosed) {
1709
+ const prompt = (g.reflectClosed ?? g.reflectOpen ?? "").trim();
1710
+ if (prompt) segments.push({ type: "reflect", prompt });
1711
+ } else if (g.bloom || g.bloomUnclosed) {
1712
+ const level = g.bloomLevel ?? g.bloomLevelUn;
1713
+ const bloomContent = g.bloomClosed ?? g.bloomOpen ?? "";
1714
+ if (level && bloomContent) {
1715
+ const qMatch = bloomContent.match(/<question>([\s\S]*?)<\/question>/i);
1716
+ const aMatch = bloomContent.match(/<answer>([\s\S]*?)<\/answer>/i);
1717
+ if (qMatch && aMatch) {
1718
+ segments.push({ type: "bloom", level, question: qMatch[1].trim(), answer: aMatch[1].trim() });
1719
+ } else if (qMatch) {
1720
+ segments.push({ type: "bloom", level, question: qMatch[1].trim(), answer: "(Answer not provided)" });
1721
+ } else {
1722
+ const clean = bloomContent.replace(/^\*\*Question\s*\d*:?\*\*\s*/i, "").replace(/^\*\*Q\d*:?\*\*\s*/i, "").trim();
1723
+ if (clean) segments.push({ type: "bloom", level, question: clean, answer: "(See answers section below)" });
1724
+ }
1725
+ }
1726
+ } else if (g.quiz) {
1727
+ segments.push({ type: "quiz", question: g.quizQuestion.trim(), answer: g.quizAnswer.trim() });
1728
+ } else if (g.visualize) {
1729
+ segments.push({
1730
+ type: "visualization",
1731
+ visualizationType: g.vizType,
1732
+ description: g.vizDesc ?? ""
1733
+ });
1734
+ }
1735
+ lastIndex = tagRegex.lastIndex;
1736
+ }
1737
+ const remaining = content.slice(lastIndex);
1738
+ if (remaining.trim()) segments.push(...parseMarkdownWithCodeBlocks2(remaining));
1739
+ return segments;
1740
+ }
1741
+
1639
1742
  // lib/jazari/layout.ts
1640
1743
  var GEAR_RADIUS = 35;
1641
1744
  var GEAR_SPACING = 130;
@@ -1921,4 +2024,4 @@ var JAZARI_COLORS = {
1921
2024
  darkBg: "#1a1a2e"
1922
2025
  };
1923
2026
 
1924
- export { ApiError, DEFAULT_CONFIG, JAZARI_COLORS, apiClient, arrowheadPath, bindCanvasCapture, bindEventBus, bindLastDrawables, bindTraitStateGetter, brainIconPath, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, clearVerification, cn, compareCellValues, computeJazariLayout, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, eightPointedStarPath, extractOutputsFromTransitions, extractStateMachine, formatDate, formatDateTime, formatGuard, formatNestedFieldLabel, formatTime, formatValue, gearTeethPath, getAllChecks, getAllTicks, getAllTraits, getBridgeHealth, getDebugEvents, getEffectSummary, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getNestedValue, getRecentEvents, getRecentGuardEvaluations, getSnapshot, getSummary, getTick, getTrait, getTraitSnapshots, getTransitions, getTransitionsForTrait, humanizeEnumValue, humanizeFieldName, initDebugShortcut, isDebugEnabled, lockIconPath, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, onDebugToggle, parseContentSegments, parseMarkdownWithCodeBlocks, pipeIconPath, recordGuardEvaluation, recordServerResponse, recordTransition, registerCheck, registerTick, registerTrait, registerTraitSnapshot, renderStateMachineToDomData, renderStateMachineToSvg, setDebugEnabled, setEntityProvider, setTickActive, sortRows, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, subscribeToVerification, toggleDebug, unregisterTick, unregisterTrait, updateAssetStatus, updateBridgeHealth, updateCheck, updateGuardResult, updateTickExecution, updateTraitState, waitForTransition };
2027
+ export { ApiError, DEFAULT_CONFIG, JAZARI_COLORS, apiClient, arrowheadPath, bindCanvasCapture, bindEventBus, bindLastDrawables, bindTraitStateGetter, brainIconPath, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, clearVerification, cn, compareCellValues, computeJazariLayout, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, eightPointedStarPath, extractOutputsFromTransitions, extractStateMachine, formatDate, formatDateTime, formatGuard, formatNestedFieldLabel, formatTime, formatValue, gearTeethPath, getAllChecks, getAllTicks, getAllTraits, getBridgeHealth, getDebugEvents, getEffectSummary, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getNestedValue, getRecentEvents, getRecentGuardEvaluations, getSnapshot, getSummary, getTick, getTrait, getTraitSnapshots, getTransitions, getTransitionsForTrait, humanizeEnumValue, humanizeFieldName, initDebugShortcut, isDebugEnabled, lockIconPath, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, onDebugToggle, parseContentSegments, parseLessonSegments, parseMarkdownWithCodeBlocks, pipeIconPath, recordGuardEvaluation, recordServerResponse, recordTransition, registerCheck, registerTick, registerTrait, registerTraitSnapshot, renderStateMachineToDomData, renderStateMachineToSvg, setDebugEnabled, setEntityProvider, setTickActive, sortRows, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, subscribeToVerification, toggleDebug, unregisterTick, unregisterTrait, updateAssetStatus, updateBridgeHealth, updateCheck, updateGuardResult, updateTickExecution, updateTraitState, waitForTransition };