@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.
@@ -27207,7 +27207,12 @@ function daysAgo(n) {
27207
27207
  d.setDate(d.getDate() - n);
27208
27208
  return d;
27209
27209
  }
27210
- var DEFAULT_PRESETS, DateRangePicker;
27210
+ function resolvePresetRange(preset) {
27211
+ if (typeof preset.range === "function") return preset.range();
27212
+ if (preset.range) return preset.range;
27213
+ return TOKEN_RANGES[preset.value]?.() ?? null;
27214
+ }
27215
+ var TOKEN_RANGES, DEFAULT_PRESETS, DateRangePicker;
27211
27216
  var init_DateRangePicker = __esm({
27212
27217
  "components/core/molecules/DateRangePicker.tsx"() {
27213
27218
  "use client";
@@ -27217,32 +27222,19 @@ var init_DateRangePicker = __esm({
27217
27222
  init_Stack();
27218
27223
  init_Typography();
27219
27224
  init_useEventBus();
27225
+ TOKEN_RANGES = {
27226
+ "7d": () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) }),
27227
+ "30d": () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) }),
27228
+ month: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) }),
27229
+ quarter: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) }),
27230
+ ytd: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
27231
+ };
27220
27232
  DEFAULT_PRESETS = [
27221
- {
27222
- label: "Last 7 days",
27223
- value: "7d",
27224
- range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
27225
- },
27226
- {
27227
- label: "Last 30 days",
27228
- value: "30d",
27229
- range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
27230
- },
27231
- {
27232
- label: "This Month",
27233
- value: "month",
27234
- range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
27235
- },
27236
- {
27237
- label: "This Quarter",
27238
- value: "quarter",
27239
- range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
27240
- },
27241
- {
27242
- label: "YTD",
27243
- value: "ytd",
27244
- range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
27245
- }
27233
+ { label: "Last 7 days", value: "7d" },
27234
+ { label: "Last 30 days", value: "30d" },
27235
+ { label: "This Month", value: "month" },
27236
+ { label: "This Quarter", value: "quarter" },
27237
+ { label: "YTD", value: "ytd" }
27246
27238
  ];
27247
27239
  DateRangePicker = ({
27248
27240
  from: fromProp,
@@ -27283,7 +27275,8 @@ var init_DateRangePicker = __esm({
27283
27275
  );
27284
27276
  const handlePreset = React85.useCallback(
27285
27277
  (preset) => {
27286
- const range = preset.range();
27278
+ const range = resolvePresetRange(preset);
27279
+ if (range === null) return;
27287
27280
  setFrom(range.from);
27288
27281
  setTo(range.to);
27289
27282
  setActivePreset(preset.value);
@@ -27291,8 +27284,12 @@ var init_DateRangePicker = __esm({
27291
27284
  },
27292
27285
  [emit]
27293
27286
  );
27287
+ const renderablePresets = React85.useMemo(
27288
+ () => presets.filter((p) => p.range !== void 0 || TOKEN_RANGES[p.value] !== void 0),
27289
+ [presets]
27290
+ );
27294
27291
  const presetButtons = React85.useMemo(
27295
- () => presets.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
27292
+ () => renderablePresets.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
27296
27293
  Button,
27297
27294
  {
27298
27295
  variant: activePreset === preset.value ? "primary" : "ghost",
@@ -27302,7 +27299,7 @@ var init_DateRangePicker = __esm({
27302
27299
  },
27303
27300
  preset.value
27304
27301
  )),
27305
- [presets, activePreset, handlePreset]
27302
+ [renderablePresets, activePreset, handlePreset]
27306
27303
  );
27307
27304
  return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", className: cn(className), children: [
27308
27305
  /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "md", align: "end", children: [
@@ -27329,7 +27326,7 @@ var init_DateRangePicker = __esm({
27329
27326
  )
27330
27327
  ] })
27331
27328
  ] }),
27332
- presets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
27329
+ renderablePresets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
27333
27330
  ] });
27334
27331
  };
27335
27332
  DateRangePicker.displayName = "DateRangePicker";
@@ -27771,6 +27768,208 @@ var init_PhysicsCanvas = __esm({
27771
27768
  };
27772
27769
  }
27773
27770
  });
27771
+
27772
+ // lib/graphViewLayouts.ts
27773
+ function buildAdjacency(nodeIds, edges) {
27774
+ const known = new Set(nodeIds);
27775
+ const out = /* @__PURE__ */ new Map();
27776
+ const inMap = /* @__PURE__ */ new Map();
27777
+ for (const id of nodeIds) {
27778
+ out.set(id, []);
27779
+ inMap.set(id, []);
27780
+ }
27781
+ for (const edge of edges) {
27782
+ if (!known.has(edge.source) || !known.has(edge.target)) continue;
27783
+ out.get(edge.source)?.push(edge.target);
27784
+ inMap.get(edge.target)?.push(edge.source);
27785
+ }
27786
+ return { out, in: inMap };
27787
+ }
27788
+ function findRoots(nodeIds, adjacency) {
27789
+ return nodeIds.filter((id) => (adjacency.in.get(id)?.length ?? 0) === 0);
27790
+ }
27791
+ function assignLayers(nodeIds, adjacency, roots) {
27792
+ const layer = new Map(nodeIds.map((id) => [id, 0]));
27793
+ const onStack = /* @__PURE__ */ new Set();
27794
+ const visit = (id) => {
27795
+ onStack.add(id);
27796
+ const currentLayer = layer.get(id) ?? 0;
27797
+ for (const next of adjacency.out.get(id) ?? []) {
27798
+ if (onStack.has(next)) continue;
27799
+ const candidate = currentLayer + 1;
27800
+ if (candidate > (layer.get(next) ?? 0)) {
27801
+ layer.set(next, candidate);
27802
+ }
27803
+ visit(next);
27804
+ }
27805
+ onStack.delete(id);
27806
+ };
27807
+ for (const root of roots) visit(root);
27808
+ return layer;
27809
+ }
27810
+ function computeVisitOrder(nodeIds, adjacency, roots) {
27811
+ const order = /* @__PURE__ */ new Map();
27812
+ const visited = /* @__PURE__ */ new Set();
27813
+ let counter = 0;
27814
+ const visit = (id) => {
27815
+ if (visited.has(id)) return;
27816
+ visited.add(id);
27817
+ order.set(id, counter++);
27818
+ for (const next of adjacency.out.get(id) ?? []) visit(next);
27819
+ };
27820
+ for (const root of roots) visit(root);
27821
+ for (const id of nodeIds) {
27822
+ if (!visited.has(id)) order.set(id, counter++);
27823
+ }
27824
+ return order;
27825
+ }
27826
+ function bfsDepthAndOrder(nodeIds, adjacency, roots) {
27827
+ const depth = new Map(nodeIds.map((id) => [id, 0]));
27828
+ const visitOrder = /* @__PURE__ */ new Map();
27829
+ const visited = /* @__PURE__ */ new Set();
27830
+ const queue = [];
27831
+ let counter = 0;
27832
+ for (const root of roots) {
27833
+ if (visited.has(root)) continue;
27834
+ visited.add(root);
27835
+ depth.set(root, 0);
27836
+ visitOrder.set(root, counter++);
27837
+ queue.push(root);
27838
+ }
27839
+ let head = 0;
27840
+ while (head < queue.length) {
27841
+ const id = queue[head++];
27842
+ const d = depth.get(id) ?? 0;
27843
+ for (const next of adjacency.out.get(id) ?? []) {
27844
+ if (visited.has(next)) continue;
27845
+ visited.add(next);
27846
+ depth.set(next, d + 1);
27847
+ visitOrder.set(next, counter++);
27848
+ queue.push(next);
27849
+ }
27850
+ }
27851
+ for (const id of nodeIds) {
27852
+ if (!visited.has(id)) visitOrder.set(id, counter++);
27853
+ }
27854
+ return { depth, visitOrder };
27855
+ }
27856
+ function edgeWalkOrder(nodeIds, adjacency) {
27857
+ const visited = /* @__PURE__ */ new Set();
27858
+ const result = [];
27859
+ for (const start of nodeIds) {
27860
+ if (visited.has(start)) continue;
27861
+ let current = start;
27862
+ while (current !== void 0 && !visited.has(current)) {
27863
+ visited.add(current);
27864
+ result.push(current);
27865
+ const outs = adjacency.out.get(current) ?? [];
27866
+ current = outs.find((next) => !visited.has(next));
27867
+ }
27868
+ }
27869
+ return result;
27870
+ }
27871
+ function groupByTier(nodeIds, tierOf, maxTier) {
27872
+ const groups = Array.from({ length: maxTier + 1 }, () => []);
27873
+ for (const id of nodeIds) {
27874
+ groups[tierOf.get(id) ?? 0].push(id);
27875
+ }
27876
+ return groups;
27877
+ }
27878
+ function distributeAxis(count, start, end) {
27879
+ if (count <= 0) return [];
27880
+ const slot = (end - start) / count;
27881
+ return Array.from({ length: count }, (_, i) => start + slot * (i + 0.5));
27882
+ }
27883
+ function orderByParentPositionThenInput(group, adjacency, positioned, inputIndex) {
27884
+ const withKey = group.map((id) => {
27885
+ const parentValues = (adjacency.in.get(id) ?? []).map((p) => positioned.get(p)).filter((v) => v !== void 0);
27886
+ const avg = parentValues.length > 0 ? parentValues.reduce((a, b) => a + b, 0) / parentValues.length : Number.POSITIVE_INFINITY;
27887
+ return { id, avg, idx: inputIndex.get(id) ?? 0 };
27888
+ });
27889
+ withKey.sort((a, b) => a.avg !== b.avg ? a.avg - b.avg : a.idx - b.idx);
27890
+ return withKey.map((k) => k.id);
27891
+ }
27892
+ function layoutFlow(nodeIds, adjacency, roots, width, height, margin) {
27893
+ const inputIndex = new Map(nodeIds.map((id, i) => [id, i]));
27894
+ const layers = assignLayers(nodeIds, adjacency, roots);
27895
+ const maxLayer = Math.max(...Array.from(layers.values()));
27896
+ const layerGroups = groupByTier(nodeIds, layers, maxLayer);
27897
+ const positions = /* @__PURE__ */ new Map();
27898
+ const yById = /* @__PURE__ */ new Map();
27899
+ for (let l = 0; l <= maxLayer; l++) {
27900
+ const x = margin + l * (width - 2 * margin) / Math.max(1, maxLayer);
27901
+ const ordered2 = orderByParentPositionThenInput(layerGroups[l], adjacency, yById, inputIndex);
27902
+ const ys = distributeAxis(ordered2.length, margin, height - margin);
27903
+ ordered2.forEach((id, i) => {
27904
+ positions.set(id, { id, x, y: ys[i] });
27905
+ yById.set(id, ys[i]);
27906
+ });
27907
+ }
27908
+ return nodeIds.map((id) => positions.get(id));
27909
+ }
27910
+ function layoutTree(nodeIds, adjacency, roots, width, height, margin) {
27911
+ const effectiveRoots = roots.length > 0 ? roots : [nodeIds[0]];
27912
+ const layers = assignLayers(nodeIds, adjacency, effectiveRoots);
27913
+ const maxLayer = Math.max(...Array.from(layers.values()));
27914
+ const visitOrder = computeVisitOrder(nodeIds, adjacency, effectiveRoots);
27915
+ const layerGroups = groupByTier(nodeIds, layers, maxLayer);
27916
+ const positions = /* @__PURE__ */ new Map();
27917
+ for (let l = 0; l <= maxLayer; l++) {
27918
+ const ordered2 = [...layerGroups[l]].sort(
27919
+ (a, b) => (visitOrder.get(a) ?? 0) - (visitOrder.get(b) ?? 0)
27920
+ );
27921
+ const y = margin + l * (height - 2 * margin) / Math.max(1, maxLayer);
27922
+ const xs = distributeAxis(ordered2.length, margin, width - margin);
27923
+ ordered2.forEach((id, i) => positions.set(id, { id, x: xs[i], y }));
27924
+ }
27925
+ return nodeIds.map((id) => positions.get(id));
27926
+ }
27927
+ function layoutRadial(nodeIds, adjacency, roots, width, height, margin) {
27928
+ const cx = width / 2;
27929
+ const cy = height / 2;
27930
+ const maxRadius = Math.min(width, height) / 2 - margin;
27931
+ if (roots.length === 0) {
27932
+ const order = edgeWalkOrder(nodeIds, adjacency);
27933
+ const k = order.length;
27934
+ const positions2 = /* @__PURE__ */ new Map();
27935
+ order.forEach((id, i) => {
27936
+ const angle = i / k * 2 * Math.PI;
27937
+ positions2.set(id, { id, x: cx + maxRadius * Math.cos(angle), y: cy + maxRadius * Math.sin(angle) });
27938
+ });
27939
+ return nodeIds.map((id) => positions2.get(id));
27940
+ }
27941
+ const { depth, visitOrder } = bfsDepthAndOrder(nodeIds, adjacency, roots);
27942
+ const maxDepth = Math.max(...Array.from(depth.values()));
27943
+ const ringGroups = groupByTier(nodeIds, depth, maxDepth);
27944
+ const positions = /* @__PURE__ */ new Map();
27945
+ for (let d = 0; d <= maxDepth; d++) {
27946
+ const ordered2 = [...ringGroups[d]].sort(
27947
+ (a, b) => (visitOrder.get(a) ?? 0) - (visitOrder.get(b) ?? 0)
27948
+ );
27949
+ const radius = d * maxRadius / Math.max(1, maxDepth);
27950
+ const k = ordered2.length;
27951
+ ordered2.forEach((id, i) => {
27952
+ const angle = i / k * 2 * Math.PI;
27953
+ positions.set(id, { id, x: cx + radius * Math.cos(angle), y: cy + radius * Math.sin(angle) });
27954
+ });
27955
+ }
27956
+ return nodeIds.map((id) => positions.get(id));
27957
+ }
27958
+ function computeStaticLayout(mode, input) {
27959
+ const { nodeIds, edges, width, height } = input;
27960
+ const margin = input.margin ?? 40;
27961
+ if (nodeIds.length === 0) return [];
27962
+ if (nodeIds.length === 1) return [{ id: nodeIds[0], x: width / 2, y: height / 2 }];
27963
+ const adjacency = buildAdjacency(nodeIds, edges);
27964
+ const roots = findRoots(nodeIds, adjacency);
27965
+ if (mode === "flow") return layoutFlow(nodeIds, adjacency, roots, width, height, margin);
27966
+ if (mode === "tree") return layoutTree(nodeIds, adjacency, roots, width, height, margin);
27967
+ return layoutRadial(nodeIds, adjacency, roots, width, height, margin);
27968
+ }
27969
+ var init_graphViewLayouts = __esm({
27970
+ "lib/graphViewLayouts.ts"() {
27971
+ }
27972
+ });
27774
27973
  function resolveNodeColor(node, groups) {
27775
27974
  if (node.color) return node.color;
27776
27975
  if (node.group) {
@@ -27785,6 +27984,7 @@ var init_GraphView = __esm({
27785
27984
  "use client";
27786
27985
  init_cn();
27787
27986
  init_atoms();
27987
+ init_graphViewLayouts();
27788
27988
  GROUP_COLORS = [
27789
27989
  "#3b82f6",
27790
27990
  // blue-500
@@ -27815,11 +28015,13 @@ var init_GraphView = __esm({
27815
28015
  height: propHeight,
27816
28016
  className,
27817
28017
  showLabels = true,
27818
- zoomToFit = true
28018
+ zoomToFit = true,
28019
+ layout = "force"
27819
28020
  }) => {
27820
28021
  const { t } = hooks.useTranslate();
27821
28022
  const containerRef = React85.useRef(null);
27822
28023
  const animRef = React85.useRef(0);
28024
+ const arrowMarkerId = React85.useId();
27823
28025
  const [simNodes, setSimNodes] = React85.useState([]);
27824
28026
  const [settled, setSettled] = React85.useState(false);
27825
28027
  const [hoveredId, setHoveredId] = React85.useState(null);
@@ -27876,6 +28078,22 @@ var init_GraphView = __esm({
27876
28078
  fy: 0
27877
28079
  };
27878
28080
  });
28081
+ if (layout !== "force") {
28082
+ const points = computeStaticLayout(layout, {
28083
+ nodeIds: nodes.map((n) => n.id),
28084
+ edges,
28085
+ width: w,
28086
+ height: h
28087
+ });
28088
+ const pointById = new Map(points.map((p) => [p.id, p]));
28089
+ const laidOut = initialNodes.map((node) => {
28090
+ const point = pointById.get(node.id);
28091
+ return point ? { ...node, x: point.x, y: point.y } : node;
28092
+ });
28093
+ setSimNodes(laidOut);
28094
+ setSettled(true);
28095
+ return;
28096
+ }
27879
28097
  let iterations = 0;
27880
28098
  const maxIterations = 120;
27881
28099
  let currentNodes = initialNodes;
@@ -27944,7 +28162,7 @@ var init_GraphView = __esm({
27944
28162
  return () => {
27945
28163
  cancelAnimationFrame(animRef.current);
27946
28164
  };
27947
- }, [nodes, edges, w, h, groups]);
28165
+ }, [nodes, edges, w, h, groups, layout]);
27948
28166
  const viewBox = React85.useMemo(() => {
27949
28167
  if (!zoomToFit || !settled || simNodes.length === 0) {
27950
28168
  return `0 0 ${w} ${h}`;
@@ -28019,6 +28237,19 @@ var init_GraphView = __esm({
28019
28237
  viewBox,
28020
28238
  preserveAspectRatio: "xMidYMid meet",
28021
28239
  children: [
28240
+ layout !== "force" && /* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsx(
28241
+ "marker",
28242
+ {
28243
+ id: arrowMarkerId,
28244
+ viewBox: "0 0 10 10",
28245
+ refX: "9",
28246
+ refY: "5",
28247
+ markerWidth: "6",
28248
+ markerHeight: "6",
28249
+ orient: "auto-start-reverse",
28250
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M0,0 L10,5 L0,10 z", fill: "currentColor" })
28251
+ }
28252
+ ) }),
28022
28253
  edges.map((edge, idx) => {
28023
28254
  const source = nodeMap.get(edge.source);
28024
28255
  const target = nodeMap.get(edge.target);
@@ -28033,8 +28264,10 @@ var init_GraphView = __esm({
28033
28264
  x2: target.x,
28034
28265
  y2: target.y,
28035
28266
  stroke: edge.color ?? DEFAULT_EDGE_COLOR,
28267
+ color: edge.color ?? DEFAULT_EDGE_COLOR,
28036
28268
  strokeWidth: 1.5,
28037
- opacity: isHighlighted ? 0.8 : 0.15
28269
+ opacity: isHighlighted ? 0.8 : 0.15,
28270
+ markerEnd: layout !== "force" ? `url(#${arrowMarkerId})` : void 0
28038
28271
  }
28039
28272
  ),
28040
28273
  showLabels && edge.label && /* @__PURE__ */ jsxRuntime.jsx(