dishui 0.0.89 → 0.0.97
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.
- package/dist/.release-verified.json +6 -0
- package/dist/ai.js +22 -0
- package/dist/components/Card/Metric2.js +11 -11
- package/dist/components/Card/Metric2.js.map +1 -1
- package/dist/components/Card/index.d.ts +20 -0
- package/dist/components/Card/index.js +184 -179
- package/dist/components/Card/index.js.map +1 -1
- package/dist/components/GroupButton/index.js +4 -4
- package/dist/components/GroupButton/index.js.map +1 -1
- package/dist/components/GroupedTable/index.js +10 -10
- package/dist/components/GroupedTable/index.js.map +1 -1
- package/dist/components/NavigationList/index.js +9 -9
- package/dist/components/NavigationList/index.js.map +1 -1
- package/dist/components/Section/index.js +11 -11
- package/dist/components/Section/index.js.map +1 -1
- package/dist/components/Skeleton/index.js +1 -1
- package/dist/components/Skeleton/index.js.map +1 -1
- package/dist/components/Table/index.d.ts +23 -2
- package/dist/components/Table/index.js +153 -101
- package/dist/components/Table/index.js.map +1 -1
- package/dist/components/ai/AgentChat/index.d.ts +54 -0
- package/dist/components/ai/AgentChat/index.js +176 -0
- package/dist/components/ai/AgentChat/index.js.map +1 -0
- package/dist/components/ai/AgentScreen/index.d.ts +50 -0
- package/dist/components/ai/AgentScreen/index.js +233 -0
- package/dist/components/ai/AgentScreen/index.js.map +1 -0
- package/dist/components/ai/ApprovalCard/index.d.ts +26 -0
- package/dist/components/ai/ApprovalCard/index.js +89 -0
- package/dist/components/ai/ApprovalCard/index.js.map +1 -0
- package/dist/components/ai/CodeView/index.d.ts +30 -0
- package/dist/components/ai/CodeView/index.js +149 -0
- package/dist/components/ai/CodeView/index.js.map +1 -0
- package/dist/components/ai/CommandSearch/index.d.ts +39 -0
- package/dist/components/ai/CommandSearch/index.js +217 -0
- package/dist/components/ai/CommandSearch/index.js.map +1 -0
- package/dist/components/ai/ContextCards/index.d.ts +42 -0
- package/dist/components/ai/ContextCards/index.js +106 -0
- package/dist/components/ai/ContextCards/index.js.map +1 -0
- package/dist/components/ai/DiffTable/index.d.ts +70 -0
- package/dist/components/ai/DiffTable/index.js +235 -0
- package/dist/components/ai/DiffTable/index.js.map +1 -0
- package/dist/components/ai/FilterTable/index.d.ts +35 -0
- package/dist/components/ai/FilterTable/index.js +86 -0
- package/dist/components/ai/FilterTable/index.js.map +1 -0
- package/dist/components/ai/FineTuneCard/index.d.ts +24 -0
- package/dist/components/ai/FineTuneCard/index.js +75 -0
- package/dist/components/ai/FineTuneCard/index.js.map +1 -0
- package/dist/components/ai/InsightCards/index.d.ts +23 -0
- package/dist/components/ai/InsightCards/index.js +64 -0
- package/dist/components/ai/InsightCards/index.js.map +1 -0
- package/dist/components/ai/LoadingState/index.d.ts +22 -0
- package/dist/components/ai/LoadingState/index.js +80 -0
- package/dist/components/ai/LoadingState/index.js.map +1 -0
- package/dist/components/ai/PromptBar/index.d.ts +26 -0
- package/dist/components/ai/PromptBar/index.js +117 -0
- package/dist/components/ai/PromptBar/index.js.map +1 -0
- package/dist/components/ai/RecommendationCard/index.d.ts +44 -0
- package/dist/components/ai/RecommendationCard/index.js +142 -0
- package/dist/components/ai/RecommendationCard/index.js.map +1 -0
- package/dist/components/ai/RecordsTable/index.d.ts +65 -0
- package/dist/components/ai/RecordsTable/index.js +334 -0
- package/dist/components/ai/RecordsTable/index.js.map +1 -0
- package/dist/components/ai/SelectionActions/index.d.ts +19 -0
- package/dist/components/ai/SelectionActions/index.js +40 -0
- package/dist/components/ai/SelectionActions/index.js.map +1 -0
- package/dist/components/ai/StateFlow/index.d.ts +24 -0
- package/dist/components/ai/StateFlow/index.js +50 -0
- package/dist/components/ai/StateFlow/index.js.map +1 -0
- package/dist/components/ai/StreamingText/index.d.ts +44 -0
- package/dist/components/ai/StreamingText/index.js +211 -0
- package/dist/components/ai/StreamingText/index.js.map +1 -0
- package/dist/components/ai/TaskRows/index.d.ts +53 -0
- package/dist/components/ai/TaskRows/index.js +186 -0
- package/dist/components/ai/TaskRows/index.js.map +1 -0
- package/dist/components/ai/Thinking/index.d.ts +47 -0
- package/dist/components/ai/Thinking/index.js +197 -0
- package/dist/components/ai/Thinking/index.js.map +1 -0
- package/dist/components/ai/ToolChips/index.d.ts +21 -0
- package/dist/components/ai/ToolChips/index.js +63 -0
- package/dist/components/ai/ToolChips/index.js.map +1 -0
- package/dist/components/ai/index.d.ts +50 -0
- package/dist/components/ai/shared.d.ts +13 -0
- package/dist/components/ai/shared.js +25 -0
- package/dist/components/ai/shared.js.map +1 -0
- package/dist/components/pro/DataTable/DataTable.js +70 -51
- package/dist/components/pro/DataTable/DataTable.js.map +1 -1
- package/dist/components/pro/DataTable/components/TableBody.d.ts +3 -1
- package/dist/components/pro/DataTable/components/TableBody.js +41 -39
- package/dist/components/pro/DataTable/components/TableBody.js.map +1 -1
- package/dist/components/pro/DataTable/components/TableToolbar.d.ts +2 -1
- package/dist/components/pro/DataTable/components/TableToolbar.js +25 -19
- package/dist/components/pro/DataTable/components/TableToolbar.js.map +1 -1
- package/dist/components/pro/DataTable/index.d.ts +1 -1
- package/dist/components/pro/DataTable/rowDetailExtension.js +1 -1
- package/dist/components/pro/DataTable/rowDetailExtension.js.map +1 -1
- package/dist/components/pro/DataTable/types.d.ts +19 -0
- package/dist/data-table.js.map +1 -1
- package/dist/dishui.css +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +128 -107
- package/dist/layouts/Sidebar.d.ts +16 -0
- package/dist/layouts/Sidebar.js +85 -52
- package/dist/layouts/Sidebar.js.map +1 -1
- package/dist/lite.d.ts +2 -0
- package/dist/lite.js +22 -21
- package/package.json +10 -3
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import { cn as e } from "../../../utils/cn.js";
|
|
2
|
+
/* empty css */
|
|
3
|
+
import { useEffect as t, useMemo as n, useState as r } from "react";
|
|
4
|
+
import { Fragment as i, jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/ai/RecordsTable/index.tsx
|
|
6
|
+
var s = {
|
|
7
|
+
index: "#",
|
|
8
|
+
company: "Company",
|
|
9
|
+
categories: "Categories",
|
|
10
|
+
lastInteraction: "Last interaction",
|
|
11
|
+
strength: "Connection strength",
|
|
12
|
+
links: "Links",
|
|
13
|
+
noContact: "No contact",
|
|
14
|
+
count: "count",
|
|
15
|
+
average: "average",
|
|
16
|
+
linksCount: "links",
|
|
17
|
+
addCalculation: "Add calculation",
|
|
18
|
+
empty: "No records"
|
|
19
|
+
}, c = {
|
|
20
|
+
"very-strong": "Very strong",
|
|
21
|
+
strong: "Strong",
|
|
22
|
+
weak: "Weak",
|
|
23
|
+
"very-weak": "Very weak",
|
|
24
|
+
none: "No communication"
|
|
25
|
+
}, l = {
|
|
26
|
+
none: 0,
|
|
27
|
+
"very-weak": 1,
|
|
28
|
+
weak: 2,
|
|
29
|
+
strong: 3,
|
|
30
|
+
"very-strong": 4
|
|
31
|
+
};
|
|
32
|
+
function u(e) {
|
|
33
|
+
return l[e] * 25;
|
|
34
|
+
}
|
|
35
|
+
var d = 6e4, f = 60 * d, p = 24 * f, m = 7 * p, h = 30.44 * p, g = 365.25 * p, _ = (e) => `${e} year${e === 1 ? "" : "s"} ago`;
|
|
36
|
+
function v(e, t) {
|
|
37
|
+
let n = Math.max(0, t - e);
|
|
38
|
+
if (n < d) return "just now";
|
|
39
|
+
if (n < f) {
|
|
40
|
+
let e = Math.round(n / d);
|
|
41
|
+
return `${e} minute${e === 1 ? "" : "s"} ago`;
|
|
42
|
+
}
|
|
43
|
+
if (n < p) {
|
|
44
|
+
let e = Math.round(n / f);
|
|
45
|
+
return `${e} hour${e === 1 ? "" : "s"} ago`;
|
|
46
|
+
}
|
|
47
|
+
if (n < m) {
|
|
48
|
+
let e = Math.round(n / p);
|
|
49
|
+
return e <= 1 ? "yesterday" : `${e} days ago`;
|
|
50
|
+
}
|
|
51
|
+
if (n < 2 * h) {
|
|
52
|
+
let e = Math.round(n / m);
|
|
53
|
+
return `${e} week${e === 1 ? "" : "s"} ago`;
|
|
54
|
+
}
|
|
55
|
+
if (n < g) return `${Math.round(n / h)} months ago`;
|
|
56
|
+
let r = n / g, i = Math.floor(r), a = r - i;
|
|
57
|
+
return a < .25 ? `about ${_(i)}` : a < .75 ? `over ${_(i)}` : `almost ${_(i + 1)}`;
|
|
58
|
+
}
|
|
59
|
+
var y = (e) => {
|
|
60
|
+
if (e == null) return null;
|
|
61
|
+
let t = typeof e == "number" ? e : Date.parse(e);
|
|
62
|
+
return Number.isFinite(t) ? t : null;
|
|
63
|
+
}, b = (e) => new Date(e).toISOString().slice(0, 10), x = (e) => {
|
|
64
|
+
try {
|
|
65
|
+
return new URL(e.includes("://") ? e : `https://${e}`).hostname.replace(/^www\./, "");
|
|
66
|
+
} catch {
|
|
67
|
+
return e;
|
|
68
|
+
}
|
|
69
|
+
}, S = (e, t, n) => {
|
|
70
|
+
switch (n) {
|
|
71
|
+
case "name": return e.name.localeCompare(t.name);
|
|
72
|
+
case "strength": return l[e.strength] - l[t.strength];
|
|
73
|
+
case "tags": return e.tags.length - t.tags.length;
|
|
74
|
+
case "lastInteraction": return (y(e.lastInteractionAt) ?? -Infinity) - (y(t.lastInteractionAt) ?? -Infinity);
|
|
75
|
+
default: return 0;
|
|
76
|
+
}
|
|
77
|
+
}, C = ({ direction: e }) => /* @__PURE__ */ o("svg", {
|
|
78
|
+
width: "12",
|
|
79
|
+
height: "12",
|
|
80
|
+
viewBox: "0 0 24 24",
|
|
81
|
+
fill: "none",
|
|
82
|
+
stroke: "currentColor",
|
|
83
|
+
strokeWidth: "2",
|
|
84
|
+
strokeLinecap: "round",
|
|
85
|
+
strokeLinejoin: "round",
|
|
86
|
+
"aria-hidden": "true",
|
|
87
|
+
children: [e !== "desc" && /* @__PURE__ */ a("path", {
|
|
88
|
+
d: "m7 10 5-5 5 5",
|
|
89
|
+
opacity: e === "asc" ? 1 : .4
|
|
90
|
+
}), e !== "asc" && /* @__PURE__ */ a("path", {
|
|
91
|
+
d: "m7 14 5 5 5-5",
|
|
92
|
+
opacity: e === "desc" ? 1 : .4
|
|
93
|
+
})]
|
|
94
|
+
}), w = ({ strength: t }) => {
|
|
95
|
+
let n = l[t];
|
|
96
|
+
return /* @__PURE__ */ a("span", {
|
|
97
|
+
className: "dishui-ai-records-table__signal",
|
|
98
|
+
"aria-hidden": "true",
|
|
99
|
+
children: Array.from({ length: 4 }, (t, r) => /* @__PURE__ */ a("span", { className: e("dishui-ai-records-table__bar", r < n && "dishui-ai-records-table__bar--on") }, r))
|
|
100
|
+
});
|
|
101
|
+
}, T = ({ label: t, sortKey: n, sort: r, onToggle: i, className: s }) => {
|
|
102
|
+
let c = r?.key === n ? r.direction : void 0;
|
|
103
|
+
return /* @__PURE__ */ a("th", {
|
|
104
|
+
scope: "col",
|
|
105
|
+
className: e("dishui-ai-records-table__th", s),
|
|
106
|
+
"aria-sort": c ? c === "asc" ? "ascending" : "descending" : "none",
|
|
107
|
+
children: /* @__PURE__ */ o("button", {
|
|
108
|
+
type: "button",
|
|
109
|
+
className: e("dishui-ai-records-table__sort", c && "dishui-ai-records-table__sort--active"),
|
|
110
|
+
onClick: () => i(n),
|
|
111
|
+
children: [/* @__PURE__ */ a("span", { children: t }), /* @__PURE__ */ a(C, { direction: c })]
|
|
112
|
+
})
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
function E({ records: l, sort: d, defaultSort: f = null, onSortChange: p, maxTags: m = 3, showIndex: h = !0, footer: g = !0, onRowClick: _, selectedId: C, stickyHeader: E = !1, maxHeight: D, now: O, emptyText: k, labels: A, className: j, style: M, ...N }) {
|
|
116
|
+
let P = {
|
|
117
|
+
...s,
|
|
118
|
+
...A
|
|
119
|
+
}, [F, I] = r(f), L = d === void 0 ? F : d, R = (e) => {
|
|
120
|
+
let t = L?.key === e ? L.direction === "asc" ? {
|
|
121
|
+
key: e,
|
|
122
|
+
direction: "desc"
|
|
123
|
+
} : null : {
|
|
124
|
+
key: e,
|
|
125
|
+
direction: "asc"
|
|
126
|
+
};
|
|
127
|
+
d === void 0 && I(t), p?.(t);
|
|
128
|
+
}, [z, B] = r(null);
|
|
129
|
+
t(() => {
|
|
130
|
+
if (O !== void 0) return;
|
|
131
|
+
let e = window.setTimeout(() => B(Date.now()), 0);
|
|
132
|
+
return () => window.clearTimeout(e);
|
|
133
|
+
}, [O]);
|
|
134
|
+
let V = O ?? z, H = n(() => {
|
|
135
|
+
if (!L) return l;
|
|
136
|
+
let e = L.direction === "asc" ? 1 : -1, t = l.map((e, t) => ({
|
|
137
|
+
r: e,
|
|
138
|
+
i: t
|
|
139
|
+
}));
|
|
140
|
+
return t.sort((t, n) => S(t.r, n.r, L.key) * e || t.i - n.i), t.map((e) => e.r);
|
|
141
|
+
}, [l, L]), U = n(() => {
|
|
142
|
+
let e = l.length;
|
|
143
|
+
return {
|
|
144
|
+
count: e,
|
|
145
|
+
avg: e ? Math.round(l.reduce((e, t) => e + u(t.strength), 0) / e) : 0,
|
|
146
|
+
links: l.filter((e) => e.link).length
|
|
147
|
+
};
|
|
148
|
+
}, [l]), W = !!_, G = D === void 0 ? void 0 : { maxHeight: D };
|
|
149
|
+
return /* @__PURE__ */ a("div", {
|
|
150
|
+
...N,
|
|
151
|
+
style: M,
|
|
152
|
+
className: e("dishui-ai-records-table", E && "dishui-ai-records-table--sticky", j),
|
|
153
|
+
children: /* @__PURE__ */ a("div", {
|
|
154
|
+
className: "dishui-ai-records-table__scroll",
|
|
155
|
+
style: G,
|
|
156
|
+
children: /* @__PURE__ */ o("table", {
|
|
157
|
+
className: "dishui-ai-records-table__table",
|
|
158
|
+
children: [
|
|
159
|
+
/* @__PURE__ */ a("thead", { children: /* @__PURE__ */ o("tr", { children: [
|
|
160
|
+
h && /* @__PURE__ */ a("th", {
|
|
161
|
+
scope: "col",
|
|
162
|
+
className: "dishui-ai-records-table__th dishui-ai-records-table__th--index",
|
|
163
|
+
children: P.index
|
|
164
|
+
}),
|
|
165
|
+
/* @__PURE__ */ a(T, {
|
|
166
|
+
label: P.company,
|
|
167
|
+
sortKey: "name",
|
|
168
|
+
sort: L,
|
|
169
|
+
onToggle: R
|
|
170
|
+
}),
|
|
171
|
+
/* @__PURE__ */ a(T, {
|
|
172
|
+
label: P.categories,
|
|
173
|
+
sortKey: "tags",
|
|
174
|
+
sort: L,
|
|
175
|
+
onToggle: R
|
|
176
|
+
}),
|
|
177
|
+
/* @__PURE__ */ a(T, {
|
|
178
|
+
label: P.lastInteraction,
|
|
179
|
+
sortKey: "lastInteraction",
|
|
180
|
+
sort: L,
|
|
181
|
+
onToggle: R
|
|
182
|
+
}),
|
|
183
|
+
/* @__PURE__ */ a(T, {
|
|
184
|
+
label: P.strength,
|
|
185
|
+
sortKey: "strength",
|
|
186
|
+
sort: L,
|
|
187
|
+
onToggle: R
|
|
188
|
+
}),
|
|
189
|
+
/* @__PURE__ */ a("th", {
|
|
190
|
+
scope: "col",
|
|
191
|
+
className: "dishui-ai-records-table__th",
|
|
192
|
+
children: P.links
|
|
193
|
+
})
|
|
194
|
+
] }) }),
|
|
195
|
+
/* @__PURE__ */ o("tbody", { children: [H.length === 0 && /* @__PURE__ */ a("tr", { children: /* @__PURE__ */ a("td", {
|
|
196
|
+
className: "dishui-ai-records-table__td dishui-ai-records-table__td--empty",
|
|
197
|
+
colSpan: h ? 6 : 5,
|
|
198
|
+
children: k ?? P.empty
|
|
199
|
+
}) }), H.map((t, n) => {
|
|
200
|
+
let r = y(t.lastInteractionAt), i = t.tags.slice(0, m), s = t.tags.slice(m), l = C === t.id;
|
|
201
|
+
return /* @__PURE__ */ o("tr", {
|
|
202
|
+
className: e("dishui-ai-records-table__row", W && "dishui-ai-records-table__row--interactive", l && "dishui-ai-records-table__row--selected"),
|
|
203
|
+
"data-selected": l || void 0,
|
|
204
|
+
tabIndex: W ? 0 : void 0,
|
|
205
|
+
onClick: W ? () => _?.(t) : void 0,
|
|
206
|
+
onKeyDown: W ? (e) => {
|
|
207
|
+
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), _?.(t));
|
|
208
|
+
} : void 0,
|
|
209
|
+
children: [
|
|
210
|
+
h && /* @__PURE__ */ a("td", {
|
|
211
|
+
className: "dishui-ai-records-table__td dishui-ai-records-table__td--index",
|
|
212
|
+
children: n + 1
|
|
213
|
+
}),
|
|
214
|
+
/* @__PURE__ */ o("td", {
|
|
215
|
+
className: "dishui-ai-records-table__td dishui-ai-records-table__td--company",
|
|
216
|
+
children: [/* @__PURE__ */ a("span", {
|
|
217
|
+
className: "dishui-ai-records-table__avatar",
|
|
218
|
+
"aria-hidden": "true",
|
|
219
|
+
children: t.avatar ?? t.name.trim().charAt(0).toUpperCase()
|
|
220
|
+
}), /* @__PURE__ */ o("span", {
|
|
221
|
+
className: "dishui-ai-records-table__name",
|
|
222
|
+
children: [t.name, t.location && /* @__PURE__ */ o("span", {
|
|
223
|
+
className: "dishui-ai-records-table__location",
|
|
224
|
+
children: [" — ", t.location]
|
|
225
|
+
})]
|
|
226
|
+
})]
|
|
227
|
+
}),
|
|
228
|
+
/* @__PURE__ */ a("td", {
|
|
229
|
+
className: "dishui-ai-records-table__td",
|
|
230
|
+
children: /* @__PURE__ */ o("span", {
|
|
231
|
+
className: "dishui-ai-records-table__tags",
|
|
232
|
+
children: [
|
|
233
|
+
i.map((e) => /* @__PURE__ */ a("span", {
|
|
234
|
+
className: "dishui-ai-records-table__tag",
|
|
235
|
+
children: e
|
|
236
|
+
}, e)),
|
|
237
|
+
s.length > 0 && /* @__PURE__ */ o("span", {
|
|
238
|
+
className: "dishui-ai-records-table__tag dishui-ai-records-table__tag--more",
|
|
239
|
+
title: s.join(", "),
|
|
240
|
+
children: ["+", s.length]
|
|
241
|
+
}),
|
|
242
|
+
t.tags.length === 0 && /* @__PURE__ */ a("span", {
|
|
243
|
+
className: "dishui-ai-records-table__muted",
|
|
244
|
+
children: "—"
|
|
245
|
+
})
|
|
246
|
+
]
|
|
247
|
+
})
|
|
248
|
+
}),
|
|
249
|
+
/* @__PURE__ */ a("td", {
|
|
250
|
+
className: e("dishui-ai-records-table__td dishui-ai-records-table__td--time", r === null && "dishui-ai-records-table__td--muted"),
|
|
251
|
+
children: r === null ? P.noContact : V === null ? b(r) : /* @__PURE__ */ a("time", {
|
|
252
|
+
dateTime: new Date(r).toISOString(),
|
|
253
|
+
title: b(r),
|
|
254
|
+
children: v(r, V)
|
|
255
|
+
})
|
|
256
|
+
}),
|
|
257
|
+
/* @__PURE__ */ o("td", {
|
|
258
|
+
className: e("dishui-ai-records-table__td dishui-ai-records-table__td--strength", `dishui-ai-records-table__td--${t.strength}`),
|
|
259
|
+
children: [/* @__PURE__ */ a(w, { strength: t.strength }), /* @__PURE__ */ a("span", { children: c[t.strength] })]
|
|
260
|
+
}),
|
|
261
|
+
/* @__PURE__ */ a("td", {
|
|
262
|
+
className: "dishui-ai-records-table__td",
|
|
263
|
+
children: t.link ? /* @__PURE__ */ a("a", {
|
|
264
|
+
className: "dishui-ai-records-table__link",
|
|
265
|
+
href: t.link.includes("://") ? t.link : `https://${t.link}`,
|
|
266
|
+
target: "_blank",
|
|
267
|
+
rel: "noreferrer",
|
|
268
|
+
onClick: (e) => e.stopPropagation(),
|
|
269
|
+
children: x(t.link)
|
|
270
|
+
}) : /* @__PURE__ */ a("span", {
|
|
271
|
+
className: "dishui-ai-records-table__muted",
|
|
272
|
+
children: "—"
|
|
273
|
+
})
|
|
274
|
+
})
|
|
275
|
+
]
|
|
276
|
+
}, t.id);
|
|
277
|
+
})] }),
|
|
278
|
+
g && /* @__PURE__ */ a("tfoot", { children: /* @__PURE__ */ a("tr", { children: g === !0 ? /* @__PURE__ */ o(i, { children: [
|
|
279
|
+
h && /* @__PURE__ */ a("td", { className: "dishui-ai-records-table__tf dishui-ai-records-table__td--index" }),
|
|
280
|
+
/* @__PURE__ */ o("td", {
|
|
281
|
+
className: "dishui-ai-records-table__tf",
|
|
282
|
+
children: [
|
|
283
|
+
/* @__PURE__ */ a("span", {
|
|
284
|
+
className: "dishui-ai-records-table__num",
|
|
285
|
+
children: U.count
|
|
286
|
+
}),
|
|
287
|
+
" ",
|
|
288
|
+
P.count
|
|
289
|
+
]
|
|
290
|
+
}),
|
|
291
|
+
/* @__PURE__ */ a("td", {
|
|
292
|
+
className: "dishui-ai-records-table__tf dishui-ai-records-table__tf--muted",
|
|
293
|
+
children: P.addCalculation
|
|
294
|
+
}),
|
|
295
|
+
/* @__PURE__ */ a("td", {
|
|
296
|
+
className: "dishui-ai-records-table__tf dishui-ai-records-table__tf--muted",
|
|
297
|
+
children: "—"
|
|
298
|
+
}),
|
|
299
|
+
/* @__PURE__ */ o("td", {
|
|
300
|
+
className: "dishui-ai-records-table__tf",
|
|
301
|
+
children: [
|
|
302
|
+
/* @__PURE__ */ o("span", {
|
|
303
|
+
className: "dishui-ai-records-table__num",
|
|
304
|
+
children: [U.avg, "%"]
|
|
305
|
+
}),
|
|
306
|
+
" ",
|
|
307
|
+
P.average
|
|
308
|
+
]
|
|
309
|
+
}),
|
|
310
|
+
/* @__PURE__ */ o("td", {
|
|
311
|
+
className: "dishui-ai-records-table__tf",
|
|
312
|
+
children: [
|
|
313
|
+
/* @__PURE__ */ a("span", {
|
|
314
|
+
className: "dishui-ai-records-table__num",
|
|
315
|
+
children: U.links
|
|
316
|
+
}),
|
|
317
|
+
" ",
|
|
318
|
+
P.linksCount
|
|
319
|
+
]
|
|
320
|
+
})
|
|
321
|
+
] }) : /* @__PURE__ */ a("td", {
|
|
322
|
+
className: "dishui-ai-records-table__tf",
|
|
323
|
+
colSpan: h ? 6 : 5,
|
|
324
|
+
children: g
|
|
325
|
+
}) }) })
|
|
326
|
+
]
|
|
327
|
+
})
|
|
328
|
+
})
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
//#endregion
|
|
332
|
+
export { c as STRENGTH_LABEL, E as default, v as formatRelativeTime, u as strengthPercent };
|
|
333
|
+
|
|
334
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/RecordsTable/index.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport './RecordsTable.css';\n\nexport type RecordStrength = 'very-strong' | 'strong' | 'weak' | 'very-weak' | 'none';\n\nexport type RecordRow = {\n id: string;\n name: string;\n location?: string;\n avatar?: React.ReactNode;\n tags: string[];\n /** Epoch ms or ISO string; `null`/undefined = no contact yet. */\n lastInteractionAt?: number | string | null;\n strength: RecordStrength;\n link?: string | null;\n};\n\nexport type RecordsSortKey = 'name' | 'lastInteraction' | 'strength' | 'tags';\nexport type RecordsSort = { key: RecordsSortKey; direction: 'asc' | 'desc' };\n\nexport type RecordsTableProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {\n records: RecordRow[];\n sort?: RecordsSort | null;\n defaultSort?: RecordsSort | null;\n onSortChange?: (sort: RecordsSort | null) => void;\n /** Tags shown before collapsing into a `+n` chip. */\n maxTags?: number;\n showIndex?: boolean;\n /** `true` computes count / average strength / link count; a node replaces it. */\n footer?: boolean | React.ReactNode;\n onRowClick?: (record: RecordRow) => void;\n selectedId?: string | null;\n stickyHeader?: boolean;\n maxHeight?: string | number;\n /** Reference time for relative dates. Defaults to mount time (set in an effect). */\n now?: number;\n emptyText?: React.ReactNode;\n labels?: Partial<typeof DEFAULT_LABELS>;\n};\n\nconst DEFAULT_LABELS = {\n index: '#',\n company: 'Company',\n categories: 'Categories',\n lastInteraction: 'Last interaction',\n strength: 'Connection strength',\n links: 'Links',\n noContact: 'No contact',\n count: 'count',\n average: 'average',\n linksCount: 'links',\n addCalculation: 'Add calculation',\n empty: 'No records',\n};\n\nexport const STRENGTH_LABEL: Record<RecordStrength, string> = {\n 'very-strong': 'Very strong',\n strong: 'Strong',\n weak: 'Weak',\n 'very-weak': 'Very weak',\n none: 'No communication',\n};\n\nconst STRENGTH_BARS: Record<RecordStrength, number> = { none: 0, 'very-weak': 1, weak: 2, strong: 3, 'very-strong': 4 };\n\n/** none 0 / very-weak 25 / weak 50 / strong 75 / very-strong 100. */\nexport function strengthPercent(strength: RecordStrength): number {\n return STRENGTH_BARS[strength] * 25;\n}\n\nconst MINUTE = 60_000;\nconst HOUR = 60 * MINUTE;\nconst DAY = 24 * HOUR;\nconst WEEK = 7 * DAY;\nconst MONTH = 30.44 * DAY;\nconst YEAR = 365.25 * DAY;\nconst yearLabel = (n: number) => `${n} year${n === 1 ? '' : 's'} ago`;\n\n/**\n * date-fns-like relative buckets: `just now`, `4 days ago`, `5 weeks ago`,\n * `11 months ago`, `about 1 year ago`, `over 1 year ago`, `almost 2 years ago`.\n */\nexport function formatRelativeTime(from: number, now: number): string {\n const diff = Math.max(0, now - from);\n if (diff < MINUTE) return 'just now';\n if (diff < HOUR) {\n const m = Math.round(diff / MINUTE);\n return `${m} minute${m === 1 ? '' : 's'} ago`;\n }\n if (diff < DAY) {\n const h = Math.round(diff / HOUR);\n return `${h} hour${h === 1 ? '' : 's'} ago`;\n }\n if (diff < WEEK) {\n const d = Math.round(diff / DAY);\n return d <= 1 ? 'yesterday' : `${d} days ago`;\n }\n if (diff < 2 * MONTH) {\n const w = Math.round(diff / WEEK);\n return `${w} week${w === 1 ? '' : 's'} ago`;\n }\n if (diff < YEAR) {\n const mo = Math.round(diff / MONTH);\n return `${mo} months ago`;\n }\n const years = diff / YEAR;\n const whole = Math.floor(years);\n const frac = years - whole;\n if (frac < 0.25) return `about ${yearLabel(whole)}`;\n if (frac < 0.75) return `over ${yearLabel(whole)}`;\n return `almost ${yearLabel(whole + 1)}`;\n}\n\nconst toEpoch = (value: number | string | null | undefined): number | null => {\n if (value === null || value === undefined) return null;\n const t = typeof value === 'number' ? value : Date.parse(value);\n return Number.isFinite(t) ? t : null;\n};\n\nconst formatAbsolute = (t: number) => new Date(t).toISOString().slice(0, 10);\n\nconst hostOf = (url: string) => {\n try {\n return new URL(url.includes('://') ? url : `https://${url}`).hostname.replace(/^www\\./, '');\n } catch {\n return url;\n }\n};\n\nconst compare = (a: RecordRow, b: RecordRow, key: RecordsSortKey): number => {\n switch (key) {\n case 'name':\n return a.name.localeCompare(b.name);\n case 'strength':\n return STRENGTH_BARS[a.strength] - STRENGTH_BARS[b.strength];\n case 'tags':\n return a.tags.length - b.tags.length;\n case 'lastInteraction': {\n const ta = toEpoch(a.lastInteractionAt) ?? Number.NEGATIVE_INFINITY;\n const tb = toEpoch(b.lastInteractionAt) ?? Number.NEGATIVE_INFINITY;\n return ta - tb;\n }\n default:\n return 0;\n }\n};\n\nconst SortIcon: React.FC<{ direction?: 'asc' | 'desc' }> = ({ direction }) => (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n {direction !== 'desc' && <path d=\"m7 10 5-5 5 5\" opacity={direction === 'asc' ? 1 : 0.4} />}\n {direction !== 'asc' && <path d=\"m7 14 5 5 5-5\" opacity={direction === 'desc' ? 1 : 0.4} />}\n </svg>\n);\n\nconst StrengthGlyph: React.FC<{ strength: RecordStrength }> = ({ strength }) => {\n const bars = STRENGTH_BARS[strength];\n return (\n <span className=\"dishui-ai-records-table__signal\" aria-hidden=\"true\">\n {Array.from({ length: 4 }, (_, i) => (\n <span key={i} className={cn('dishui-ai-records-table__bar', i < bars && 'dishui-ai-records-table__bar--on')} />\n ))}\n </span>\n );\n};\n\ntype SortableHeaderProps = {\n label: React.ReactNode;\n sortKey: RecordsSortKey;\n sort: RecordsSort | null;\n onToggle: (key: RecordsSortKey) => void;\n className?: string;\n};\n\nconst SortableHeader: React.FC<SortableHeaderProps> = ({ label, sortKey, sort, onToggle, className }) => {\n const active = sort?.key === sortKey ? sort.direction : undefined;\n return (\n <th\n scope=\"col\"\n className={cn('dishui-ai-records-table__th', className)}\n aria-sort={active ? (active === 'asc' ? 'ascending' : 'descending') : 'none'}\n >\n <button\n type=\"button\"\n className={cn('dishui-ai-records-table__sort', active && 'dishui-ai-records-table__sort--active')}\n onClick={() => onToggle(sortKey)}\n >\n <span>{label}</span>\n <SortIcon direction={active} />\n </button>\n </th>\n );\n};\n\n/**\n * CRM-style grid with tag chips, sortable columns, relative interaction\n * dates and a 4-bar connection-strength glyph paired with its label.\n */\nexport default function RecordsTable({\n records,\n sort: sortProp,\n defaultSort = null,\n onSortChange,\n maxTags = 3,\n showIndex = true,\n footer = true,\n onRowClick,\n selectedId,\n stickyHeader = false,\n maxHeight,\n now: nowProp,\n emptyText,\n labels: labelOverrides,\n className,\n style,\n ...rest\n}: RecordsTableProps) {\n const labels = { ...DEFAULT_LABELS, ...labelOverrides };\n\n const [internalSort, setInternalSort] = useState<RecordsSort | null>(defaultSort);\n const sort = sortProp !== undefined ? sortProp : internalSort;\n const toggleSort = (key: RecordsSortKey) => {\n const next: RecordsSort | null =\n sort?.key !== key ? { key, direction: 'asc' } : sort.direction === 'asc' ? { key, direction: 'desc' } : null;\n if (sortProp === undefined) setInternalSort(next);\n onSortChange?.(next);\n };\n\n // Relative times need a reference \"now\"; never read the clock during render.\n const [mountNow, setMountNow] = useState<number | null>(null);\n useEffect(() => {\n if (nowProp !== undefined) return;\n const id = window.setTimeout(() => setMountNow(Date.now()), 0);\n return () => window.clearTimeout(id);\n }, [nowProp]);\n const now = nowProp ?? mountNow;\n\n const sorted = useMemo(() => {\n if (!sort) return records;\n const dir = sort.direction === 'asc' ? 1 : -1;\n const indexed = records.map((r, i) => ({ r, i }));\n // The copied array is intentionally sorted in place; `records` is never mutated.\n // eslint-disable-next-line unicorn/no-array-sort\n indexed.sort((a, b) => compare(a.r, b.r, sort.key) * dir || a.i - b.i);\n return indexed.map(x => x.r);\n }, [records, sort]);\n\n const stats = useMemo(() => {\n const count = records.length;\n const avg = count ? Math.round(records.reduce((n, r) => n + strengthPercent(r.strength), 0) / count) : 0;\n const links = records.filter(r => r.link).length;\n return { count, avg, links };\n }, [records]);\n\n const interactive = Boolean(onRowClick);\n const scrollStyle: React.CSSProperties | undefined = maxHeight !== undefined ? { maxHeight } : undefined;\n\n return (\n <div {...rest} style={style} className={cn('dishui-ai-records-table', stickyHeader && 'dishui-ai-records-table--sticky', className)}>\n <div className=\"dishui-ai-records-table__scroll\" style={scrollStyle}>\n <table className=\"dishui-ai-records-table__table\">\n <thead>\n <tr>\n {showIndex && <th scope=\"col\" className=\"dishui-ai-records-table__th dishui-ai-records-table__th--index\">{labels.index}</th>}\n <SortableHeader label={labels.company} sortKey=\"name\" sort={sort} onToggle={toggleSort} />\n <SortableHeader label={labels.categories} sortKey=\"tags\" sort={sort} onToggle={toggleSort} />\n <SortableHeader label={labels.lastInteraction} sortKey=\"lastInteraction\" sort={sort} onToggle={toggleSort} />\n <SortableHeader label={labels.strength} sortKey=\"strength\" sort={sort} onToggle={toggleSort} />\n <th scope=\"col\" className=\"dishui-ai-records-table__th\">{labels.links}</th>\n </tr>\n </thead>\n <tbody>\n {sorted.length === 0 && (\n <tr>\n <td className=\"dishui-ai-records-table__td dishui-ai-records-table__td--empty\" colSpan={showIndex ? 6 : 5}>\n {emptyText ?? labels.empty}\n </td>\n </tr>\n )}\n {sorted.map((record, i) => {\n const t = toEpoch(record.lastInteractionAt);\n const shown = record.tags.slice(0, maxTags);\n const hiddenTags = record.tags.slice(maxTags);\n const selected = selectedId === record.id;\n return (\n <tr\n key={record.id}\n className={cn(\n 'dishui-ai-records-table__row',\n interactive && 'dishui-ai-records-table__row--interactive',\n selected && 'dishui-ai-records-table__row--selected',\n )}\n data-selected={selected || undefined}\n tabIndex={interactive ? 0 : undefined}\n onClick={interactive ? () => onRowClick?.(record) : undefined}\n onKeyDown={\n interactive\n ? e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onRowClick?.(record);\n }\n }\n : undefined\n }\n >\n {showIndex && <td className=\"dishui-ai-records-table__td dishui-ai-records-table__td--index\">{i + 1}</td>}\n <td className=\"dishui-ai-records-table__td dishui-ai-records-table__td--company\">\n <span className=\"dishui-ai-records-table__avatar\" aria-hidden=\"true\">\n {record.avatar ?? record.name.trim().charAt(0).toUpperCase()}\n </span>\n <span className=\"dishui-ai-records-table__name\">\n {record.name}\n {record.location && <span className=\"dishui-ai-records-table__location\"> — {record.location}</span>}\n </span>\n </td>\n <td className=\"dishui-ai-records-table__td\">\n <span className=\"dishui-ai-records-table__tags\">\n {shown.map(tag => (\n <span key={tag} className=\"dishui-ai-records-table__tag\">{tag}</span>\n ))}\n {hiddenTags.length > 0 && (\n <span className=\"dishui-ai-records-table__tag dishui-ai-records-table__tag--more\" title={hiddenTags.join(', ')}>\n +{hiddenTags.length}\n </span>\n )}\n {record.tags.length === 0 && <span className=\"dishui-ai-records-table__muted\">—</span>}\n </span>\n </td>\n <td className={cn('dishui-ai-records-table__td dishui-ai-records-table__td--time', t === null && 'dishui-ai-records-table__td--muted')}>\n {t === null ? labels.noContact : now === null ? formatAbsolute(t) : <time dateTime={new Date(t).toISOString()} title={formatAbsolute(t)}>{formatRelativeTime(t, now)}</time>}\n </td>\n <td className={cn('dishui-ai-records-table__td dishui-ai-records-table__td--strength', `dishui-ai-records-table__td--${record.strength}`)}>\n <StrengthGlyph strength={record.strength} />\n <span>{STRENGTH_LABEL[record.strength]}</span>\n </td>\n <td className=\"dishui-ai-records-table__td\">\n {record.link ? (\n <a\n className=\"dishui-ai-records-table__link\"\n href={record.link.includes('://') ? record.link : `https://${record.link}`}\n target=\"_blank\"\n rel=\"noreferrer\"\n onClick={e => e.stopPropagation()}\n >\n {hostOf(record.link)}\n </a>\n ) : (\n <span className=\"dishui-ai-records-table__muted\">—</span>\n )}\n </td>\n </tr>\n );\n })}\n </tbody>\n {footer && (\n <tfoot>\n <tr>\n {footer === true ? (\n <>\n {showIndex && <td className=\"dishui-ai-records-table__tf dishui-ai-records-table__td--index\" />}\n <td className=\"dishui-ai-records-table__tf\"><span className=\"dishui-ai-records-table__num\">{stats.count}</span> {labels.count}</td>\n <td className=\"dishui-ai-records-table__tf dishui-ai-records-table__tf--muted\">{labels.addCalculation}</td>\n <td className=\"dishui-ai-records-table__tf dishui-ai-records-table__tf--muted\">—</td>\n <td className=\"dishui-ai-records-table__tf\"><span className=\"dishui-ai-records-table__num\">{stats.avg}%</span> {labels.average}</td>\n <td className=\"dishui-ai-records-table__tf\"><span className=\"dishui-ai-records-table__num\">{stats.links}</span> {labels.linksCount}</td>\n </>\n ) : (\n <td className=\"dishui-ai-records-table__tf\" colSpan={showIndex ? 6 : 5}>{footer}</td>\n )}\n </tr>\n </tfoot>\n )}\n </table>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type SelectionAction = {
|
|
3
|
+
id: string;
|
|
4
|
+
label: React.ReactNode;
|
|
5
|
+
icon?: React.ReactNode;
|
|
6
|
+
onSelect: () => void;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
disabledReason?: string;
|
|
9
|
+
destructive?: boolean;
|
|
10
|
+
};
|
|
11
|
+
export type SelectionActionsProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {
|
|
12
|
+
count: number;
|
|
13
|
+
actions: SelectionAction[];
|
|
14
|
+
onClear?: () => void;
|
|
15
|
+
selectionLabel?: (count: number) => React.ReactNode;
|
|
16
|
+
clearLabel?: string;
|
|
17
|
+
sticky?: boolean;
|
|
18
|
+
};
|
|
19
|
+
export default function SelectionActions({ count, actions, onClear, selectionLabel, clearLabel, sticky, className, ...rest }: SelectionActionsProps): React.JSX.Element | null;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { cn as e } from "../../../utils/cn.js";
|
|
2
|
+
/* empty css */
|
|
3
|
+
import "react";
|
|
4
|
+
import { jsx as t, jsxs as n } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/ai/SelectionActions/index.tsx
|
|
6
|
+
var r = (e) => `${e} selected`;
|
|
7
|
+
function i({ count: i, actions: a, onClear: o, selectionLabel: s = r, clearLabel: c = "Clear selection", sticky: l = !1, className: u, ...d }) {
|
|
8
|
+
return i <= 0 ? null : /* @__PURE__ */ n("div", {
|
|
9
|
+
...d,
|
|
10
|
+
className: e("dishui-ai-selection-actions", l && "dishui-ai-selection-actions--sticky", u),
|
|
11
|
+
role: "toolbar",
|
|
12
|
+
"aria-label": "Selection actions",
|
|
13
|
+
children: [
|
|
14
|
+
/* @__PURE__ */ t("strong", { children: s(i) }),
|
|
15
|
+
/* @__PURE__ */ t("span", {
|
|
16
|
+
className: "dishui-ai-selection-actions__divider",
|
|
17
|
+
"aria-hidden": "true"
|
|
18
|
+
}),
|
|
19
|
+
a.map((r) => /* @__PURE__ */ n("button", {
|
|
20
|
+
type: "button",
|
|
21
|
+
className: e(r.destructive && "dishui-ai-selection-actions__action--destructive"),
|
|
22
|
+
disabled: r.disabled,
|
|
23
|
+
title: r.disabledReason,
|
|
24
|
+
onClick: r.onSelect,
|
|
25
|
+
children: [r.icon, /* @__PURE__ */ t("span", { children: r.label })]
|
|
26
|
+
}, r.id)),
|
|
27
|
+
o && /* @__PURE__ */ t("button", {
|
|
28
|
+
type: "button",
|
|
29
|
+
className: "dishui-ai-selection-actions__clear",
|
|
30
|
+
onClick: o,
|
|
31
|
+
"aria-label": c,
|
|
32
|
+
children: "×"
|
|
33
|
+
})
|
|
34
|
+
]
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { i as default };
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/SelectionActions/index.tsx"],"sourcesContent":["import React from 'react';\nimport { cn } from '../../../utils/cn';\nimport './SelectionActions.css';\n\nexport type SelectionAction = { id: string; label: React.ReactNode; icon?: React.ReactNode; onSelect: () => void; disabled?: boolean; disabledReason?: string; destructive?: boolean };\nexport type SelectionActionsProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & { count: number; actions: SelectionAction[]; onClear?: () => void; selectionLabel?: (count: number) => React.ReactNode; clearLabel?: string; sticky?: boolean };\nconst defaultSelectionLabel = (count: number) => `${count} selected`;\nexport default function SelectionActions({ count, actions, onClear, selectionLabel = defaultSelectionLabel, clearLabel = 'Clear selection', sticky = false, className, ...rest }: SelectionActionsProps) {\n if (count <= 0) return null;\n return <div {...rest} className={cn('dishui-ai-selection-actions', sticky && 'dishui-ai-selection-actions--sticky', className)} role=\"toolbar\" aria-label=\"Selection actions\"><strong>{selectionLabel(count)}</strong><span className=\"dishui-ai-selection-actions__divider\" aria-hidden=\"true\"/>{actions.map(action => <button key={action.id} type=\"button\" className={cn(action.destructive && 'dishui-ai-selection-actions__action--destructive')} disabled={action.disabled} title={action.disabledReason} onClick={action.onSelect}>{action.icon}<span>{action.label}</span></button>)}{onClear && <button type=\"button\" className=\"dishui-ai-selection-actions__clear\" onClick={onClear} aria-label={clearLabel}>×</button>}</div>;\n}\n"],"mappings":";;;;;AAMA,IAAM,KAAyB,MAAkB,GAAG,EAAM;AAC1D,SAAwB,EAAiB,EAAE,UAAO,YAAS,YAAS,oBAAiB,GAAuB,gBAAa,mBAAmB,YAAS,IAAO,cAAW,GAAG,KAA+B;CAEvM,OADI,KAAS,IAAU,OAChB,kBAAC,OAAD;EAAK,GAAI;EAAM,WAAW,EAAG,+BAA+B,KAAU,uCAAuC,CAAS;EAAG,MAAK;EAAU,cAAW;EAAnJ,UAAA;GAAuK,kBAAC,UAAD,EAAA,UAAS,EAAe,CAAK,EAAU,CAAA;GAAC,kBAAC,QAAD;IAAM,WAAU;IAAuC,eAAY;GAAO,CAAA;GAAE,EAAQ,KAAI,MAAU,kBAAC,UAAD;IAAwB,MAAK;IAAS,WAAW,EAAG,EAAO,eAAe,kDAAkD;IAAG,UAAU,EAAO;IAAU,OAAO,EAAO;IAAgB,SAAS,EAAO;IAAxM,UAAA,CAAmN,EAAO,MAAK,kBAAC,QAAD,EAAA,UAAO,EAAO,MAAY,CAAA,CAAS;GAArP,GAAA,EAAO,EAA8O,CAAC;GAAG,KAAW,kBAAC,UAAD;IAAQ,MAAK;IAAS,WAAU;IAAqC,SAAS;IAAS,cAAY;IAAY,UAAA;GAAS,CAAA;EAAO;;AAC1sB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type StateFlowNode = {
|
|
3
|
+
id: string;
|
|
4
|
+
label: React.ReactNode;
|
|
5
|
+
description?: React.ReactNode;
|
|
6
|
+
status?: 'pending' | 'running' | 'completed' | 'failed';
|
|
7
|
+
shape?: 'process' | 'decision' | 'terminal';
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
};
|
|
10
|
+
export type StateFlowEdge = {
|
|
11
|
+
from: string;
|
|
12
|
+
to: string;
|
|
13
|
+
label?: React.ReactNode;
|
|
14
|
+
};
|
|
15
|
+
export type StateFlowProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'onSelect'> & {
|
|
16
|
+
nodes: StateFlowNode[];
|
|
17
|
+
edges: StateFlowEdge[];
|
|
18
|
+
selectedId?: string;
|
|
19
|
+
defaultSelectedId?: string;
|
|
20
|
+
onSelect?: (node: StateFlowNode) => void;
|
|
21
|
+
direction?: 'vertical' | 'horizontal';
|
|
22
|
+
emptyText?: React.ReactNode;
|
|
23
|
+
};
|
|
24
|
+
export default function StateFlow({ nodes, edges, selectedId, defaultSelectedId, onSelect, direction, emptyText, className, ...rest }: StateFlowProps): React.JSX.Element;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { cn as e } from "../../../utils/cn.js";
|
|
2
|
+
/* empty css */
|
|
3
|
+
import t, { useId as n, useMemo as r, useState as i } from "react";
|
|
4
|
+
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/ai/StateFlow/index.tsx
|
|
6
|
+
function s({ nodes: s, edges: c, selectedId: l, defaultSelectedId: u, onSelect: d, direction: f = "vertical", emptyText: p = "No steps in this flow", className: m, ...h }) {
|
|
7
|
+
let g = n(), [_, v] = i(u), y = l ?? _, b = r(() => {
|
|
8
|
+
let e = /* @__PURE__ */ new Map();
|
|
9
|
+
return c.forEach((t) => e.set(t.to, [...e.get(t.to) ?? [], t])), e;
|
|
10
|
+
}, [c]);
|
|
11
|
+
if (!s.length) return /* @__PURE__ */ a("div", {
|
|
12
|
+
...h,
|
|
13
|
+
className: e("dishui-ai-state-flow dishui-ai-state-flow--empty", m),
|
|
14
|
+
children: p
|
|
15
|
+
});
|
|
16
|
+
let x = (e) => {
|
|
17
|
+
e.disabled || (l === void 0 && v(e.id), d?.(e));
|
|
18
|
+
};
|
|
19
|
+
return /* @__PURE__ */ a("div", {
|
|
20
|
+
...h,
|
|
21
|
+
className: e("dishui-ai-state-flow", `dishui-ai-state-flow--${f}`, m),
|
|
22
|
+
role: "list",
|
|
23
|
+
"aria-label": "Workflow",
|
|
24
|
+
children: s.map((n, r) => /* @__PURE__ */ o(t.Fragment, { children: [r > 0 && /* @__PURE__ */ o("div", {
|
|
25
|
+
className: "dishui-ai-state-flow__connector",
|
|
26
|
+
"aria-hidden": "true",
|
|
27
|
+
children: [/* @__PURE__ */ a("span", { children: "↓" }), (b.get(n.id) ?? []).map((e) => e.label && /* @__PURE__ */ a("small", { children: e.label }, `${e.from}-${e.to}`))]
|
|
28
|
+
}), /* @__PURE__ */ o("button", {
|
|
29
|
+
type: "button",
|
|
30
|
+
id: `${g}-${n.id}`,
|
|
31
|
+
role: "listitem",
|
|
32
|
+
disabled: n.disabled,
|
|
33
|
+
"aria-current": y === n.id ? "step" : void 0,
|
|
34
|
+
className: e("dishui-ai-state-flow__node", `dishui-ai-state-flow__node--${n.shape ?? "process"}`, n.status && `dishui-ai-state-flow__node--${n.status}`, y === n.id && "dishui-ai-state-flow__node--selected"),
|
|
35
|
+
onClick: () => x(n),
|
|
36
|
+
children: [
|
|
37
|
+
/* @__PURE__ */ a("span", {
|
|
38
|
+
className: "dishui-ai-state-flow__status",
|
|
39
|
+
children: n.status ?? "step"
|
|
40
|
+
}),
|
|
41
|
+
/* @__PURE__ */ a("strong", { children: n.label }),
|
|
42
|
+
n.description && /* @__PURE__ */ a("small", { children: n.description })
|
|
43
|
+
]
|
|
44
|
+
})] }, n.id))
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
export { s as default };
|
|
49
|
+
|
|
50
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/StateFlow/index.tsx"],"sourcesContent":["import React, { useId, useMemo, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport './StateFlow.css';\n\nexport type StateFlowNode = { id: string; label: React.ReactNode; description?: React.ReactNode; status?: 'pending' | 'running' | 'completed' | 'failed'; shape?: 'process' | 'decision' | 'terminal'; disabled?: boolean };\nexport type StateFlowEdge = { from: string; to: string; label?: React.ReactNode };\nexport type StateFlowProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'onSelect'> & { nodes: StateFlowNode[]; edges: StateFlowEdge[]; selectedId?: string; defaultSelectedId?: string; onSelect?: (node: StateFlowNode) => void; direction?: 'vertical' | 'horizontal'; emptyText?: React.ReactNode };\n\nexport default function StateFlow({ nodes, edges, selectedId, defaultSelectedId, onSelect, direction = 'vertical', emptyText = 'No steps in this flow', className, ...rest }: StateFlowProps) {\n const uid = useId(); const [internal, setInternal] = useState(defaultSelectedId); const selected = selectedId ?? internal;\n const incoming = useMemo(() => { const map = new Map<string, StateFlowEdge[]>(); edges.forEach(edge => map.set(edge.to, [...(map.get(edge.to) ?? []), edge])); return map; }, [edges]);\n if (!nodes.length) return <div {...rest} className={cn('dishui-ai-state-flow dishui-ai-state-flow--empty', className)}>{emptyText}</div>;\n const select = (node: StateFlowNode) => { if (node.disabled) return; if (selectedId === undefined) setInternal(node.id); onSelect?.(node); };\n return <div {...rest} className={cn('dishui-ai-state-flow', `dishui-ai-state-flow--${direction}`, className)} role=\"list\" aria-label=\"Workflow\">{nodes.map((node, index) => <React.Fragment key={node.id}>{index > 0 && <div className=\"dishui-ai-state-flow__connector\" aria-hidden=\"true\"><span>↓</span>{(incoming.get(node.id) ?? []).map(edge => edge.label && <small key={`${edge.from}-${edge.to}`}>{edge.label}</small>)}</div>}<button type=\"button\" id={`${uid}-${node.id}`} role=\"listitem\" disabled={node.disabled} aria-current={selected === node.id ? 'step' : undefined} className={cn('dishui-ai-state-flow__node', `dishui-ai-state-flow__node--${node.shape ?? 'process'}`, node.status && `dishui-ai-state-flow__node--${node.status}`, selected === node.id && 'dishui-ai-state-flow__node--selected')} onClick={() => select(node)}><span className=\"dishui-ai-state-flow__status\">{node.status ?? 'step'}</span><strong>{node.label}</strong>{node.description && <small>{node.description}</small>}</button></React.Fragment>)}</div>;\n}\n"],"mappings":";;;;;AAQA,SAAwB,EAAU,EAAE,UAAO,UAAO,eAAY,sBAAmB,aAAU,eAAY,YAAY,eAAY,yBAAyB,cAAW,GAAG,KAAwB;CAC5L,IAAM,IAAM,EAAM,GAAS,CAAC,GAAU,KAAe,EAAS,CAAiB,GAAS,IAAW,KAAc,GAC3G,IAAW,QAAc;EAAE,IAAM,oBAAM,IAAI,IAA6B;EAAiF,OAA9E,EAAM,SAAQ,MAAQ,EAAI,IAAI,EAAK,IAAI,CAAC,GAAI,EAAI,IAAI,EAAK,EAAE,KAAK,CAAC,GAAI,CAAI,CAAC,CAAC,GAAU;CAAK,GAAG,CAAC,CAAK,CAAC;CACrL,IAAI,CAAC,EAAM,QAAQ,OAAO,kBAAC,OAAD;EAAK,GAAI;EAAM,WAAW,EAAG,oDAAoD,CAAS;EAAI,UAAA;CAAe,CAAA;CACvI,IAAM,KAAU,MAAwB;EAAM,EAAK,aAAsB,MAAe,KAAA,KAAW,EAAY,EAAK,EAAE,GAAG,IAAW,CAAI;CAAG;CAC3I,OAAO,kBAAC,OAAD;EAAK,GAAI;EAAM,WAAW,EAAG,wBAAwB,yBAAyB,KAAa,CAAS;EAAG,MAAK;EAAO,cAAW;EAAY,UAAA,EAAM,KAAK,GAAM,MAAU,kBAAC,EAAM,UAAP,EAAA,UAAA,CAA+B,IAAQ,KAAK,kBAAC,OAAD;GAAK,WAAU;GAAkC,eAAY;GAA7D,UAAA,CAAoE,kBAAC,QAAD,EAAA,UAAM,IAAO,CAAA,IAAG,EAAS,IAAI,EAAK,EAAE,KAAK,CAAC,EAAA,CAAG,KAAI,MAAQ,EAAK,SAAS,kBAAC,SAAD,EAAA,UAAwC,EAAK,MAAa,GAA9C,GAAG,EAAK,KAAK,GAAG,EAAK,IAAyB,CAAC,CAAO;EAAE,CAAA,GAAA,kBAAC,UAAD;GAAQ,MAAK;GAAS,IAAI,GAAG,EAAI,GAAG,EAAK;GAAM,MAAK;GAAW,UAAU,EAAK;GAAU,gBAAc,MAAa,EAAK,KAAK,SAAS,KAAA;GAAW,WAAW,EAAG,8BAA8B,+BAA+B,EAAK,SAAS,aAAa,EAAK,UAAU,+BAA+B,EAAK,UAAU,MAAa,EAAK,MAAM,sCAAsC;GAAG,eAAe,EAAO,CAAI;GAA/Y,UAAA;IAAkZ,kBAAC,QAAD;KAAM,WAAU;KAAgC,UAAA,EAAK,UAAU;IAAa,CAAA;IAAC,kBAAC,UAAD,EAAA,UAAS,EAAK,MAAc,CAAA;IAAE,EAAK,eAAe,kBAAC,SAAD,EAAA,UAAQ,EAAK,YAAmB,CAAA;GAAU;EAAiB,CAAA,CAAA,EAAA,GAAlzB,EAAK,EAA6yB,CAAC;CAAO,CAAA;AAC7/B"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type StreamingSource = {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
domain?: string;
|
|
6
|
+
url?: string;
|
|
7
|
+
favicon?: React.ReactNode;
|
|
8
|
+
};
|
|
9
|
+
export type StreamingAction = {
|
|
10
|
+
id: string;
|
|
11
|
+
label: string;
|
|
12
|
+
icon?: React.ReactNode;
|
|
13
|
+
onClick?: () => void;
|
|
14
|
+
};
|
|
15
|
+
export type StreamingFeedback = 'up' | 'down';
|
|
16
|
+
export type StreamingTextProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {
|
|
17
|
+
/** Full or partial answer text. `\n\n` starts a new paragraph. */
|
|
18
|
+
text: string;
|
|
19
|
+
/** Shows the caret and hides actions / follow-ups until the answer is complete. */
|
|
20
|
+
streaming?: boolean;
|
|
21
|
+
/** Reveal `text` progressively on the client. Remount (key) to replay. */
|
|
22
|
+
typewriter?: boolean;
|
|
23
|
+
/** Characters revealed per tick in typewriter mode. */
|
|
24
|
+
typewriterSpeed?: number;
|
|
25
|
+
sources?: StreamingSource[];
|
|
26
|
+
/** Render `[n]` markers in `text` as inline chips pointing at `sources[n - 1]`. */
|
|
27
|
+
citations?: boolean;
|
|
28
|
+
/** Source chips shown before the “+k” overflow toggle. */
|
|
29
|
+
maxVisibleSources?: number;
|
|
30
|
+
/** Extra actions appended after the built-in copy / regenerate / feedback buttons. */
|
|
31
|
+
actions?: StreamingAction[];
|
|
32
|
+
onCopy?: (text: string) => void;
|
|
33
|
+
onRegenerate?: () => void;
|
|
34
|
+
onFeedback?: (kind: StreamingFeedback) => void;
|
|
35
|
+
followUps?: string[];
|
|
36
|
+
onFollowUp?: (question: string) => void;
|
|
37
|
+
followUpsLabel?: React.ReactNode;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Streamed answer: paragraphs with optional inline citations, a source bar,
|
|
41
|
+
* an action row and follow-up questions. Fully controlled — it renders the
|
|
42
|
+
* `text` it is given; `typewriter` only adds a client-side reveal.
|
|
43
|
+
*/
|
|
44
|
+
export default function StreamingText({ text, streaming, typewriter, typewriterSpeed, sources, citations, maxVisibleSources, actions, onCopy, onRegenerate, onFeedback, followUps, onFollowUp, followUpsLabel, className, ...rest }: StreamingTextProps): React.JSX.Element;
|