@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.
@@ -27624,7 +27624,12 @@ function daysAgo(n) {
27624
27624
  d.setDate(d.getDate() - n);
27625
27625
  return d;
27626
27626
  }
27627
- var DEFAULT_PRESETS, DateRangePicker;
27627
+ function resolvePresetRange(preset) {
27628
+ if (typeof preset.range === "function") return preset.range();
27629
+ if (preset.range) return preset.range;
27630
+ return TOKEN_RANGES[preset.value]?.() ?? null;
27631
+ }
27632
+ var TOKEN_RANGES, DEFAULT_PRESETS, DateRangePicker;
27628
27633
  var init_DateRangePicker = __esm({
27629
27634
  "components/core/molecules/DateRangePicker.tsx"() {
27630
27635
  "use client";
@@ -27634,32 +27639,19 @@ var init_DateRangePicker = __esm({
27634
27639
  init_Stack();
27635
27640
  init_Typography();
27636
27641
  init_useEventBus();
27642
+ TOKEN_RANGES = {
27643
+ "7d": () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) }),
27644
+ "30d": () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) }),
27645
+ month: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) }),
27646
+ quarter: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) }),
27647
+ ytd: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
27648
+ };
27637
27649
  DEFAULT_PRESETS = [
27638
- {
27639
- label: "Last 7 days",
27640
- value: "7d",
27641
- range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
27642
- },
27643
- {
27644
- label: "Last 30 days",
27645
- value: "30d",
27646
- range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
27647
- },
27648
- {
27649
- label: "This Month",
27650
- value: "month",
27651
- range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
27652
- },
27653
- {
27654
- label: "This Quarter",
27655
- value: "quarter",
27656
- range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
27657
- },
27658
- {
27659
- label: "YTD",
27660
- value: "ytd",
27661
- range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
27662
- }
27650
+ { label: "Last 7 days", value: "7d" },
27651
+ { label: "Last 30 days", value: "30d" },
27652
+ { label: "This Month", value: "month" },
27653
+ { label: "This Quarter", value: "quarter" },
27654
+ { label: "YTD", value: "ytd" }
27663
27655
  ];
27664
27656
  DateRangePicker = ({
27665
27657
  from: fromProp,
@@ -27700,7 +27692,8 @@ var init_DateRangePicker = __esm({
27700
27692
  );
27701
27693
  const handlePreset = useCallback(
27702
27694
  (preset) => {
27703
- const range = preset.range();
27695
+ const range = resolvePresetRange(preset);
27696
+ if (range === null) return;
27704
27697
  setFrom(range.from);
27705
27698
  setTo(range.to);
27706
27699
  setActivePreset(preset.value);
@@ -27708,8 +27701,12 @@ var init_DateRangePicker = __esm({
27708
27701
  },
27709
27702
  [emit]
27710
27703
  );
27704
+ const renderablePresets = useMemo(
27705
+ () => presets.filter((p) => p.range !== void 0 || TOKEN_RANGES[p.value] !== void 0),
27706
+ [presets]
27707
+ );
27711
27708
  const presetButtons = useMemo(
27712
- () => presets.map((preset) => /* @__PURE__ */ jsx(
27709
+ () => renderablePresets.map((preset) => /* @__PURE__ */ jsx(
27713
27710
  Button,
27714
27711
  {
27715
27712
  variant: activePreset === preset.value ? "primary" : "ghost",
@@ -27719,7 +27716,7 @@ var init_DateRangePicker = __esm({
27719
27716
  },
27720
27717
  preset.value
27721
27718
  )),
27722
- [presets, activePreset, handlePreset]
27719
+ [renderablePresets, activePreset, handlePreset]
27723
27720
  );
27724
27721
  return /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: cn(className), children: [
27725
27722
  /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "end", children: [
@@ -27746,7 +27743,7 @@ var init_DateRangePicker = __esm({
27746
27743
  )
27747
27744
  ] })
27748
27745
  ] }),
27749
- presets.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
27746
+ renderablePresets.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
27750
27747
  ] });
27751
27748
  };
27752
27749
  DateRangePicker.displayName = "DateRangePicker";
@@ -28188,6 +28185,208 @@ var init_PhysicsCanvas = __esm({
28188
28185
  };
28189
28186
  }
28190
28187
  });
28188
+
28189
+ // lib/graphViewLayouts.ts
28190
+ function buildAdjacency(nodeIds, edges) {
28191
+ const known = new Set(nodeIds);
28192
+ const out = /* @__PURE__ */ new Map();
28193
+ const inMap = /* @__PURE__ */ new Map();
28194
+ for (const id of nodeIds) {
28195
+ out.set(id, []);
28196
+ inMap.set(id, []);
28197
+ }
28198
+ for (const edge of edges) {
28199
+ if (!known.has(edge.source) || !known.has(edge.target)) continue;
28200
+ out.get(edge.source)?.push(edge.target);
28201
+ inMap.get(edge.target)?.push(edge.source);
28202
+ }
28203
+ return { out, in: inMap };
28204
+ }
28205
+ function findRoots(nodeIds, adjacency) {
28206
+ return nodeIds.filter((id) => (adjacency.in.get(id)?.length ?? 0) === 0);
28207
+ }
28208
+ function assignLayers(nodeIds, adjacency, roots) {
28209
+ const layer = new Map(nodeIds.map((id) => [id, 0]));
28210
+ const onStack = /* @__PURE__ */ new Set();
28211
+ const visit = (id) => {
28212
+ onStack.add(id);
28213
+ const currentLayer = layer.get(id) ?? 0;
28214
+ for (const next of adjacency.out.get(id) ?? []) {
28215
+ if (onStack.has(next)) continue;
28216
+ const candidate = currentLayer + 1;
28217
+ if (candidate > (layer.get(next) ?? 0)) {
28218
+ layer.set(next, candidate);
28219
+ }
28220
+ visit(next);
28221
+ }
28222
+ onStack.delete(id);
28223
+ };
28224
+ for (const root of roots) visit(root);
28225
+ return layer;
28226
+ }
28227
+ function computeVisitOrder(nodeIds, adjacency, roots) {
28228
+ const order = /* @__PURE__ */ new Map();
28229
+ const visited = /* @__PURE__ */ new Set();
28230
+ let counter = 0;
28231
+ const visit = (id) => {
28232
+ if (visited.has(id)) return;
28233
+ visited.add(id);
28234
+ order.set(id, counter++);
28235
+ for (const next of adjacency.out.get(id) ?? []) visit(next);
28236
+ };
28237
+ for (const root of roots) visit(root);
28238
+ for (const id of nodeIds) {
28239
+ if (!visited.has(id)) order.set(id, counter++);
28240
+ }
28241
+ return order;
28242
+ }
28243
+ function bfsDepthAndOrder(nodeIds, adjacency, roots) {
28244
+ const depth = new Map(nodeIds.map((id) => [id, 0]));
28245
+ const visitOrder = /* @__PURE__ */ new Map();
28246
+ const visited = /* @__PURE__ */ new Set();
28247
+ const queue = [];
28248
+ let counter = 0;
28249
+ for (const root of roots) {
28250
+ if (visited.has(root)) continue;
28251
+ visited.add(root);
28252
+ depth.set(root, 0);
28253
+ visitOrder.set(root, counter++);
28254
+ queue.push(root);
28255
+ }
28256
+ let head = 0;
28257
+ while (head < queue.length) {
28258
+ const id = queue[head++];
28259
+ const d = depth.get(id) ?? 0;
28260
+ for (const next of adjacency.out.get(id) ?? []) {
28261
+ if (visited.has(next)) continue;
28262
+ visited.add(next);
28263
+ depth.set(next, d + 1);
28264
+ visitOrder.set(next, counter++);
28265
+ queue.push(next);
28266
+ }
28267
+ }
28268
+ for (const id of nodeIds) {
28269
+ if (!visited.has(id)) visitOrder.set(id, counter++);
28270
+ }
28271
+ return { depth, visitOrder };
28272
+ }
28273
+ function edgeWalkOrder(nodeIds, adjacency) {
28274
+ const visited = /* @__PURE__ */ new Set();
28275
+ const result = [];
28276
+ for (const start of nodeIds) {
28277
+ if (visited.has(start)) continue;
28278
+ let current = start;
28279
+ while (current !== void 0 && !visited.has(current)) {
28280
+ visited.add(current);
28281
+ result.push(current);
28282
+ const outs = adjacency.out.get(current) ?? [];
28283
+ current = outs.find((next) => !visited.has(next));
28284
+ }
28285
+ }
28286
+ return result;
28287
+ }
28288
+ function groupByTier(nodeIds, tierOf, maxTier) {
28289
+ const groups = Array.from({ length: maxTier + 1 }, () => []);
28290
+ for (const id of nodeIds) {
28291
+ groups[tierOf.get(id) ?? 0].push(id);
28292
+ }
28293
+ return groups;
28294
+ }
28295
+ function distributeAxis(count, start, end) {
28296
+ if (count <= 0) return [];
28297
+ const slot = (end - start) / count;
28298
+ return Array.from({ length: count }, (_, i) => start + slot * (i + 0.5));
28299
+ }
28300
+ function orderByParentPositionThenInput(group, adjacency, positioned, inputIndex) {
28301
+ const withKey = group.map((id) => {
28302
+ const parentValues = (adjacency.in.get(id) ?? []).map((p) => positioned.get(p)).filter((v) => v !== void 0);
28303
+ const avg = parentValues.length > 0 ? parentValues.reduce((a, b) => a + b, 0) / parentValues.length : Number.POSITIVE_INFINITY;
28304
+ return { id, avg, idx: inputIndex.get(id) ?? 0 };
28305
+ });
28306
+ withKey.sort((a, b) => a.avg !== b.avg ? a.avg - b.avg : a.idx - b.idx);
28307
+ return withKey.map((k) => k.id);
28308
+ }
28309
+ function layoutFlow(nodeIds, adjacency, roots, width, height, margin) {
28310
+ const inputIndex = new Map(nodeIds.map((id, i) => [id, i]));
28311
+ const layers = assignLayers(nodeIds, adjacency, roots);
28312
+ const maxLayer = Math.max(...Array.from(layers.values()));
28313
+ const layerGroups = groupByTier(nodeIds, layers, maxLayer);
28314
+ const positions = /* @__PURE__ */ new Map();
28315
+ const yById = /* @__PURE__ */ new Map();
28316
+ for (let l = 0; l <= maxLayer; l++) {
28317
+ const x = margin + l * (width - 2 * margin) / Math.max(1, maxLayer);
28318
+ const ordered2 = orderByParentPositionThenInput(layerGroups[l], adjacency, yById, inputIndex);
28319
+ const ys = distributeAxis(ordered2.length, margin, height - margin);
28320
+ ordered2.forEach((id, i) => {
28321
+ positions.set(id, { id, x, y: ys[i] });
28322
+ yById.set(id, ys[i]);
28323
+ });
28324
+ }
28325
+ return nodeIds.map((id) => positions.get(id));
28326
+ }
28327
+ function layoutTree(nodeIds, adjacency, roots, width, height, margin) {
28328
+ const effectiveRoots = roots.length > 0 ? roots : [nodeIds[0]];
28329
+ const layers = assignLayers(nodeIds, adjacency, effectiveRoots);
28330
+ const maxLayer = Math.max(...Array.from(layers.values()));
28331
+ const visitOrder = computeVisitOrder(nodeIds, adjacency, effectiveRoots);
28332
+ const layerGroups = groupByTier(nodeIds, layers, maxLayer);
28333
+ const positions = /* @__PURE__ */ new Map();
28334
+ for (let l = 0; l <= maxLayer; l++) {
28335
+ const ordered2 = [...layerGroups[l]].sort(
28336
+ (a, b) => (visitOrder.get(a) ?? 0) - (visitOrder.get(b) ?? 0)
28337
+ );
28338
+ const y = margin + l * (height - 2 * margin) / Math.max(1, maxLayer);
28339
+ const xs = distributeAxis(ordered2.length, margin, width - margin);
28340
+ ordered2.forEach((id, i) => positions.set(id, { id, x: xs[i], y }));
28341
+ }
28342
+ return nodeIds.map((id) => positions.get(id));
28343
+ }
28344
+ function layoutRadial(nodeIds, adjacency, roots, width, height, margin) {
28345
+ const cx = width / 2;
28346
+ const cy = height / 2;
28347
+ const maxRadius = Math.min(width, height) / 2 - margin;
28348
+ if (roots.length === 0) {
28349
+ const order = edgeWalkOrder(nodeIds, adjacency);
28350
+ const k = order.length;
28351
+ const positions2 = /* @__PURE__ */ new Map();
28352
+ order.forEach((id, i) => {
28353
+ const angle = i / k * 2 * Math.PI;
28354
+ positions2.set(id, { id, x: cx + maxRadius * Math.cos(angle), y: cy + maxRadius * Math.sin(angle) });
28355
+ });
28356
+ return nodeIds.map((id) => positions2.get(id));
28357
+ }
28358
+ const { depth, visitOrder } = bfsDepthAndOrder(nodeIds, adjacency, roots);
28359
+ const maxDepth = Math.max(...Array.from(depth.values()));
28360
+ const ringGroups = groupByTier(nodeIds, depth, maxDepth);
28361
+ const positions = /* @__PURE__ */ new Map();
28362
+ for (let d = 0; d <= maxDepth; d++) {
28363
+ const ordered2 = [...ringGroups[d]].sort(
28364
+ (a, b) => (visitOrder.get(a) ?? 0) - (visitOrder.get(b) ?? 0)
28365
+ );
28366
+ const radius = d * maxRadius / Math.max(1, maxDepth);
28367
+ const k = ordered2.length;
28368
+ ordered2.forEach((id, i) => {
28369
+ const angle = i / k * 2 * Math.PI;
28370
+ positions.set(id, { id, x: cx + radius * Math.cos(angle), y: cy + radius * Math.sin(angle) });
28371
+ });
28372
+ }
28373
+ return nodeIds.map((id) => positions.get(id));
28374
+ }
28375
+ function computeStaticLayout(mode, input) {
28376
+ const { nodeIds, edges, width, height } = input;
28377
+ const margin = input.margin ?? 40;
28378
+ if (nodeIds.length === 0) return [];
28379
+ if (nodeIds.length === 1) return [{ id: nodeIds[0], x: width / 2, y: height / 2 }];
28380
+ const adjacency = buildAdjacency(nodeIds, edges);
28381
+ const roots = findRoots(nodeIds, adjacency);
28382
+ if (mode === "flow") return layoutFlow(nodeIds, adjacency, roots, width, height, margin);
28383
+ if (mode === "tree") return layoutTree(nodeIds, adjacency, roots, width, height, margin);
28384
+ return layoutRadial(nodeIds, adjacency, roots, width, height, margin);
28385
+ }
28386
+ var init_graphViewLayouts = __esm({
28387
+ "lib/graphViewLayouts.ts"() {
28388
+ }
28389
+ });
28191
28390
  function resolveNodeColor(node, groups) {
28192
28391
  if (node.color) return node.color;
28193
28392
  if (node.group) {
@@ -28202,6 +28401,7 @@ var init_GraphView = __esm({
28202
28401
  "use client";
28203
28402
  init_cn();
28204
28403
  init_atoms();
28404
+ init_graphViewLayouts();
28205
28405
  GROUP_COLORS = [
28206
28406
  "#3b82f6",
28207
28407
  // blue-500
@@ -28232,11 +28432,13 @@ var init_GraphView = __esm({
28232
28432
  height: propHeight,
28233
28433
  className,
28234
28434
  showLabels = true,
28235
- zoomToFit = true
28435
+ zoomToFit = true,
28436
+ layout = "force"
28236
28437
  }) => {
28237
28438
  const { t } = useTranslate();
28238
28439
  const containerRef = useRef(null);
28239
28440
  const animRef = useRef(0);
28441
+ const arrowMarkerId = useId();
28240
28442
  const [simNodes, setSimNodes] = useState([]);
28241
28443
  const [settled, setSettled] = useState(false);
28242
28444
  const [hoveredId, setHoveredId] = useState(null);
@@ -28293,6 +28495,22 @@ var init_GraphView = __esm({
28293
28495
  fy: 0
28294
28496
  };
28295
28497
  });
28498
+ if (layout !== "force") {
28499
+ const points = computeStaticLayout(layout, {
28500
+ nodeIds: nodes.map((n) => n.id),
28501
+ edges,
28502
+ width: w,
28503
+ height: h
28504
+ });
28505
+ const pointById = new Map(points.map((p) => [p.id, p]));
28506
+ const laidOut = initialNodes.map((node) => {
28507
+ const point = pointById.get(node.id);
28508
+ return point ? { ...node, x: point.x, y: point.y } : node;
28509
+ });
28510
+ setSimNodes(laidOut);
28511
+ setSettled(true);
28512
+ return;
28513
+ }
28296
28514
  let iterations = 0;
28297
28515
  const maxIterations = 120;
28298
28516
  let currentNodes = initialNodes;
@@ -28361,7 +28579,7 @@ var init_GraphView = __esm({
28361
28579
  return () => {
28362
28580
  cancelAnimationFrame(animRef.current);
28363
28581
  };
28364
- }, [nodes, edges, w, h, groups]);
28582
+ }, [nodes, edges, w, h, groups, layout]);
28365
28583
  const viewBox = useMemo(() => {
28366
28584
  if (!zoomToFit || !settled || simNodes.length === 0) {
28367
28585
  return `0 0 ${w} ${h}`;
@@ -28436,6 +28654,19 @@ var init_GraphView = __esm({
28436
28654
  viewBox,
28437
28655
  preserveAspectRatio: "xMidYMid meet",
28438
28656
  children: [
28657
+ layout !== "force" && /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx(
28658
+ "marker",
28659
+ {
28660
+ id: arrowMarkerId,
28661
+ viewBox: "0 0 10 10",
28662
+ refX: "9",
28663
+ refY: "5",
28664
+ markerWidth: "6",
28665
+ markerHeight: "6",
28666
+ orient: "auto-start-reverse",
28667
+ children: /* @__PURE__ */ jsx("path", { d: "M0,0 L10,5 L0,10 z", fill: "currentColor" })
28668
+ }
28669
+ ) }),
28439
28670
  edges.map((edge, idx) => {
28440
28671
  const source = nodeMap.get(edge.source);
28441
28672
  const target = nodeMap.get(edge.target);
@@ -28450,8 +28681,10 @@ var init_GraphView = __esm({
28450
28681
  x2: target.x,
28451
28682
  y2: target.y,
28452
28683
  stroke: edge.color ?? DEFAULT_EDGE_COLOR,
28684
+ color: edge.color ?? DEFAULT_EDGE_COLOR,
28453
28685
  strokeWidth: 1.5,
28454
- opacity: isHighlighted ? 0.8 : 0.15
28686
+ opacity: isHighlighted ? 0.8 : 0.15,
28687
+ markerEnd: layout !== "force" ? `url(#${arrowMarkerId})` : void 0
28455
28688
  }
28456
28689
  ),
28457
28690
  showLabels && edge.label && /* @__PURE__ */ jsx(