@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.
@@ -26299,7 +26299,12 @@ function daysAgo(n) {
26299
26299
  d.setDate(d.getDate() - n);
26300
26300
  return d;
26301
26301
  }
26302
- var DEFAULT_PRESETS; exports.DateRangePicker = void 0;
26302
+ function resolvePresetRange(preset) {
26303
+ if (typeof preset.range === "function") return preset.range();
26304
+ if (preset.range) return preset.range;
26305
+ return TOKEN_RANGES[preset.value]?.() ?? null;
26306
+ }
26307
+ var TOKEN_RANGES, DEFAULT_PRESETS; exports.DateRangePicker = void 0;
26303
26308
  var init_DateRangePicker = __esm({
26304
26309
  "components/core/molecules/DateRangePicker.tsx"() {
26305
26310
  "use client";
@@ -26309,32 +26314,19 @@ var init_DateRangePicker = __esm({
26309
26314
  init_Stack();
26310
26315
  init_Typography();
26311
26316
  init_useEventBus();
26317
+ TOKEN_RANGES = {
26318
+ "7d": () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) }),
26319
+ "30d": () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) }),
26320
+ month: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) }),
26321
+ quarter: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) }),
26322
+ ytd: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
26323
+ };
26312
26324
  DEFAULT_PRESETS = [
26313
- {
26314
- label: "Last 7 days",
26315
- value: "7d",
26316
- range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
26317
- },
26318
- {
26319
- label: "Last 30 days",
26320
- value: "30d",
26321
- range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
26322
- },
26323
- {
26324
- label: "This Month",
26325
- value: "month",
26326
- range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
26327
- },
26328
- {
26329
- label: "This Quarter",
26330
- value: "quarter",
26331
- range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
26332
- },
26333
- {
26334
- label: "YTD",
26335
- value: "ytd",
26336
- range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
26337
- }
26325
+ { label: "Last 7 days", value: "7d" },
26326
+ { label: "Last 30 days", value: "30d" },
26327
+ { label: "This Month", value: "month" },
26328
+ { label: "This Quarter", value: "quarter" },
26329
+ { label: "YTD", value: "ytd" }
26338
26330
  ];
26339
26331
  exports.DateRangePicker = ({
26340
26332
  from: fromProp,
@@ -26375,7 +26367,8 @@ var init_DateRangePicker = __esm({
26375
26367
  );
26376
26368
  const handlePreset = React77.useCallback(
26377
26369
  (preset) => {
26378
- const range = preset.range();
26370
+ const range = resolvePresetRange(preset);
26371
+ if (range === null) return;
26379
26372
  setFrom(range.from);
26380
26373
  setTo(range.to);
26381
26374
  setActivePreset(preset.value);
@@ -26383,8 +26376,12 @@ var init_DateRangePicker = __esm({
26383
26376
  },
26384
26377
  [emit]
26385
26378
  );
26379
+ const renderablePresets = React77.useMemo(
26380
+ () => presets.filter((p) => p.range !== void 0 || TOKEN_RANGES[p.value] !== void 0),
26381
+ [presets]
26382
+ );
26386
26383
  const presetButtons = React77.useMemo(
26387
- () => presets.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
26384
+ () => renderablePresets.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
26388
26385
  exports.Button,
26389
26386
  {
26390
26387
  variant: activePreset === preset.value ? "primary" : "ghost",
@@ -26394,7 +26391,7 @@ var init_DateRangePicker = __esm({
26394
26391
  },
26395
26392
  preset.value
26396
26393
  )),
26397
- [presets, activePreset, handlePreset]
26394
+ [renderablePresets, activePreset, handlePreset]
26398
26395
  );
26399
26396
  return /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "sm", className: cn(className), children: [
26400
26397
  /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "md", align: "end", children: [
@@ -26421,7 +26418,7 @@ var init_DateRangePicker = __esm({
26421
26418
  )
26422
26419
  ] })
26423
26420
  ] }),
26424
- presets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: "xs", wrap: true, children: presetButtons })
26421
+ renderablePresets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: "xs", wrap: true, children: presetButtons })
26425
26422
  ] });
26426
26423
  };
26427
26424
  exports.DateRangePicker.displayName = "DateRangePicker";
@@ -29297,6 +29294,208 @@ var init_PhysicsCanvas = __esm({
29297
29294
  };
29298
29295
  }
29299
29296
  });
29297
+
29298
+ // lib/graphViewLayouts.ts
29299
+ function buildAdjacency(nodeIds, edges) {
29300
+ const known = new Set(nodeIds);
29301
+ const out = /* @__PURE__ */ new Map();
29302
+ const inMap = /* @__PURE__ */ new Map();
29303
+ for (const id of nodeIds) {
29304
+ out.set(id, []);
29305
+ inMap.set(id, []);
29306
+ }
29307
+ for (const edge of edges) {
29308
+ if (!known.has(edge.source) || !known.has(edge.target)) continue;
29309
+ out.get(edge.source)?.push(edge.target);
29310
+ inMap.get(edge.target)?.push(edge.source);
29311
+ }
29312
+ return { out, in: inMap };
29313
+ }
29314
+ function findRoots(nodeIds, adjacency) {
29315
+ return nodeIds.filter((id) => (adjacency.in.get(id)?.length ?? 0) === 0);
29316
+ }
29317
+ function assignLayers(nodeIds, adjacency, roots) {
29318
+ const layer = new Map(nodeIds.map((id) => [id, 0]));
29319
+ const onStack = /* @__PURE__ */ new Set();
29320
+ const visit = (id) => {
29321
+ onStack.add(id);
29322
+ const currentLayer = layer.get(id) ?? 0;
29323
+ for (const next of adjacency.out.get(id) ?? []) {
29324
+ if (onStack.has(next)) continue;
29325
+ const candidate = currentLayer + 1;
29326
+ if (candidate > (layer.get(next) ?? 0)) {
29327
+ layer.set(next, candidate);
29328
+ }
29329
+ visit(next);
29330
+ }
29331
+ onStack.delete(id);
29332
+ };
29333
+ for (const root of roots) visit(root);
29334
+ return layer;
29335
+ }
29336
+ function computeVisitOrder(nodeIds, adjacency, roots) {
29337
+ const order = /* @__PURE__ */ new Map();
29338
+ const visited = /* @__PURE__ */ new Set();
29339
+ let counter = 0;
29340
+ const visit = (id) => {
29341
+ if (visited.has(id)) return;
29342
+ visited.add(id);
29343
+ order.set(id, counter++);
29344
+ for (const next of adjacency.out.get(id) ?? []) visit(next);
29345
+ };
29346
+ for (const root of roots) visit(root);
29347
+ for (const id of nodeIds) {
29348
+ if (!visited.has(id)) order.set(id, counter++);
29349
+ }
29350
+ return order;
29351
+ }
29352
+ function bfsDepthAndOrder(nodeIds, adjacency, roots) {
29353
+ const depth = new Map(nodeIds.map((id) => [id, 0]));
29354
+ const visitOrder = /* @__PURE__ */ new Map();
29355
+ const visited = /* @__PURE__ */ new Set();
29356
+ const queue = [];
29357
+ let counter = 0;
29358
+ for (const root of roots) {
29359
+ if (visited.has(root)) continue;
29360
+ visited.add(root);
29361
+ depth.set(root, 0);
29362
+ visitOrder.set(root, counter++);
29363
+ queue.push(root);
29364
+ }
29365
+ let head = 0;
29366
+ while (head < queue.length) {
29367
+ const id = queue[head++];
29368
+ const d = depth.get(id) ?? 0;
29369
+ for (const next of adjacency.out.get(id) ?? []) {
29370
+ if (visited.has(next)) continue;
29371
+ visited.add(next);
29372
+ depth.set(next, d + 1);
29373
+ visitOrder.set(next, counter++);
29374
+ queue.push(next);
29375
+ }
29376
+ }
29377
+ for (const id of nodeIds) {
29378
+ if (!visited.has(id)) visitOrder.set(id, counter++);
29379
+ }
29380
+ return { depth, visitOrder };
29381
+ }
29382
+ function edgeWalkOrder(nodeIds, adjacency) {
29383
+ const visited = /* @__PURE__ */ new Set();
29384
+ const result = [];
29385
+ for (const start of nodeIds) {
29386
+ if (visited.has(start)) continue;
29387
+ let current = start;
29388
+ while (current !== void 0 && !visited.has(current)) {
29389
+ visited.add(current);
29390
+ result.push(current);
29391
+ const outs = adjacency.out.get(current) ?? [];
29392
+ current = outs.find((next) => !visited.has(next));
29393
+ }
29394
+ }
29395
+ return result;
29396
+ }
29397
+ function groupByTier(nodeIds, tierOf, maxTier) {
29398
+ const groups = Array.from({ length: maxTier + 1 }, () => []);
29399
+ for (const id of nodeIds) {
29400
+ groups[tierOf.get(id) ?? 0].push(id);
29401
+ }
29402
+ return groups;
29403
+ }
29404
+ function distributeAxis(count, start, end) {
29405
+ if (count <= 0) return [];
29406
+ const slot = (end - start) / count;
29407
+ return Array.from({ length: count }, (_, i) => start + slot * (i + 0.5));
29408
+ }
29409
+ function orderByParentPositionThenInput(group, adjacency, positioned, inputIndex) {
29410
+ const withKey = group.map((id) => {
29411
+ const parentValues = (adjacency.in.get(id) ?? []).map((p) => positioned.get(p)).filter((v) => v !== void 0);
29412
+ const avg = parentValues.length > 0 ? parentValues.reduce((a, b) => a + b, 0) / parentValues.length : Number.POSITIVE_INFINITY;
29413
+ return { id, avg, idx: inputIndex.get(id) ?? 0 };
29414
+ });
29415
+ withKey.sort((a, b) => a.avg !== b.avg ? a.avg - b.avg : a.idx - b.idx);
29416
+ return withKey.map((k) => k.id);
29417
+ }
29418
+ function layoutFlow(nodeIds, adjacency, roots, width, height, margin) {
29419
+ const inputIndex = new Map(nodeIds.map((id, i) => [id, i]));
29420
+ const layers = assignLayers(nodeIds, adjacency, roots);
29421
+ const maxLayer = Math.max(...Array.from(layers.values()));
29422
+ const layerGroups = groupByTier(nodeIds, layers, maxLayer);
29423
+ const positions = /* @__PURE__ */ new Map();
29424
+ const yById = /* @__PURE__ */ new Map();
29425
+ for (let l = 0; l <= maxLayer; l++) {
29426
+ const x = margin + l * (width - 2 * margin) / Math.max(1, maxLayer);
29427
+ const ordered2 = orderByParentPositionThenInput(layerGroups[l], adjacency, yById, inputIndex);
29428
+ const ys = distributeAxis(ordered2.length, margin, height - margin);
29429
+ ordered2.forEach((id, i) => {
29430
+ positions.set(id, { id, x, y: ys[i] });
29431
+ yById.set(id, ys[i]);
29432
+ });
29433
+ }
29434
+ return nodeIds.map((id) => positions.get(id));
29435
+ }
29436
+ function layoutTree(nodeIds, adjacency, roots, width, height, margin) {
29437
+ const effectiveRoots = roots.length > 0 ? roots : [nodeIds[0]];
29438
+ const layers = assignLayers(nodeIds, adjacency, effectiveRoots);
29439
+ const maxLayer = Math.max(...Array.from(layers.values()));
29440
+ const visitOrder = computeVisitOrder(nodeIds, adjacency, effectiveRoots);
29441
+ const layerGroups = groupByTier(nodeIds, layers, maxLayer);
29442
+ const positions = /* @__PURE__ */ new Map();
29443
+ for (let l = 0; l <= maxLayer; l++) {
29444
+ const ordered2 = [...layerGroups[l]].sort(
29445
+ (a, b) => (visitOrder.get(a) ?? 0) - (visitOrder.get(b) ?? 0)
29446
+ );
29447
+ const y = margin + l * (height - 2 * margin) / Math.max(1, maxLayer);
29448
+ const xs = distributeAxis(ordered2.length, margin, width - margin);
29449
+ ordered2.forEach((id, i) => positions.set(id, { id, x: xs[i], y }));
29450
+ }
29451
+ return nodeIds.map((id) => positions.get(id));
29452
+ }
29453
+ function layoutRadial(nodeIds, adjacency, roots, width, height, margin) {
29454
+ const cx = width / 2;
29455
+ const cy = height / 2;
29456
+ const maxRadius = Math.min(width, height) / 2 - margin;
29457
+ if (roots.length === 0) {
29458
+ const order = edgeWalkOrder(nodeIds, adjacency);
29459
+ const k = order.length;
29460
+ const positions2 = /* @__PURE__ */ new Map();
29461
+ order.forEach((id, i) => {
29462
+ const angle = i / k * 2 * Math.PI;
29463
+ positions2.set(id, { id, x: cx + maxRadius * Math.cos(angle), y: cy + maxRadius * Math.sin(angle) });
29464
+ });
29465
+ return nodeIds.map((id) => positions2.get(id));
29466
+ }
29467
+ const { depth, visitOrder } = bfsDepthAndOrder(nodeIds, adjacency, roots);
29468
+ const maxDepth = Math.max(...Array.from(depth.values()));
29469
+ const ringGroups = groupByTier(nodeIds, depth, maxDepth);
29470
+ const positions = /* @__PURE__ */ new Map();
29471
+ for (let d = 0; d <= maxDepth; d++) {
29472
+ const ordered2 = [...ringGroups[d]].sort(
29473
+ (a, b) => (visitOrder.get(a) ?? 0) - (visitOrder.get(b) ?? 0)
29474
+ );
29475
+ const radius = d * maxRadius / Math.max(1, maxDepth);
29476
+ const k = ordered2.length;
29477
+ ordered2.forEach((id, i) => {
29478
+ const angle = i / k * 2 * Math.PI;
29479
+ positions.set(id, { id, x: cx + radius * Math.cos(angle), y: cy + radius * Math.sin(angle) });
29480
+ });
29481
+ }
29482
+ return nodeIds.map((id) => positions.get(id));
29483
+ }
29484
+ function computeStaticLayout(mode, input) {
29485
+ const { nodeIds, edges, width, height } = input;
29486
+ const margin = input.margin ?? 40;
29487
+ if (nodeIds.length === 0) return [];
29488
+ if (nodeIds.length === 1) return [{ id: nodeIds[0], x: width / 2, y: height / 2 }];
29489
+ const adjacency = buildAdjacency(nodeIds, edges);
29490
+ const roots = findRoots(nodeIds, adjacency);
29491
+ if (mode === "flow") return layoutFlow(nodeIds, adjacency, roots, width, height, margin);
29492
+ if (mode === "tree") return layoutTree(nodeIds, adjacency, roots, width, height, margin);
29493
+ return layoutRadial(nodeIds, adjacency, roots, width, height, margin);
29494
+ }
29495
+ var init_graphViewLayouts = __esm({
29496
+ "lib/graphViewLayouts.ts"() {
29497
+ }
29498
+ });
29300
29499
  function resolveNodeColor(node, groups) {
29301
29500
  if (node.color) return node.color;
29302
29501
  if (node.group) {
@@ -29311,6 +29510,7 @@ var init_GraphView = __esm({
29311
29510
  "use client";
29312
29511
  init_cn();
29313
29512
  init_atoms();
29513
+ init_graphViewLayouts();
29314
29514
  GROUP_COLORS = [
29315
29515
  "#3b82f6",
29316
29516
  // blue-500
@@ -29341,11 +29541,13 @@ var init_GraphView = __esm({
29341
29541
  height: propHeight,
29342
29542
  className,
29343
29543
  showLabels = true,
29344
- zoomToFit = true
29544
+ zoomToFit = true,
29545
+ layout = "force"
29345
29546
  }) => {
29346
29547
  const { t } = hooks.useTranslate();
29347
29548
  const containerRef = React77.useRef(null);
29348
29549
  const animRef = React77.useRef(0);
29550
+ const arrowMarkerId = React77.useId();
29349
29551
  const [simNodes, setSimNodes] = React77.useState([]);
29350
29552
  const [settled, setSettled] = React77.useState(false);
29351
29553
  const [hoveredId, setHoveredId] = React77.useState(null);
@@ -29402,6 +29604,22 @@ var init_GraphView = __esm({
29402
29604
  fy: 0
29403
29605
  };
29404
29606
  });
29607
+ if (layout !== "force") {
29608
+ const points = computeStaticLayout(layout, {
29609
+ nodeIds: nodes.map((n) => n.id),
29610
+ edges,
29611
+ width: w,
29612
+ height: h
29613
+ });
29614
+ const pointById = new Map(points.map((p) => [p.id, p]));
29615
+ const laidOut = initialNodes.map((node) => {
29616
+ const point = pointById.get(node.id);
29617
+ return point ? { ...node, x: point.x, y: point.y } : node;
29618
+ });
29619
+ setSimNodes(laidOut);
29620
+ setSettled(true);
29621
+ return;
29622
+ }
29405
29623
  let iterations = 0;
29406
29624
  const maxIterations = 120;
29407
29625
  let currentNodes = initialNodes;
@@ -29470,7 +29688,7 @@ var init_GraphView = __esm({
29470
29688
  return () => {
29471
29689
  cancelAnimationFrame(animRef.current);
29472
29690
  };
29473
- }, [nodes, edges, w, h, groups]);
29691
+ }, [nodes, edges, w, h, groups, layout]);
29474
29692
  const viewBox = React77.useMemo(() => {
29475
29693
  if (!zoomToFit || !settled || simNodes.length === 0) {
29476
29694
  return `0 0 ${w} ${h}`;
@@ -29545,6 +29763,19 @@ var init_GraphView = __esm({
29545
29763
  viewBox,
29546
29764
  preserveAspectRatio: "xMidYMid meet",
29547
29765
  children: [
29766
+ layout !== "force" && /* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsx(
29767
+ "marker",
29768
+ {
29769
+ id: arrowMarkerId,
29770
+ viewBox: "0 0 10 10",
29771
+ refX: "9",
29772
+ refY: "5",
29773
+ markerWidth: "6",
29774
+ markerHeight: "6",
29775
+ orient: "auto-start-reverse",
29776
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M0,0 L10,5 L0,10 z", fill: "currentColor" })
29777
+ }
29778
+ ) }),
29548
29779
  edges.map((edge, idx) => {
29549
29780
  const source = nodeMap.get(edge.source);
29550
29781
  const target = nodeMap.get(edge.target);
@@ -29559,8 +29790,10 @@ var init_GraphView = __esm({
29559
29790
  x2: target.x,
29560
29791
  y2: target.y,
29561
29792
  stroke: edge.color ?? DEFAULT_EDGE_COLOR,
29793
+ color: edge.color ?? DEFAULT_EDGE_COLOR,
29562
29794
  strokeWidth: 1.5,
29563
- opacity: isHighlighted ? 0.8 : 0.15
29795
+ opacity: isHighlighted ? 0.8 : 0.15,
29796
+ markerEnd: layout !== "force" ? `url(#${arrowMarkerId})` : void 0
29564
29797
  }
29565
29798
  ),
29566
29799
  showLabels && edge.label && /* @__PURE__ */ jsxRuntime.jsx(
@@ -39351,7 +39584,7 @@ function parseLessonSegments(lesson) {
39351
39584
  content = content.replace(connectResult.fullMatch, "").trim();
39352
39585
  }
39353
39586
  const tagRegex = new RegExp(
39354
- '(?<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*\\/?>)',
39587
+ '(?<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*\\/?>)',
39355
39588
  "gi"
39356
39589
  );
39357
39590
  let lastIndex = 0;