@almadar/ui 5.146.3 → 5.148.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.
@@ -8615,7 +8615,10 @@ var init_LearningCanvas = __esm({
8615
8615
  ctx.fillRect(0, 0, width, height);
8616
8616
  }
8617
8617
  for (const shape of shapes) {
8618
- drawShape(ctx, shape, width, height);
8618
+ if (shape.type !== "text") drawShape(ctx, shape, width, height);
8619
+ }
8620
+ for (const shape of shapes) {
8621
+ if (shape.type === "text") drawShape(ctx, shape, width, height);
8619
8622
  }
8620
8623
  }, [width, height, backgroundColor, shapes]);
8621
8624
  useEffect(() => {
@@ -8696,7 +8699,7 @@ var init_AlgorithmCanvas = __esm({
8696
8699
  DEFAULT_CELL_COLOR = "#e5e7eb";
8697
8700
  DEFAULT_POINTER_COLOR = "#dc2626";
8698
8701
  POINTER_BAND = 34;
8699
- TOP_PAD = 12;
8702
+ TOP_PAD = 26;
8700
8703
  AlgorithmCanvas = ({
8701
8704
  className,
8702
8705
  width = 600,
@@ -23681,6 +23684,7 @@ var init_FilterGroup = __esm({
23681
23684
  init_Badge();
23682
23685
  init_Stack();
23683
23686
  init_Icon();
23687
+ init_RangeSlider();
23684
23688
  init_useEventBus();
23685
23689
  init_useQuerySingleton();
23686
23690
  resolveFilterType = (filter) => filter.filterType ?? filter.type;
@@ -23875,6 +23879,35 @@ var init_FilterGroup = __esm({
23875
23879
  onClear: () => handleFilterSelect(`${filter.field}_to`, null)
23876
23880
  }
23877
23881
  )
23882
+ ] }) : resolveFilterType(filter) === "numberrange" || resolveFilterType(filter) === "number-range" ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
23883
+ /* @__PURE__ */ jsx(
23884
+ RangeSlider,
23885
+ {
23886
+ min: filter.min ?? 0,
23887
+ max: filter.max ?? 100,
23888
+ step: filter.step ?? 1,
23889
+ value: Number(
23890
+ selectedValues[`${filter.field}_min`] ?? filter.min ?? 0
23891
+ ),
23892
+ onChange: (v) => handleFilterSelect(`${filter.field}_min`, String(v)),
23893
+ showTooltip: true,
23894
+ "aria-label": t("filterGroup.from")
23895
+ }
23896
+ ),
23897
+ /* @__PURE__ */ jsx(
23898
+ RangeSlider,
23899
+ {
23900
+ min: filter.min ?? 0,
23901
+ max: filter.max ?? 100,
23902
+ step: filter.step ?? 1,
23903
+ value: Number(
23904
+ selectedValues[`${filter.field}_max`] ?? filter.max ?? 100
23905
+ ),
23906
+ onChange: (v) => handleFilterSelect(`${filter.field}_max`, String(v)),
23907
+ showTooltip: true,
23908
+ "aria-label": t("filterGroup.to")
23909
+ }
23910
+ )
23878
23911
  ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
23879
23912
  Input,
23880
23913
  {
@@ -23957,6 +23990,36 @@ var init_FilterGroup = __esm({
23957
23990
  className: "text-sm min-w-[100px]"
23958
23991
  }
23959
23992
  )
23993
+ ] }) : resolveFilterType(filter) === "numberrange" || resolveFilterType(filter) === "number-range" ? /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
23994
+ /* @__PURE__ */ jsx(
23995
+ RangeSlider,
23996
+ {
23997
+ min: filter.min ?? 0,
23998
+ max: filter.max ?? 100,
23999
+ step: filter.step ?? 1,
24000
+ value: Number(
24001
+ selectedValues[`${filter.field}_min`] ?? filter.min ?? 0
24002
+ ),
24003
+ onChange: (v) => handleFilterSelect(`${filter.field}_min`, String(v)),
24004
+ className: "min-w-[100px]",
24005
+ "aria-label": t("filterGroup.from")
24006
+ }
24007
+ ),
24008
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "-" }),
24009
+ /* @__PURE__ */ jsx(
24010
+ RangeSlider,
24011
+ {
24012
+ min: filter.min ?? 0,
24013
+ max: filter.max ?? 100,
24014
+ step: filter.step ?? 1,
24015
+ value: Number(
24016
+ selectedValues[`${filter.field}_max`] ?? filter.max ?? 100
24017
+ ),
24018
+ onChange: (v) => handleFilterSelect(`${filter.field}_max`, String(v)),
24019
+ className: "min-w-[100px]",
24020
+ "aria-label": t("filterGroup.to")
24021
+ }
24022
+ )
23960
24023
  ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
23961
24024
  Input,
23962
24025
  {
@@ -24075,6 +24138,38 @@ var init_FilterGroup = __esm({
24075
24138
  className: "min-w-[130px]"
24076
24139
  }
24077
24140
  )
24141
+ ] }) : resolveFilterType(filter) === "numberrange" || resolveFilterType(filter) === "number-range" ? /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
24142
+ /* @__PURE__ */ jsx(
24143
+ RangeSlider,
24144
+ {
24145
+ min: filter.min ?? 0,
24146
+ max: filter.max ?? 100,
24147
+ step: filter.step ?? 1,
24148
+ value: Number(
24149
+ selectedValues[`${filter.field}_min`] ?? filter.min ?? 0
24150
+ ),
24151
+ onChange: (v) => handleFilterSelect(`${filter.field}_min`, String(v)),
24152
+ showTooltip: true,
24153
+ className: "min-w-[130px]",
24154
+ "aria-label": t("filterGroup.from")
24155
+ }
24156
+ ),
24157
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "-" }),
24158
+ /* @__PURE__ */ jsx(
24159
+ RangeSlider,
24160
+ {
24161
+ min: filter.min ?? 0,
24162
+ max: filter.max ?? 100,
24163
+ step: filter.step ?? 1,
24164
+ value: Number(
24165
+ selectedValues[`${filter.field}_max`] ?? filter.max ?? 100
24166
+ ),
24167
+ onChange: (v) => handleFilterSelect(`${filter.field}_max`, String(v)),
24168
+ showTooltip: true,
24169
+ className: "min-w-[130px]",
24170
+ "aria-label": t("filterGroup.to")
24171
+ }
24172
+ )
24078
24173
  ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
24079
24174
  Input,
24080
24175
  {
@@ -26224,7 +26319,12 @@ function daysAgo(n) {
26224
26319
  d.setDate(d.getDate() - n);
26225
26320
  return d;
26226
26321
  }
26227
- var DEFAULT_PRESETS, DateRangePicker;
26322
+ function resolvePresetRange(preset) {
26323
+ if (typeof preset.range === "function") return preset.range();
26324
+ if (preset.range) return preset.range;
26325
+ return TOKEN_RANGES[preset.value]?.() ?? null;
26326
+ }
26327
+ var TOKEN_RANGES, DEFAULT_PRESETS, DateRangePicker;
26228
26328
  var init_DateRangePicker = __esm({
26229
26329
  "components/core/molecules/DateRangePicker.tsx"() {
26230
26330
  "use client";
@@ -26234,32 +26334,19 @@ var init_DateRangePicker = __esm({
26234
26334
  init_Stack();
26235
26335
  init_Typography();
26236
26336
  init_useEventBus();
26337
+ TOKEN_RANGES = {
26338
+ "7d": () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) }),
26339
+ "30d": () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) }),
26340
+ month: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) }),
26341
+ quarter: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) }),
26342
+ ytd: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
26343
+ };
26237
26344
  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
- }
26345
+ { label: "Last 7 days", value: "7d" },
26346
+ { label: "Last 30 days", value: "30d" },
26347
+ { label: "This Month", value: "month" },
26348
+ { label: "This Quarter", value: "quarter" },
26349
+ { label: "YTD", value: "ytd" }
26263
26350
  ];
26264
26351
  DateRangePicker = ({
26265
26352
  from: fromProp,
@@ -26300,7 +26387,8 @@ var init_DateRangePicker = __esm({
26300
26387
  );
26301
26388
  const handlePreset = useCallback(
26302
26389
  (preset) => {
26303
- const range = preset.range();
26390
+ const range = resolvePresetRange(preset);
26391
+ if (range === null) return;
26304
26392
  setFrom(range.from);
26305
26393
  setTo(range.to);
26306
26394
  setActivePreset(preset.value);
@@ -26308,8 +26396,12 @@ var init_DateRangePicker = __esm({
26308
26396
  },
26309
26397
  [emit]
26310
26398
  );
26399
+ const renderablePresets = useMemo(
26400
+ () => presets.filter((p) => p.range !== void 0 || TOKEN_RANGES[p.value] !== void 0),
26401
+ [presets]
26402
+ );
26311
26403
  const presetButtons = useMemo(
26312
- () => presets.map((preset) => /* @__PURE__ */ jsx(
26404
+ () => renderablePresets.map((preset) => /* @__PURE__ */ jsx(
26313
26405
  Button,
26314
26406
  {
26315
26407
  variant: activePreset === preset.value ? "primary" : "ghost",
@@ -26319,7 +26411,7 @@ var init_DateRangePicker = __esm({
26319
26411
  },
26320
26412
  preset.value
26321
26413
  )),
26322
- [presets, activePreset, handlePreset]
26414
+ [renderablePresets, activePreset, handlePreset]
26323
26415
  );
26324
26416
  return /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: cn(className), children: [
26325
26417
  /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "end", children: [
@@ -26346,7 +26438,7 @@ var init_DateRangePicker = __esm({
26346
26438
  )
26347
26439
  ] })
26348
26440
  ] }),
26349
- presets.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
26441
+ renderablePresets.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
26350
26442
  ] });
26351
26443
  };
26352
26444
  DateRangePicker.displayName = "DateRangePicker";
@@ -29222,6 +29314,208 @@ var init_PhysicsCanvas = __esm({
29222
29314
  };
29223
29315
  }
29224
29316
  });
29317
+
29318
+ // lib/graphViewLayouts.ts
29319
+ function buildAdjacency(nodeIds, edges) {
29320
+ const known = new Set(nodeIds);
29321
+ const out = /* @__PURE__ */ new Map();
29322
+ const inMap = /* @__PURE__ */ new Map();
29323
+ for (const id of nodeIds) {
29324
+ out.set(id, []);
29325
+ inMap.set(id, []);
29326
+ }
29327
+ for (const edge of edges) {
29328
+ if (!known.has(edge.source) || !known.has(edge.target)) continue;
29329
+ out.get(edge.source)?.push(edge.target);
29330
+ inMap.get(edge.target)?.push(edge.source);
29331
+ }
29332
+ return { out, in: inMap };
29333
+ }
29334
+ function findRoots(nodeIds, adjacency) {
29335
+ return nodeIds.filter((id) => (adjacency.in.get(id)?.length ?? 0) === 0);
29336
+ }
29337
+ function assignLayers(nodeIds, adjacency, roots) {
29338
+ const layer = new Map(nodeIds.map((id) => [id, 0]));
29339
+ const onStack = /* @__PURE__ */ new Set();
29340
+ const visit = (id) => {
29341
+ onStack.add(id);
29342
+ const currentLayer = layer.get(id) ?? 0;
29343
+ for (const next of adjacency.out.get(id) ?? []) {
29344
+ if (onStack.has(next)) continue;
29345
+ const candidate = currentLayer + 1;
29346
+ if (candidate > (layer.get(next) ?? 0)) {
29347
+ layer.set(next, candidate);
29348
+ }
29349
+ visit(next);
29350
+ }
29351
+ onStack.delete(id);
29352
+ };
29353
+ for (const root of roots) visit(root);
29354
+ return layer;
29355
+ }
29356
+ function computeVisitOrder(nodeIds, adjacency, roots) {
29357
+ const order = /* @__PURE__ */ new Map();
29358
+ const visited = /* @__PURE__ */ new Set();
29359
+ let counter = 0;
29360
+ const visit = (id) => {
29361
+ if (visited.has(id)) return;
29362
+ visited.add(id);
29363
+ order.set(id, counter++);
29364
+ for (const next of adjacency.out.get(id) ?? []) visit(next);
29365
+ };
29366
+ for (const root of roots) visit(root);
29367
+ for (const id of nodeIds) {
29368
+ if (!visited.has(id)) order.set(id, counter++);
29369
+ }
29370
+ return order;
29371
+ }
29372
+ function bfsDepthAndOrder(nodeIds, adjacency, roots) {
29373
+ const depth = new Map(nodeIds.map((id) => [id, 0]));
29374
+ const visitOrder = /* @__PURE__ */ new Map();
29375
+ const visited = /* @__PURE__ */ new Set();
29376
+ const queue = [];
29377
+ let counter = 0;
29378
+ for (const root of roots) {
29379
+ if (visited.has(root)) continue;
29380
+ visited.add(root);
29381
+ depth.set(root, 0);
29382
+ visitOrder.set(root, counter++);
29383
+ queue.push(root);
29384
+ }
29385
+ let head = 0;
29386
+ while (head < queue.length) {
29387
+ const id = queue[head++];
29388
+ const d = depth.get(id) ?? 0;
29389
+ for (const next of adjacency.out.get(id) ?? []) {
29390
+ if (visited.has(next)) continue;
29391
+ visited.add(next);
29392
+ depth.set(next, d + 1);
29393
+ visitOrder.set(next, counter++);
29394
+ queue.push(next);
29395
+ }
29396
+ }
29397
+ for (const id of nodeIds) {
29398
+ if (!visited.has(id)) visitOrder.set(id, counter++);
29399
+ }
29400
+ return { depth, visitOrder };
29401
+ }
29402
+ function edgeWalkOrder(nodeIds, adjacency) {
29403
+ const visited = /* @__PURE__ */ new Set();
29404
+ const result = [];
29405
+ for (const start of nodeIds) {
29406
+ if (visited.has(start)) continue;
29407
+ let current = start;
29408
+ while (current !== void 0 && !visited.has(current)) {
29409
+ visited.add(current);
29410
+ result.push(current);
29411
+ const outs = adjacency.out.get(current) ?? [];
29412
+ current = outs.find((next) => !visited.has(next));
29413
+ }
29414
+ }
29415
+ return result;
29416
+ }
29417
+ function groupByTier(nodeIds, tierOf, maxTier) {
29418
+ const groups = Array.from({ length: maxTier + 1 }, () => []);
29419
+ for (const id of nodeIds) {
29420
+ groups[tierOf.get(id) ?? 0].push(id);
29421
+ }
29422
+ return groups;
29423
+ }
29424
+ function distributeAxis(count, start, end) {
29425
+ if (count <= 0) return [];
29426
+ const slot = (end - start) / count;
29427
+ return Array.from({ length: count }, (_, i) => start + slot * (i + 0.5));
29428
+ }
29429
+ function orderByParentPositionThenInput(group, adjacency, positioned, inputIndex) {
29430
+ const withKey = group.map((id) => {
29431
+ const parentValues = (adjacency.in.get(id) ?? []).map((p) => positioned.get(p)).filter((v) => v !== void 0);
29432
+ const avg = parentValues.length > 0 ? parentValues.reduce((a, b) => a + b, 0) / parentValues.length : Number.POSITIVE_INFINITY;
29433
+ return { id, avg, idx: inputIndex.get(id) ?? 0 };
29434
+ });
29435
+ withKey.sort((a, b) => a.avg !== b.avg ? a.avg - b.avg : a.idx - b.idx);
29436
+ return withKey.map((k) => k.id);
29437
+ }
29438
+ function layoutFlow(nodeIds, adjacency, roots, width, height, margin) {
29439
+ const inputIndex = new Map(nodeIds.map((id, i) => [id, i]));
29440
+ const layers = assignLayers(nodeIds, adjacency, roots);
29441
+ const maxLayer = Math.max(...Array.from(layers.values()));
29442
+ const layerGroups = groupByTier(nodeIds, layers, maxLayer);
29443
+ const positions = /* @__PURE__ */ new Map();
29444
+ const yById = /* @__PURE__ */ new Map();
29445
+ for (let l = 0; l <= maxLayer; l++) {
29446
+ const x = margin + l * (width - 2 * margin) / Math.max(1, maxLayer);
29447
+ const ordered2 = orderByParentPositionThenInput(layerGroups[l], adjacency, yById, inputIndex);
29448
+ const ys = distributeAxis(ordered2.length, margin, height - margin);
29449
+ ordered2.forEach((id, i) => {
29450
+ positions.set(id, { id, x, y: ys[i] });
29451
+ yById.set(id, ys[i]);
29452
+ });
29453
+ }
29454
+ return nodeIds.map((id) => positions.get(id));
29455
+ }
29456
+ function layoutTree(nodeIds, adjacency, roots, width, height, margin) {
29457
+ const effectiveRoots = roots.length > 0 ? roots : [nodeIds[0]];
29458
+ const layers = assignLayers(nodeIds, adjacency, effectiveRoots);
29459
+ const maxLayer = Math.max(...Array.from(layers.values()));
29460
+ const visitOrder = computeVisitOrder(nodeIds, adjacency, effectiveRoots);
29461
+ const layerGroups = groupByTier(nodeIds, layers, maxLayer);
29462
+ const positions = /* @__PURE__ */ new Map();
29463
+ for (let l = 0; l <= maxLayer; l++) {
29464
+ const ordered2 = [...layerGroups[l]].sort(
29465
+ (a, b) => (visitOrder.get(a) ?? 0) - (visitOrder.get(b) ?? 0)
29466
+ );
29467
+ const y = margin + l * (height - 2 * margin) / Math.max(1, maxLayer);
29468
+ const xs = distributeAxis(ordered2.length, margin, width - margin);
29469
+ ordered2.forEach((id, i) => positions.set(id, { id, x: xs[i], y }));
29470
+ }
29471
+ return nodeIds.map((id) => positions.get(id));
29472
+ }
29473
+ function layoutRadial(nodeIds, adjacency, roots, width, height, margin) {
29474
+ const cx = width / 2;
29475
+ const cy = height / 2;
29476
+ const maxRadius = Math.min(width, height) / 2 - margin;
29477
+ if (roots.length === 0) {
29478
+ const order = edgeWalkOrder(nodeIds, adjacency);
29479
+ const k = order.length;
29480
+ const positions2 = /* @__PURE__ */ new Map();
29481
+ order.forEach((id, i) => {
29482
+ const angle = i / k * 2 * Math.PI;
29483
+ positions2.set(id, { id, x: cx + maxRadius * Math.cos(angle), y: cy + maxRadius * Math.sin(angle) });
29484
+ });
29485
+ return nodeIds.map((id) => positions2.get(id));
29486
+ }
29487
+ const { depth, visitOrder } = bfsDepthAndOrder(nodeIds, adjacency, roots);
29488
+ const maxDepth = Math.max(...Array.from(depth.values()));
29489
+ const ringGroups = groupByTier(nodeIds, depth, maxDepth);
29490
+ const positions = /* @__PURE__ */ new Map();
29491
+ for (let d = 0; d <= maxDepth; d++) {
29492
+ const ordered2 = [...ringGroups[d]].sort(
29493
+ (a, b) => (visitOrder.get(a) ?? 0) - (visitOrder.get(b) ?? 0)
29494
+ );
29495
+ const radius = d * maxRadius / Math.max(1, maxDepth);
29496
+ const k = ordered2.length;
29497
+ ordered2.forEach((id, i) => {
29498
+ const angle = i / k * 2 * Math.PI;
29499
+ positions.set(id, { id, x: cx + radius * Math.cos(angle), y: cy + radius * Math.sin(angle) });
29500
+ });
29501
+ }
29502
+ return nodeIds.map((id) => positions.get(id));
29503
+ }
29504
+ function computeStaticLayout(mode, input) {
29505
+ const { nodeIds, edges, width, height } = input;
29506
+ const margin = input.margin ?? 40;
29507
+ if (nodeIds.length === 0) return [];
29508
+ if (nodeIds.length === 1) return [{ id: nodeIds[0], x: width / 2, y: height / 2 }];
29509
+ const adjacency = buildAdjacency(nodeIds, edges);
29510
+ const roots = findRoots(nodeIds, adjacency);
29511
+ if (mode === "flow") return layoutFlow(nodeIds, adjacency, roots, width, height, margin);
29512
+ if (mode === "tree") return layoutTree(nodeIds, adjacency, roots, width, height, margin);
29513
+ return layoutRadial(nodeIds, adjacency, roots, width, height, margin);
29514
+ }
29515
+ var init_graphViewLayouts = __esm({
29516
+ "lib/graphViewLayouts.ts"() {
29517
+ }
29518
+ });
29225
29519
  function resolveNodeColor(node, groups) {
29226
29520
  if (node.color) return node.color;
29227
29521
  if (node.group) {
@@ -29236,6 +29530,7 @@ var init_GraphView = __esm({
29236
29530
  "use client";
29237
29531
  init_cn();
29238
29532
  init_atoms();
29533
+ init_graphViewLayouts();
29239
29534
  GROUP_COLORS = [
29240
29535
  "#3b82f6",
29241
29536
  // blue-500
@@ -29266,11 +29561,13 @@ var init_GraphView = __esm({
29266
29561
  height: propHeight,
29267
29562
  className,
29268
29563
  showLabels = true,
29269
- zoomToFit = true
29564
+ zoomToFit = true,
29565
+ layout = "force"
29270
29566
  }) => {
29271
29567
  const { t } = useTranslate();
29272
29568
  const containerRef = useRef(null);
29273
29569
  const animRef = useRef(0);
29570
+ const arrowMarkerId = useId();
29274
29571
  const [simNodes, setSimNodes] = useState([]);
29275
29572
  const [settled, setSettled] = useState(false);
29276
29573
  const [hoveredId, setHoveredId] = useState(null);
@@ -29327,6 +29624,22 @@ var init_GraphView = __esm({
29327
29624
  fy: 0
29328
29625
  };
29329
29626
  });
29627
+ if (layout !== "force") {
29628
+ const points = computeStaticLayout(layout, {
29629
+ nodeIds: nodes.map((n) => n.id),
29630
+ edges,
29631
+ width: w,
29632
+ height: h
29633
+ });
29634
+ const pointById = new Map(points.map((p) => [p.id, p]));
29635
+ const laidOut = initialNodes.map((node) => {
29636
+ const point = pointById.get(node.id);
29637
+ return point ? { ...node, x: point.x, y: point.y } : node;
29638
+ });
29639
+ setSimNodes(laidOut);
29640
+ setSettled(true);
29641
+ return;
29642
+ }
29330
29643
  let iterations = 0;
29331
29644
  const maxIterations = 120;
29332
29645
  let currentNodes = initialNodes;
@@ -29395,7 +29708,7 @@ var init_GraphView = __esm({
29395
29708
  return () => {
29396
29709
  cancelAnimationFrame(animRef.current);
29397
29710
  };
29398
- }, [nodes, edges, w, h, groups]);
29711
+ }, [nodes, edges, w, h, groups, layout]);
29399
29712
  const viewBox = useMemo(() => {
29400
29713
  if (!zoomToFit || !settled || simNodes.length === 0) {
29401
29714
  return `0 0 ${w} ${h}`;
@@ -29470,6 +29783,19 @@ var init_GraphView = __esm({
29470
29783
  viewBox,
29471
29784
  preserveAspectRatio: "xMidYMid meet",
29472
29785
  children: [
29786
+ layout !== "force" && /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx(
29787
+ "marker",
29788
+ {
29789
+ id: arrowMarkerId,
29790
+ viewBox: "0 0 10 10",
29791
+ refX: "9",
29792
+ refY: "5",
29793
+ markerWidth: "6",
29794
+ markerHeight: "6",
29795
+ orient: "auto-start-reverse",
29796
+ children: /* @__PURE__ */ jsx("path", { d: "M0,0 L10,5 L0,10 z", fill: "currentColor" })
29797
+ }
29798
+ ) }),
29473
29799
  edges.map((edge, idx) => {
29474
29800
  const source = nodeMap.get(edge.source);
29475
29801
  const target = nodeMap.get(edge.target);
@@ -29484,8 +29810,10 @@ var init_GraphView = __esm({
29484
29810
  x2: target.x,
29485
29811
  y2: target.y,
29486
29812
  stroke: edge.color ?? DEFAULT_EDGE_COLOR,
29813
+ color: edge.color ?? DEFAULT_EDGE_COLOR,
29487
29814
  strokeWidth: 1.5,
29488
- opacity: isHighlighted ? 0.8 : 0.15
29815
+ opacity: isHighlighted ? 0.8 : 0.15,
29816
+ markerEnd: layout !== "force" ? `url(#${arrowMarkerId})` : void 0
29489
29817
  }
29490
29818
  ),
29491
29819
  showLabels && edge.label && /* @__PURE__ */ jsx(
@@ -39276,7 +39604,7 @@ function parseLessonSegments(lesson) {
39276
39604
  content = content.replace(connectResult.fullMatch, "").trim();
39277
39605
  }
39278
39606
  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*\\/?>)',
39607
+ '(?<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
39608
  "gi"
39281
39609
  );
39282
39610
  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