@canmingir/link 1.2.3 → 1.2.5

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.
@@ -0,0 +1,114 @@
1
+ export const toPxNumber = (v, fallback = 1) => {
2
+ if (v == null) return fallback;
3
+ if (typeof v === "number") return v;
4
+ const n = parseFloat(String(v));
5
+ return Number.isFinite(n) ? n : fallback;
6
+ };
7
+
8
+ export const getBaseStyleForVariant = (v) => {
9
+ switch (v) {
10
+ case "card":
11
+ return {
12
+ lineColor: "#BDBDBD",
13
+ lineWidth: "2px",
14
+ lineStyle: "solid",
15
+ gap: 56,
16
+ shape: 8,
17
+ bg: "background.paper",
18
+ hoverBg: "grey.100",
19
+ borderColor: "#9E9E9E",
20
+ };
21
+ case "pill":
22
+ return {
23
+ lineColor: "#9C27B0",
24
+ lineWidth: "2px",
25
+ lineStyle: "dashed",
26
+ gap: 48,
27
+ shape: 9999,
28
+ bg: "rgba(156, 39, 176, 0.08)",
29
+ hoverBg: "rgba(156, 39, 176, 0.16)",
30
+ borderColor: "#9C27B0",
31
+ };
32
+ case "simple":
33
+ default:
34
+ return {
35
+ lineColor: "#E0E0E0",
36
+ lineWidth: "1.5px",
37
+ lineStyle: "solid",
38
+ gap: 40,
39
+ shape: 4,
40
+ bg: "background.default",
41
+ hoverBg: "grey.100",
42
+ borderColor: "#E0E0E0",
43
+ };
44
+ }
45
+ };
46
+
47
+ export const getDecisionNodeStyle = (nodeType) => {
48
+ const styles = {
49
+ start: { bg: "#E8F5E9", borderColor: "#4CAF50", shape: 8 },
50
+ decision: { bg: "#FFF3E0", borderColor: "#FF9800", shape: 24 },
51
+ process: { bg: "#E3F2FD", borderColor: "#2196F3", shape: 8 },
52
+ end: { bg: "#FFEBEE", borderColor: "#F44336", shape: 8 },
53
+ };
54
+ return styles[nodeType] || styles.process;
55
+ };
56
+
57
+ export const applySemanticTokens = (styleObj, base) => {
58
+ const s = { ...styleObj };
59
+
60
+ const borderWeightMap = { light: 1, normal: 3, bold: 5 };
61
+ if (
62
+ typeof s.border === "string" &&
63
+ ["light", "normal", "bold"].includes(s.border)
64
+ ) {
65
+ const w = borderWeightMap[s.border];
66
+ if (s.borderWidth == null) s.borderWidth = w;
67
+ if (s.lineWidth == null) s.lineWidth = `${w}px`;
68
+ if (!s.borderColor)
69
+ s.borderColor = base.borderColor || base.lineColor || "#E0E0E0";
70
+ } else if (
71
+ typeof s.border === "string" &&
72
+ (s.border.startsWith("#") || s.border.startsWith("rgb"))
73
+ ) {
74
+ s.borderColor = s.border;
75
+ }
76
+
77
+ // size: small | medium | large
78
+ const sizeMap = {
79
+ small: { cardWidth: 140, gap: 20 },
80
+ medium: { cardWidth: 180, gap: 30 },
81
+ large: { cardWidth: 220, gap: 40 },
82
+ };
83
+ if (s.size && sizeMap[s.size]) {
84
+ const { cardWidth, gap } = sizeMap[s.size];
85
+ if (s.cardWidth == null) s.cardWidth = cardWidth;
86
+ if (s.gap == null) s.gap = gap;
87
+ }
88
+
89
+ // shape: "square" | "vertical" (affects dimensions)
90
+ if (s.shape === "square") {
91
+ const defaultSize = 140;
92
+ if (s.cardWidth != null && s.minHeight == null) s.minHeight = s.cardWidth;
93
+ else if (s.minHeight != null && s.cardWidth == null)
94
+ s.cardWidth = s.minHeight;
95
+ else if (s.cardWidth == null && s.minHeight == null) {
96
+ s.cardWidth = defaultSize;
97
+ s.minHeight = defaultSize;
98
+ }
99
+ }
100
+
101
+ if (s.shape === "vertical") {
102
+ const defaultWidth = 160;
103
+ if (s.cardWidth == null) s.cardWidth = defaultWidth;
104
+ if (s.minHeight == null) s.minHeight = Math.max(s.cardWidth * 1.3, 110);
105
+ }
106
+
107
+ // shadow: "none" | "soft" | "heavy"
108
+ const shadowVariantMap = { none: 0, soft: 2, heavy: 6 };
109
+ if (s.shadow && shadowVariantMap[s.shadow] != null && s.shadowLevel == null) {
110
+ s.shadowLevel = shadowVariantMap[s.shadow];
111
+ }
112
+
113
+ return s;
114
+ };
package/src/lib/index.js CHANGED
@@ -21,3 +21,16 @@ export { default as TableHeadCustom } from "./TableHeadCustom/TableHeadCustom";
21
21
  export { default as TableSelectedAction } from "./TableSelectedAction/TableSelectedAction";
22
22
  export { default as useTable } from "./useTable/useTable";
23
23
  export { default as useChart } from "./useChart/useChart";
24
+
25
+ export { default as Flow } from "./Flow/Flow";
26
+
27
+ export {
28
+ HeaderCard,
29
+ MediaAvatarCard,
30
+ SideStripeCard,
31
+ AvatarRoleCard,
32
+ } from "./Flow/layouts/CardLayout";
33
+
34
+ export { default as ActionNode } from "./Flow/layouts/ActionNode";
35
+
36
+ export { default as InfoNode } from "./Flow/layouts/InfoNode";
@@ -1,7 +1,7 @@
1
- import { alpha, useTheme } from "@mui/material/styles";
2
-
3
1
  import merge from "lodash/merge";
4
- import { useResponsive } from "src/hooks/use-responsive";
2
+ import { useResponsive } from "../../hooks/use-responsive";
3
+
4
+ import { alpha, useTheme } from "@mui/material/styles";
5
5
 
6
6
  export default function useChart(options) {
7
7
  const theme = useTheme();
@@ -95,6 +95,8 @@ function Callback() {
95
95
 
96
96
  storage.set(name, "accessToken", accessToken);
97
97
  storage.set(name, "refreshToken", refreshToken);
98
+ // TODO - update provider info
99
+ storage.set(name, "provider", provider);
98
100
 
99
101
  dispatch({ type: "LOGIN", payload: { user: userInfo } });
100
102
 
@@ -0,0 +1,333 @@
1
+ import { FlowChart } from "../lib/FlowChart";
2
+ import React from "react";
3
+
4
+ const treeToLinked = (tree) => {
5
+ if (!tree) return { nodes: {}, roots: [] };
6
+
7
+ const nodes = {};
8
+ const roots = [];
9
+
10
+ const walk = (node, parentId = null) => {
11
+ if (!node || !node.id) return;
12
+
13
+ const { children, ...rest } = node;
14
+ if (!nodes[node.id]) {
15
+ nodes[node.id] = { ...rest, id: node.id };
16
+ }
17
+
18
+ const kids = Array.isArray(children) ? children : [];
19
+ const nextIds = kids.map((c) => c.id).filter(Boolean);
20
+
21
+ if (nextIds.length === 1) {
22
+ nodes[node.id].next = nextIds[0];
23
+ } else if (nextIds.length > 1) {
24
+ nodes[node.id].next = nextIds;
25
+ }
26
+
27
+ if (parentId) {
28
+ nodes[node.id].previous = parentId;
29
+ } else if (!roots.includes(node.id)) {
30
+ roots.push(node.id);
31
+ }
32
+
33
+ kids.forEach((child) => walk(child, node.id));
34
+ };
35
+
36
+ walk(tree);
37
+ return { nodes, roots };
38
+ };
39
+
40
+ const arrayToLinked = (arr) => {
41
+ const a = Array.isArray(arr) ? [...arr] : [];
42
+ if (!a.length) return { nodes: {}, roots: [] };
43
+
44
+ a.sort((x, y) => {
45
+ const dx = x?.createdAt ? new Date(x.createdAt).getTime() : 0;
46
+ const dy = y?.createdAt ? new Date(y.createdAt).getTime() : 0;
47
+ return dx - dy;
48
+ });
49
+
50
+ const nodes = {};
51
+ const ids = [];
52
+
53
+ for (let i = 0; i < a.length; i++) {
54
+ const id = a[i]?.id ?? `auto-${i}`;
55
+ ids.push(id);
56
+ nodes[id] = { ...(a[i] || {}), id };
57
+ }
58
+
59
+ for (let i = 0; i < ids.length; i++) {
60
+ const cur = ids[i];
61
+ const prev = ids[i - 1];
62
+ const nxt = ids[i + 1];
63
+ if (prev) nodes[cur].previous = prev;
64
+ if (nxt) nodes[cur].next = nxt;
65
+ }
66
+
67
+ return { nodes, roots: [ids[0]] };
68
+ };
69
+
70
+ export default {
71
+ title: "Components/FlowChart",
72
+ component: FlowChart,
73
+ parameters: {
74
+ layout: "centered",
75
+ },
76
+ tags: ["autodocs"],
77
+ argTypes: {
78
+ data: {
79
+ control: "object",
80
+ description:
81
+ "Linked graph data: { nodes: { [id]: { id, next?, previous?, ... } }, roots?: string[] }",
82
+ },
83
+ style: {
84
+ control: "object",
85
+ description:
86
+ "Styling tokens or a style object; can also be a function (node) => tokens.",
87
+ },
88
+ type: {
89
+ control: "text",
90
+ description: 'Type of the flow chart, e.g. "default" or "task".',
91
+ },
92
+ variant: {
93
+ control: {
94
+ type: "select",
95
+ options: ["simple", "card", "pill", "decision"],
96
+ },
97
+ description: "Visual variant of the flow chart nodes.",
98
+ },
99
+ },
100
+ };
101
+
102
+ const simpleTree = {
103
+ id: "root",
104
+ label: "Start",
105
+ children: [
106
+ { id: "step1", label: "Step 1", children: [] },
107
+ { id: "step2", label: "Step 2", children: [] },
108
+ ],
109
+ };
110
+
111
+ export const SimpleTextNodes = {
112
+ args: {
113
+ type: "default",
114
+ data: treeToLinked(simpleTree),
115
+ variant: "simple",
116
+ },
117
+ };
118
+
119
+ const cardTree = {
120
+ id: "1",
121
+ title: "Project Alpha",
122
+ description: "Main project",
123
+ status: "active",
124
+ children: [
125
+ {
126
+ id: "2",
127
+ title: "Task 1",
128
+ description: "First task",
129
+ status: "completed",
130
+ children: [],
131
+ },
132
+ {
133
+ id: "3",
134
+ title: "Task 2",
135
+ description: "Second task",
136
+ status: "in-progress",
137
+ children: [],
138
+ },
139
+ ],
140
+ };
141
+
142
+ export const CardNodes = {
143
+ args: {
144
+ type: "default",
145
+ data: treeToLinked(cardTree),
146
+ variant: "card",
147
+ style: {
148
+ border: "light",
149
+ size: "small",
150
+ shadow: "heavy",
151
+ shape: "square",
152
+ },
153
+ },
154
+ };
155
+
156
+ export const OrganizationalChart = {
157
+ render: () => {
158
+ const orgTree = {
159
+ id: "add6dfa4-45ba-4da2-bc5c-5a529610b52f",
160
+ name: "Rebellion Coffee Shop Team",
161
+ icon: ":ph:coffee-bean-duotone:",
162
+ description: null,
163
+ type: null,
164
+ organizationId: "dfb990bb-81dd-4584-82ce-050eb8f6a12f",
165
+ coach: "Elijah",
166
+ colleagues: [
167
+ {
168
+ id: "00db1bd4-4829-40f2-8b99-d2e42342157e",
169
+ name: "Ava",
170
+ avatar: ":1:",
171
+ character: "Funny, friendly, and a coffee lover",
172
+ title: "Barista",
173
+ role: "Barista Expert",
174
+ teamId: "add6dfa4-45ba-4da2-bc5c-5a529610b52f",
175
+ aiEngineId: "289a3c9a-f23b-421a-ac6e-f14052a2d57c",
176
+ },
177
+ {
178
+ id: "ef906c5d-cafe-4518-9edc-b80c605df58e",
179
+ name: "Taylor",
180
+ title: "Customer Service Representative",
181
+ avatar: ":2:",
182
+ character: "Friendly, helpful, and a team player",
183
+ role: "Customer Service Representative",
184
+ teamId: "e6d4744d-a11b-4c75-acad-e24a02903729",
185
+ aiEngineId: "289a3c9a-f23b-421a-ac6e-f14052a2d57c",
186
+ },
187
+ ],
188
+ };
189
+
190
+ const data = treeToLinked(orgTree);
191
+
192
+ return <FlowChart type="teamChart" data={data} variant="simple" />;
193
+ },
194
+ };
195
+
196
+ export const DecisionTree = {
197
+ render: () => {
198
+ const decisionTree = {
199
+ id: "start",
200
+ label: "Start Process",
201
+ type: "start",
202
+ children: [
203
+ {
204
+ id: "check",
205
+ label: "Valid Input?",
206
+ type: "decision",
207
+ children: [
208
+ {
209
+ id: "process",
210
+ label: "Process Data",
211
+ type: "process",
212
+ children: [
213
+ { id: "success", label: "Success", type: "end", children: [] },
214
+ ],
215
+ },
216
+ {
217
+ id: "error",
218
+ label: "Show Error",
219
+ type: "process",
220
+ children: [
221
+ { id: "end", label: "End", type: "end", children: [] },
222
+ ],
223
+ },
224
+ ],
225
+ },
226
+ ],
227
+ };
228
+
229
+ const data = treeToLinked(decisionTree);
230
+
231
+ return (
232
+ <FlowChart
233
+ data={data}
234
+ variant="decision"
235
+ style={{ connectorType: "curved" }}
236
+ />
237
+ );
238
+ },
239
+ };
240
+
241
+ const deepTree = {
242
+ id: "root",
243
+ label: "Root",
244
+ children: [
245
+ {
246
+ id: "branch1",
247
+ label: "Branch 1",
248
+ children: [
249
+ {
250
+ id: "leaf1-1",
251
+ label: "Leaf 1.1",
252
+ children: [{ id: "leaf1-1-1", label: "Leaf 1.1.1", children: [] }],
253
+ },
254
+ ],
255
+ },
256
+ {
257
+ id: "branch2",
258
+ label: "Branch 2",
259
+ children: [
260
+ { id: "leaf2-1", label: "Leaf 2.1", children: [] },
261
+ { id: "leaf2-2", label: "Leaf 2.2", children: [] },
262
+ ],
263
+ },
264
+ ],
265
+ };
266
+
267
+ export const DeepHierarchy = {
268
+ args: {
269
+ type: "default",
270
+ data: treeToLinked(deepTree),
271
+ variant: "simple",
272
+ },
273
+ };
274
+
275
+ export const TaskFlow = {
276
+ render: () => {
277
+ const timeline = [
278
+ {
279
+ id: "773b051a-326a-4140-98c4-d63df8aba39f",
280
+ action: "PLATFORM:scrape_website",
281
+ parameters: {
282
+ url: "https://nucleoid.com/domain-ownership.html",
283
+ },
284
+ result:
285
+ '\n URL: https://nucleoid.com/domain-ownership.html\n Title: \n Content: This domain "nucleoid.com" is owned by Can Mingir for Nucleoid Ltd. Co. Contact: canmingir@nucleoid.com Phone: (914) 525-5929 Address: 2972 Webb Bridge Rd, Alpharetta, GA 30009, United States\n ',
286
+ comment: "Scrape the website to extract the list of emails",
287
+ status: "COMPLETED",
288
+ taskId: "6ce93ce9-d923-46ba-b8a9-1a4cea50ca07",
289
+ createdAt: "2025-11-10T13:09:53.188Z",
290
+ },
291
+ {
292
+ id: "e6b12140-f922-4fa5-9e9d-e3064909716c",
293
+ action: "PLATFORM:llm",
294
+ parameters: {
295
+ message:
296
+ 'Extract the email addresses from the scraped website content:\n\nThis domain "nucleoid.com" is owned by Can Mingir for Nucleoid Ltd. Co. Contact: canmingir@nucleoid.com Phone: (914) 525-5929 Address: 2972 Webb Bridge Rd, Alpharetta, GA 30009, United States',
297
+ },
298
+ result: '["canmingir@nucleoid.com"]',
299
+ comment: "Extract the email addresses from the scraped website content",
300
+ status: "COMPLETED",
301
+ taskId: "6ce93ce9-d923-46ba-b8a9-1a4cea50ca07",
302
+ createdAt: "2025-11-10T13:09:59.261Z",
303
+ },
304
+ {
305
+ id: "05fba361-4071-4db7-88e8-4f1b6fabddba",
306
+ action: "PLATFORM:complete",
307
+ parameters: {},
308
+ result: "Task completed successfully",
309
+ comment:
310
+ "Task completed after extracting email addresses from the website",
311
+ status: "COMPLETED",
312
+ taskId: "6ce93ce9-d923-46ba-b8a9-1a4cea50ca07",
313
+ createdAt: "2025-11-10T13:10:02.653Z",
314
+ },
315
+ ];
316
+
317
+ const data = arrayToLinked(timeline);
318
+
319
+ return (
320
+ <FlowChart
321
+ type="task"
322
+ data={data}
323
+ variant="pill"
324
+ style={{
325
+ visible: true,
326
+ delay: 0,
327
+ isLoading: false,
328
+ connectorType: "curved",
329
+ }}
330
+ />
331
+ );
332
+ },
333
+ };