dishui 0.0.91 → 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.js +6 -6
- 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/rowDetailExtension.js +1 -1
- package/dist/components/pro/DataTable/rowDetailExtension.js.map +1 -1
- package/dist/dishui.css +1 -1
- package/dist/index.d.ts +3 -2
- 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/package.json +10 -3
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { cn as e } from "../../../utils/cn.js";
|
|
2
|
+
/* empty css */
|
|
3
|
+
import t, { useEffect as n, useId as r, useMemo as i, useRef as a, useState as o } from "react";
|
|
4
|
+
import { Fragment as s, jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/ai/CommandSearch/index.tsx
|
|
6
|
+
var u = () => /* @__PURE__ */ l("svg", {
|
|
7
|
+
width: "16",
|
|
8
|
+
height: "16",
|
|
9
|
+
viewBox: "0 0 24 24",
|
|
10
|
+
fill: "none",
|
|
11
|
+
stroke: "currentColor",
|
|
12
|
+
strokeWidth: "2",
|
|
13
|
+
strokeLinecap: "round",
|
|
14
|
+
strokeLinejoin: "round",
|
|
15
|
+
"aria-hidden": "true",
|
|
16
|
+
children: [/* @__PURE__ */ c("circle", {
|
|
17
|
+
cx: "11",
|
|
18
|
+
cy: "11",
|
|
19
|
+
r: "8"
|
|
20
|
+
}), /* @__PURE__ */ c("path", { d: "m21 21-4.3-4.3" })]
|
|
21
|
+
}), d = () => /* @__PURE__ */ l("svg", {
|
|
22
|
+
width: "16",
|
|
23
|
+
height: "16",
|
|
24
|
+
viewBox: "0 0 24 24",
|
|
25
|
+
fill: "none",
|
|
26
|
+
stroke: "currentColor",
|
|
27
|
+
strokeWidth: "2",
|
|
28
|
+
strokeLinecap: "round",
|
|
29
|
+
strokeLinejoin: "round",
|
|
30
|
+
"aria-hidden": "true",
|
|
31
|
+
children: [/* @__PURE__ */ c("path", { d: "M5 12h14" }), /* @__PURE__ */ c("path", { d: "m12 5 7 7-7 7" })]
|
|
32
|
+
});
|
|
33
|
+
function f(e, t) {
|
|
34
|
+
let n = t.trim().toLowerCase();
|
|
35
|
+
return !n || [
|
|
36
|
+
e.label,
|
|
37
|
+
e.description ?? "",
|
|
38
|
+
...e.keywords ?? []
|
|
39
|
+
].join(" ").toLowerCase().includes(n);
|
|
40
|
+
}
|
|
41
|
+
function p(e, t) {
|
|
42
|
+
let n = t.trim();
|
|
43
|
+
if (!n) return e;
|
|
44
|
+
let r = e.toLowerCase().indexOf(n.toLowerCase());
|
|
45
|
+
return r < 0 ? e : /* @__PURE__ */ l(s, { children: [
|
|
46
|
+
e.slice(0, r),
|
|
47
|
+
/* @__PURE__ */ c("mark", {
|
|
48
|
+
className: "dishui-ai-command-search__mark",
|
|
49
|
+
children: e.slice(r, r + n.length)
|
|
50
|
+
}),
|
|
51
|
+
e.slice(r + n.length)
|
|
52
|
+
] });
|
|
53
|
+
}
|
|
54
|
+
function m({ items: m, query: h, defaultQuery: g = "", onQueryChange: _, onSelect: v, onSubmit: y, placeholder: b = "Search or ask…", filter: x = f, highlightMatches: S = !0, emptyState: C, maxVisible: w, autoFocus: T, inline: E = !0, loading: D = !1, label: O = "Search", className: k, ...A }) {
|
|
55
|
+
let j = r(), M = `${j}-list`, N = a(null), [P, F] = o(g), I = h ?? P, [L, R] = o(-1), z = (e) => {
|
|
56
|
+
h === void 0 && F(e), _?.(e), R(-1);
|
|
57
|
+
}, B = i(() => {
|
|
58
|
+
let e = m.filter((e) => x(e, I));
|
|
59
|
+
return w === void 0 ? e : e.slice(0, w);
|
|
60
|
+
}, [
|
|
61
|
+
m,
|
|
62
|
+
x,
|
|
63
|
+
I,
|
|
64
|
+
w
|
|
65
|
+
]), V = L < B.length ? L : -1;
|
|
66
|
+
n(() => {
|
|
67
|
+
V < 0 || document.getElementById(`${j}-opt-${V}`)?.scrollIntoView({ block: "nearest" });
|
|
68
|
+
}, [V, j]);
|
|
69
|
+
let H = (e) => {
|
|
70
|
+
e.onSelect?.(), v?.(e);
|
|
71
|
+
}, U = (e) => {
|
|
72
|
+
let t = B.length;
|
|
73
|
+
switch (e.key) {
|
|
74
|
+
case "ArrowDown":
|
|
75
|
+
e.preventDefault(), t && R((e) => (e + 1) % t);
|
|
76
|
+
break;
|
|
77
|
+
case "ArrowUp":
|
|
78
|
+
e.preventDefault(), t && R((e) => e <= 0 ? t - 1 : e - 1);
|
|
79
|
+
break;
|
|
80
|
+
case "Home":
|
|
81
|
+
t && (e.preventDefault(), R(0));
|
|
82
|
+
break;
|
|
83
|
+
case "End":
|
|
84
|
+
t && (e.preventDefault(), R(t - 1));
|
|
85
|
+
break;
|
|
86
|
+
case "Enter":
|
|
87
|
+
e.preventDefault(), V >= 0 && B[V] ? H(B[V]) : y?.(I);
|
|
88
|
+
break;
|
|
89
|
+
case "Escape": I && (e.preventDefault(), z("")), R(-1);
|
|
90
|
+
}
|
|
91
|
+
}, W = i(() => {
|
|
92
|
+
let e = [], t = /* @__PURE__ */ new Map();
|
|
93
|
+
return B.forEach((n, r) => {
|
|
94
|
+
let i = n.group ?? "";
|
|
95
|
+
t.has(i) || (t.set(i, []), e.push(i)), t.get(i).push({
|
|
96
|
+
item: n,
|
|
97
|
+
index: r
|
|
98
|
+
});
|
|
99
|
+
}), e.map((e) => ({
|
|
100
|
+
key: e,
|
|
101
|
+
entries: t.get(e)
|
|
102
|
+
}));
|
|
103
|
+
}, [B]), G = B.length === 0, K = V >= 0 ? `${j}-opt-${V}` : void 0;
|
|
104
|
+
return /* @__PURE__ */ l("div", {
|
|
105
|
+
...A,
|
|
106
|
+
className: e("dishui-ai-command-search", E && "dishui-ai-command-search--inline", k),
|
|
107
|
+
children: [
|
|
108
|
+
/* @__PURE__ */ l("div", {
|
|
109
|
+
className: e("dishui-ai-command-search__field", D && "dishui-ai-command-search__field--loading"),
|
|
110
|
+
children: [
|
|
111
|
+
/* @__PURE__ */ c("span", {
|
|
112
|
+
className: "dishui-ai-command-search__glyph",
|
|
113
|
+
"aria-hidden": "true",
|
|
114
|
+
children: /* @__PURE__ */ c(u, {})
|
|
115
|
+
}),
|
|
116
|
+
/* @__PURE__ */ c("input", {
|
|
117
|
+
ref: N,
|
|
118
|
+
className: "dishui-ai-command-search__input",
|
|
119
|
+
type: "text",
|
|
120
|
+
role: "combobox",
|
|
121
|
+
"aria-label": O,
|
|
122
|
+
"aria-expanded": !G,
|
|
123
|
+
"aria-controls": M,
|
|
124
|
+
"aria-activedescendant": K,
|
|
125
|
+
"aria-autocomplete": "list",
|
|
126
|
+
"aria-busy": D || void 0,
|
|
127
|
+
autoComplete: "off",
|
|
128
|
+
spellCheck: !1,
|
|
129
|
+
autoFocus: T,
|
|
130
|
+
placeholder: b,
|
|
131
|
+
value: I,
|
|
132
|
+
onChange: (e) => z(e.target.value),
|
|
133
|
+
onKeyDown: U
|
|
134
|
+
}),
|
|
135
|
+
D && /* @__PURE__ */ c("span", {
|
|
136
|
+
className: "dishui-ai-command-search__spinner",
|
|
137
|
+
role: "status",
|
|
138
|
+
"aria-label": "Searching"
|
|
139
|
+
}),
|
|
140
|
+
I && !D && /* @__PURE__ */ c("button", {
|
|
141
|
+
type: "button",
|
|
142
|
+
className: "dishui-ai-command-search__clear",
|
|
143
|
+
"aria-label": "Clear search",
|
|
144
|
+
onClick: () => {
|
|
145
|
+
z(""), N.current?.focus();
|
|
146
|
+
},
|
|
147
|
+
children: "×"
|
|
148
|
+
})
|
|
149
|
+
]
|
|
150
|
+
}),
|
|
151
|
+
/* @__PURE__ */ c("ul", {
|
|
152
|
+
id: M,
|
|
153
|
+
role: "listbox",
|
|
154
|
+
"aria-label": O,
|
|
155
|
+
className: "dishui-ai-command-search__list",
|
|
156
|
+
children: W.map((n) => /* @__PURE__ */ l(t.Fragment, { children: [n.key && /* @__PURE__ */ c("li", {
|
|
157
|
+
role: "presentation",
|
|
158
|
+
className: "dishui-ai-command-search__group",
|
|
159
|
+
children: n.key
|
|
160
|
+
}), n.entries.map(({ item: t, index: n }) => {
|
|
161
|
+
let r = n === V;
|
|
162
|
+
return /* @__PURE__ */ l("li", {
|
|
163
|
+
id: `${j}-opt-${n}`,
|
|
164
|
+
role: "option",
|
|
165
|
+
"aria-selected": r,
|
|
166
|
+
className: e("dishui-ai-command-search__option", r && "dishui-ai-command-search__option--active"),
|
|
167
|
+
onMouseMove: () => {
|
|
168
|
+
r || R(n);
|
|
169
|
+
},
|
|
170
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
171
|
+
onClick: () => H(t),
|
|
172
|
+
children: [
|
|
173
|
+
/* @__PURE__ */ c("span", {
|
|
174
|
+
className: "dishui-ai-command-search__icon",
|
|
175
|
+
"aria-hidden": "true",
|
|
176
|
+
children: t.icon ?? /* @__PURE__ */ c(d, {})
|
|
177
|
+
}),
|
|
178
|
+
/* @__PURE__ */ l("span", {
|
|
179
|
+
className: "dishui-ai-command-search__text",
|
|
180
|
+
children: [/* @__PURE__ */ c("span", {
|
|
181
|
+
className: "dishui-ai-command-search__label",
|
|
182
|
+
children: S ? p(t.label, I) : t.label
|
|
183
|
+
}), t.description && /* @__PURE__ */ c("span", {
|
|
184
|
+
className: "dishui-ai-command-search__description",
|
|
185
|
+
children: S ? p(t.description, I) : t.description
|
|
186
|
+
})]
|
|
187
|
+
}),
|
|
188
|
+
t.shortcut && /* @__PURE__ */ c("kbd", {
|
|
189
|
+
className: "dishui-ai-command-search__shortcut",
|
|
190
|
+
children: t.shortcut
|
|
191
|
+
})
|
|
192
|
+
]
|
|
193
|
+
}, t.id);
|
|
194
|
+
})] }, n.key || "__default"))
|
|
195
|
+
}),
|
|
196
|
+
G && /* @__PURE__ */ c("div", {
|
|
197
|
+
className: "dishui-ai-command-search__empty",
|
|
198
|
+
role: "status",
|
|
199
|
+
children: typeof C == "function" ? C(I) : C ?? /* @__PURE__ */ l(s, { children: [/* @__PURE__ */ c("p", {
|
|
200
|
+
className: "dishui-ai-command-search__empty-title",
|
|
201
|
+
children: I.trim() ? /* @__PURE__ */ l(s, { children: [
|
|
202
|
+
"No results for “",
|
|
203
|
+
I.trim(),
|
|
204
|
+
"”"
|
|
205
|
+
] }) : "Nothing to show"
|
|
206
|
+
}), /* @__PURE__ */ c("p", {
|
|
207
|
+
className: "dishui-ai-command-search__empty-hint",
|
|
208
|
+
children: y ? "Try a different phrase or press Enter to ask the agent" : "Try a different phrase"
|
|
209
|
+
})] })
|
|
210
|
+
})
|
|
211
|
+
]
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
//#endregion
|
|
215
|
+
export { m as default };
|
|
216
|
+
|
|
217
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/CommandSearch/index.tsx"],"sourcesContent":["import React, { useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport './CommandSearch.css';\n\nexport type CommandSearchItem = {\n id: string;\n label: string;\n description?: string;\n icon?: React.ReactNode;\n group?: string;\n keywords?: string[];\n shortcut?: string;\n onSelect?: () => void;\n};\n\nexport type CommandSearchProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect' | 'onSubmit' | 'children'> & {\n items: CommandSearchItem[];\n query?: string;\n defaultQuery?: string;\n onQueryChange?: (query: string) => void;\n onSelect?: (item: CommandSearchItem) => void;\n /** Enter with nothing highlighted, or on an empty result set. */\n onSubmit?: (query: string) => void;\n placeholder?: string;\n /** Custom predicate; default is a case-insensitive match on label / description / keywords. */\n filter?: (item: CommandSearchItem, query: string) => boolean;\n /** Wrap matched substrings in `<mark>`. */\n highlightMatches?: boolean;\n emptyState?: React.ReactNode | ((query: string) => React.ReactNode);\n maxVisible?: number;\n autoFocus?: boolean;\n /** Renders as an in-page panel (not a modal). */\n inline?: boolean;\n /** Show a small indeterminate indicator in the input. */\n loading?: boolean;\n /** Accessible name for the input. */\n label?: string;\n};\n\nconst SearchIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </svg>\n);\nconst ArrowRight = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M5 12h14\" />\n <path d=\"m12 5 7 7-7 7\" />\n </svg>\n);\n\nfunction defaultFilter(item: CommandSearchItem, query: string): boolean {\n const q = query.trim().toLowerCase();\n if (!q) return true;\n const hay = [item.label, item.description ?? '', ...(item.keywords ?? [])].join(' ').toLowerCase();\n return hay.includes(q);\n}\n\nfunction highlight(text: string, query: string): React.ReactNode {\n const q = query.trim();\n if (!q) return text;\n const idx = text.toLowerCase().indexOf(q.toLowerCase());\n if (idx < 0) return text;\n return (\n <>\n {text.slice(0, idx)}\n <mark className=\"dishui-ai-command-search__mark\">{text.slice(idx, idx + q.length)}</mark>\n {text.slice(idx + q.length)}\n </>\n );\n}\n\n/**\n * Command search: an input over a filtered, grouped listbox with keyboard\n * navigation and an empty state that hands the query to the agent.\n */\nexport default function CommandSearch({\n items,\n query,\n defaultQuery = '',\n onQueryChange,\n onSelect,\n onSubmit,\n placeholder = 'Search or ask…',\n filter = defaultFilter,\n highlightMatches = true,\n emptyState,\n maxVisible,\n autoFocus,\n inline = true,\n loading = false,\n label = 'Search',\n className,\n ...rest\n}: CommandSearchProps) {\n const uid = useId();\n const listId = `${uid}-list`;\n const inputRef = useRef<HTMLInputElement>(null);\n\n const [internalQuery, setInternalQuery] = useState(defaultQuery);\n const q = query ?? internalQuery;\n const [highlighted, setHighlighted] = useState<number>(-1);\n const setQuery = (next: string) => {\n if (query === undefined) setInternalQuery(next);\n onQueryChange?.(next);\n setHighlighted(-1);\n };\n\n const visible = useMemo(() => {\n const matched = items.filter(item => filter(item, q));\n return maxVisible !== undefined ? matched.slice(0, maxVisible) : matched;\n }, [items, filter, q, maxVisible]);\n\n // -1 means \"nothing highlighted\"; clamp in case the result set shrank.\n const activeIndex = highlighted < visible.length ? highlighted : -1;\n\n // Keep the highlighted option in view.\n useEffect(() => {\n if (activeIndex < 0) return;\n const el = document.getElementById(`${uid}-opt-${activeIndex}`);\n el?.scrollIntoView({ block: 'nearest' });\n }, [activeIndex, uid]);\n\n const select = (item: CommandSearchItem) => {\n item.onSelect?.();\n onSelect?.(item);\n };\n\n const onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n const n = visible.length;\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n if (n) setHighlighted(i => (i + 1) % n);\n break;\n case 'ArrowUp':\n e.preventDefault();\n if (n) setHighlighted(i => (i <= 0 ? n - 1 : i - 1));\n break;\n case 'Home':\n if (n) { e.preventDefault(); setHighlighted(0); }\n break;\n case 'End':\n if (n) { e.preventDefault(); setHighlighted(n - 1); }\n break;\n case 'Enter':\n e.preventDefault();\n if (activeIndex >= 0 && visible[activeIndex]) select(visible[activeIndex]);\n else onSubmit?.(q);\n break;\n case 'Escape':\n if (q) { e.preventDefault(); setQuery(''); }\n setHighlighted(-1);\n break;\n default:\n }\n };\n\n // Group while preserving first-seen order.\n const groups = useMemo(() => {\n const order: string[] = [];\n const map = new Map<string, { item: CommandSearchItem; index: number }[]>();\n visible.forEach((item, index) => {\n const key = item.group ?? '';\n if (!map.has(key)) { map.set(key, []); order.push(key); }\n map.get(key)!.push({ item, index });\n });\n return order.map(key => ({ key, entries: map.get(key)! }));\n }, [visible]);\n\n const empty = visible.length === 0;\n const activeId = activeIndex >= 0 ? `${uid}-opt-${activeIndex}` : undefined;\n\n return (\n <div {...rest} className={cn('dishui-ai-command-search', inline && 'dishui-ai-command-search--inline', className)}>\n <div className={cn('dishui-ai-command-search__field', loading && 'dishui-ai-command-search__field--loading')}>\n <span className=\"dishui-ai-command-search__glyph\" aria-hidden=\"true\"><SearchIcon /></span>\n <input\n ref={inputRef}\n className=\"dishui-ai-command-search__input\"\n type=\"text\"\n role=\"combobox\"\n aria-label={label}\n aria-expanded={!empty}\n aria-controls={listId}\n aria-activedescendant={activeId}\n aria-autocomplete=\"list\"\n aria-busy={loading || undefined}\n autoComplete=\"off\"\n spellCheck={false}\n autoFocus={autoFocus}\n placeholder={placeholder}\n value={q}\n onChange={e => setQuery(e.target.value)}\n onKeyDown={onKeyDown}\n />\n {loading && <span className=\"dishui-ai-command-search__spinner\" role=\"status\" aria-label=\"Searching\" />}\n {q && !loading && (\n <button\n type=\"button\"\n className=\"dishui-ai-command-search__clear\"\n aria-label=\"Clear search\"\n onClick={() => { setQuery(''); inputRef.current?.focus(); }}\n >\n ×\n </button>\n )}\n </div>\n\n <ul id={listId} role=\"listbox\" aria-label={label} className=\"dishui-ai-command-search__list\">\n {groups.map(group => (\n <React.Fragment key={group.key || '__default'}>\n {group.key && (\n <li role=\"presentation\" className=\"dishui-ai-command-search__group\">{group.key}</li>\n )}\n {group.entries.map(({ item, index }) => {\n const isActive = index === activeIndex;\n return (\n <li\n key={item.id}\n id={`${uid}-opt-${index}`}\n role=\"option\"\n aria-selected={isActive}\n className={cn('dishui-ai-command-search__option', isActive && 'dishui-ai-command-search__option--active')}\n onMouseMove={() => { if (!isActive) setHighlighted(index); }}\n onMouseDown={e => e.preventDefault()}\n onClick={() => select(item)}\n >\n <span className=\"dishui-ai-command-search__icon\" aria-hidden=\"true\">{item.icon ?? <ArrowRight />}</span>\n <span className=\"dishui-ai-command-search__text\">\n <span className=\"dishui-ai-command-search__label\">{highlightMatches ? highlight(item.label, q) : item.label}</span>\n {item.description && (\n <span className=\"dishui-ai-command-search__description\">\n {highlightMatches ? highlight(item.description, q) : item.description}\n </span>\n )}\n </span>\n {item.shortcut && <kbd className=\"dishui-ai-command-search__shortcut\">{item.shortcut}</kbd>}\n </li>\n );\n })}\n </React.Fragment>\n ))}\n </ul>\n\n {empty && (\n <div className=\"dishui-ai-command-search__empty\" role=\"status\">\n {typeof emptyState === 'function' ? emptyState(q) : emptyState ?? (\n <>\n <p className=\"dishui-ai-command-search__empty-title\">\n {q.trim() ? <>No results for “{q.trim()}”</> : 'Nothing to show'}\n </p>\n <p className=\"dishui-ai-command-search__empty-hint\">\n {onSubmit ? 'Try a different phrase or press Enter to ask the agent' : 'Try a different phrase'}\n </p>\n </>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type ContextSourceKind = 'pdf' | 'csv' | 'doc' | 'web' | 'db' | 'code' | (string & {});
|
|
3
|
+
export type ContextSource = {
|
|
4
|
+
kind: ContextSourceKind;
|
|
5
|
+
name: string;
|
|
6
|
+
url?: string;
|
|
7
|
+
page?: number;
|
|
8
|
+
};
|
|
9
|
+
export type ContextChunk = {
|
|
10
|
+
id: string;
|
|
11
|
+
title: React.ReactNode;
|
|
12
|
+
excerpt: string;
|
|
13
|
+
/** Defaults to `excerpt.length`. */
|
|
14
|
+
characters?: number;
|
|
15
|
+
/** Relevance 0–1, shown as a percentage. */
|
|
16
|
+
score?: number;
|
|
17
|
+
source: ContextSource;
|
|
18
|
+
};
|
|
19
|
+
export type ContextCardsLabels = {
|
|
20
|
+
characters?: string;
|
|
21
|
+
page?: string;
|
|
22
|
+
};
|
|
23
|
+
export type ContextCardsProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'title' | 'onSelect'> & {
|
|
24
|
+
chunks: ContextChunk[];
|
|
25
|
+
/** Total count when only a subset is passed; defaults to `chunks.length`. */
|
|
26
|
+
total?: number;
|
|
27
|
+
title?: React.ReactNode;
|
|
28
|
+
/** Grid columns on wide containers; collapses to 1 below 560px. */
|
|
29
|
+
columns?: 1 | 2;
|
|
30
|
+
/** Makes each card a button. */
|
|
31
|
+
onSelect?: (chunk: ContextChunk) => void;
|
|
32
|
+
selectedId?: string;
|
|
33
|
+
/** Excerpt line clamp. */
|
|
34
|
+
maxExcerptLines?: number;
|
|
35
|
+
emptyText?: React.ReactNode;
|
|
36
|
+
labels?: ContextCardsLabels;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Retrieved knowledge chunks with their sources: a header count, then
|
|
40
|
+
* cards with title, character count, clamped excerpt and a source pill.
|
|
41
|
+
*/
|
|
42
|
+
export default function ContextCards({ chunks, total, title, columns, onSelect, selectedId, maxExcerptLines, emptyText, labels, className, ...rest }: ContextCardsProps): React.JSX.Element;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { cn as e } from "../../../utils/cn.js";
|
|
2
|
+
/* empty css */
|
|
3
|
+
import "react";
|
|
4
|
+
import { Fragment as t, jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/ai/ContextCards/index.tsx
|
|
6
|
+
var i = {
|
|
7
|
+
characters: "characters",
|
|
8
|
+
page: "p."
|
|
9
|
+
}, a = new Intl.NumberFormat("en-US");
|
|
10
|
+
function o({ chunks: o, total: s, title: c = "All chunks", columns: l = 2, onSelect: u, selectedId: d, maxExcerptLines: f = 3, emptyText: p = "No context retrieved", labels: m, className: h, ...g }) {
|
|
11
|
+
let _ = {
|
|
12
|
+
...i,
|
|
13
|
+
...m
|
|
14
|
+
}, v = s ?? o.length, y = {
|
|
15
|
+
WebkitLineClamp: f,
|
|
16
|
+
lineClamp: f
|
|
17
|
+
};
|
|
18
|
+
return /* @__PURE__ */ r("div", {
|
|
19
|
+
...g,
|
|
20
|
+
className: e("dishui-ai-context-cards", `dishui-ai-context-cards--cols-${l}`, h),
|
|
21
|
+
children: [/* @__PURE__ */ r("div", {
|
|
22
|
+
className: "dishui-ai-context-cards__header",
|
|
23
|
+
children: [/* @__PURE__ */ n("span", {
|
|
24
|
+
className: "dishui-ai-context-cards__title",
|
|
25
|
+
children: c
|
|
26
|
+
}), /* @__PURE__ */ n("span", {
|
|
27
|
+
className: "dishui-ai-context-cards__count",
|
|
28
|
+
children: a.format(v)
|
|
29
|
+
})]
|
|
30
|
+
}), o.length === 0 ? /* @__PURE__ */ n("div", {
|
|
31
|
+
className: "dishui-ai-context-cards__empty",
|
|
32
|
+
children: p
|
|
33
|
+
}) : /* @__PURE__ */ n("ul", {
|
|
34
|
+
className: "dishui-ai-context-cards__grid",
|
|
35
|
+
children: o.map((i) => {
|
|
36
|
+
let o = i.characters ?? i.excerpt.length, s = i.id === d, c = /* @__PURE__ */ r(t, { children: [
|
|
37
|
+
/* @__PURE__ */ r("div", {
|
|
38
|
+
className: "dishui-ai-context-cards__card-header",
|
|
39
|
+
children: [
|
|
40
|
+
/* @__PURE__ */ n("span", {
|
|
41
|
+
className: "dishui-ai-context-cards__card-title",
|
|
42
|
+
children: i.title
|
|
43
|
+
}),
|
|
44
|
+
/* @__PURE__ */ r("span", {
|
|
45
|
+
className: "dishui-ai-context-cards__chars",
|
|
46
|
+
children: [
|
|
47
|
+
a.format(o),
|
|
48
|
+
" ",
|
|
49
|
+
_.characters
|
|
50
|
+
]
|
|
51
|
+
}),
|
|
52
|
+
i.score !== void 0 && /* @__PURE__ */ r("span", {
|
|
53
|
+
className: "dishui-ai-context-cards__score",
|
|
54
|
+
children: [Math.round(i.score * 100), "%"]
|
|
55
|
+
})
|
|
56
|
+
]
|
|
57
|
+
}),
|
|
58
|
+
/* @__PURE__ */ n("p", {
|
|
59
|
+
className: "dishui-ai-context-cards__excerpt",
|
|
60
|
+
style: y,
|
|
61
|
+
children: i.excerpt
|
|
62
|
+
}),
|
|
63
|
+
/* @__PURE__ */ r("span", {
|
|
64
|
+
className: "dishui-ai-context-cards__source",
|
|
65
|
+
children: [
|
|
66
|
+
/* @__PURE__ */ n("span", {
|
|
67
|
+
className: "dishui-ai-context-cards__kind",
|
|
68
|
+
children: i.source.kind
|
|
69
|
+
}),
|
|
70
|
+
/* @__PURE__ */ n("span", {
|
|
71
|
+
className: "dishui-ai-context-cards__source-name",
|
|
72
|
+
title: i.source.name,
|
|
73
|
+
children: i.source.name
|
|
74
|
+
}),
|
|
75
|
+
i.source.page !== void 0 && /* @__PURE__ */ r("span", {
|
|
76
|
+
className: "dishui-ai-context-cards__page",
|
|
77
|
+
children: [
|
|
78
|
+
_.page,
|
|
79
|
+
" ",
|
|
80
|
+
i.source.page
|
|
81
|
+
]
|
|
82
|
+
})
|
|
83
|
+
]
|
|
84
|
+
})
|
|
85
|
+
] }), l = e("dishui-ai-context-cards__card", u && "dishui-ai-context-cards__card--interactive", s && "dishui-ai-context-cards__card--selected");
|
|
86
|
+
return /* @__PURE__ */ n("li", {
|
|
87
|
+
className: "dishui-ai-context-cards__item",
|
|
88
|
+
children: u ? /* @__PURE__ */ n("button", {
|
|
89
|
+
type: "button",
|
|
90
|
+
className: l,
|
|
91
|
+
"aria-pressed": s,
|
|
92
|
+
onClick: () => u(i),
|
|
93
|
+
children: c
|
|
94
|
+
}) : /* @__PURE__ */ n("div", {
|
|
95
|
+
className: l,
|
|
96
|
+
children: c
|
|
97
|
+
})
|
|
98
|
+
}, i.id);
|
|
99
|
+
})
|
|
100
|
+
})]
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
export { o as default };
|
|
105
|
+
|
|
106
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/ContextCards/index.tsx"],"sourcesContent":["import React from 'react';\nimport { cn } from '../../../utils/cn';\nimport './ContextCards.css';\n\nexport type ContextSourceKind = 'pdf' | 'csv' | 'doc' | 'web' | 'db' | 'code' | (string & {});\n\nexport type ContextSource = {\n kind: ContextSourceKind;\n name: string;\n url?: string;\n page?: number;\n};\n\nexport type ContextChunk = {\n id: string;\n title: React.ReactNode;\n excerpt: string;\n /** Defaults to `excerpt.length`. */\n characters?: number;\n /** Relevance 0–1, shown as a percentage. */\n score?: number;\n source: ContextSource;\n};\n\nexport type ContextCardsLabels = {\n characters?: string;\n page?: string;\n};\n\nexport type ContextCardsProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'title' | 'onSelect'> & {\n chunks: ContextChunk[];\n /** Total count when only a subset is passed; defaults to `chunks.length`. */\n total?: number;\n title?: React.ReactNode;\n /** Grid columns on wide containers; collapses to 1 below 560px. */\n columns?: 1 | 2;\n /** Makes each card a button. */\n onSelect?: (chunk: ContextChunk) => void;\n selectedId?: string;\n /** Excerpt line clamp. */\n maxExcerptLines?: number;\n emptyText?: React.ReactNode;\n labels?: ContextCardsLabels;\n};\n\nconst DEFAULT_LABELS: Required<ContextCardsLabels> = { characters: 'characters', page: 'p.' };\n\nconst numberFormat = new Intl.NumberFormat('en-US');\n\n/**\n * Retrieved knowledge chunks with their sources: a header count, then\n * cards with title, character count, clamped excerpt and a source pill.\n */\nexport default function ContextCards({\n chunks,\n total,\n title = 'All chunks',\n columns = 2,\n onSelect,\n selectedId,\n maxExcerptLines = 3,\n emptyText = 'No context retrieved',\n labels,\n className,\n ...rest\n}: ContextCardsProps) {\n const text = { ...DEFAULT_LABELS, ...labels };\n const count = total ?? chunks.length;\n const excerptStyle: React.CSSProperties = { WebkitLineClamp: maxExcerptLines, lineClamp: maxExcerptLines };\n\n return (\n <div {...rest} className={cn('dishui-ai-context-cards', `dishui-ai-context-cards--cols-${columns}`, className)}>\n <div className=\"dishui-ai-context-cards__header\">\n <span className=\"dishui-ai-context-cards__title\">{title}</span>\n <span className=\"dishui-ai-context-cards__count\">{numberFormat.format(count)}</span>\n </div>\n\n {chunks.length === 0 ? (\n <div className=\"dishui-ai-context-cards__empty\">{emptyText}</div>\n ) : (\n <ul className=\"dishui-ai-context-cards__grid\">\n {chunks.map(chunk => {\n const characters = chunk.characters ?? chunk.excerpt.length;\n const selected = chunk.id === selectedId;\n const inner = (\n <>\n <div className=\"dishui-ai-context-cards__card-header\">\n <span className=\"dishui-ai-context-cards__card-title\">{chunk.title}</span>\n <span className=\"dishui-ai-context-cards__chars\">\n {numberFormat.format(characters)} {text.characters}\n </span>\n {chunk.score !== undefined && (\n <span className=\"dishui-ai-context-cards__score\">{Math.round(chunk.score * 100)}%</span>\n )}\n </div>\n <p className=\"dishui-ai-context-cards__excerpt\" style={excerptStyle}>{chunk.excerpt}</p>\n <span className=\"dishui-ai-context-cards__source\">\n <span className=\"dishui-ai-context-cards__kind\">{chunk.source.kind}</span>\n <span className=\"dishui-ai-context-cards__source-name\" title={chunk.source.name}>\n {chunk.source.name}\n </span>\n {chunk.source.page !== undefined && (\n <span className=\"dishui-ai-context-cards__page\">{text.page} {chunk.source.page}</span>\n )}\n </span>\n </>\n );\n const cardClass = cn(\n 'dishui-ai-context-cards__card',\n onSelect && 'dishui-ai-context-cards__card--interactive',\n selected && 'dishui-ai-context-cards__card--selected',\n );\n return (\n <li key={chunk.id} className=\"dishui-ai-context-cards__item\">\n {onSelect ? (\n <button type=\"button\" className={cardClass} aria-pressed={selected} onClick={() => onSelect(chunk)}>\n {inner}\n </button>\n ) : (\n <div className={cardClass}>{inner}</div>\n )}\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;AA6CA,IAAM,IAA+C;CAAE,YAAY;CAAc,MAAM;AAAK,GAEtF,IAAe,IAAI,KAAK,aAAa,OAAO;AAMlD,SAAwB,EAAa,EACnC,WACA,UACA,WAAQ,cACR,aAAU,GACV,aACA,eACA,qBAAkB,GAClB,eAAY,wBACZ,WACA,cACA,GAAG,KACiB;CACpB,IAAM,IAAO;EAAE,GAAG;EAAgB,GAAG;CAAO,GACtC,IAAQ,KAAS,EAAO,QACxB,IAAoC;EAAE,iBAAiB;EAAiB,WAAW;CAAgB;CAEzG,OACE,kBAAC,OAAD;EAAK,GAAI;EAAM,WAAW,EAAG,2BAA2B,iCAAiC,KAAW,CAAS;EAA7G,UAAA,CACE,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,QAAD;IAAM,WAAU;IAAkC,UAAA;GAAY,CAAA,GAC9D,kBAAC,QAAD;IAAM,WAAU;IAAkC,UAAA,EAAa,OAAO,CAAK;GAAQ,CAAA,CAChF;EAEJ,CAAA,GAAA,EAAO,WAAW,IACjB,kBAAC,OAAD;GAAK,WAAU;GAAkC,UAAA;EAAe,CAAA,IAEhE,kBAAC,MAAD;GAAI,WAAU;GACX,UAAA,EAAO,KAAI,MAAS;IACnB,IAAM,IAAa,EAAM,cAAc,EAAM,QAAQ,QAC/C,IAAW,EAAM,OAAO,GACxB,IACJ,kBAAA,GAAA,EAAA,UAAA;KACE,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA;OACE,kBAAC,QAAD;QAAM,WAAU;QAAuC,UAAA,EAAM;OAAY,CAAA;OACzE,kBAAC,QAAD;QAAM,WAAU;QAAhB,UAAA;SACG,EAAa,OAAO,CAAU;SAAE;SAAE,EAAK;QACpC;;OACL,EAAM,UAAU,KAAA,KACf,kBAAC,QAAD;QAAM,WAAU;QAAhB,UAAA,CAAkD,KAAK,MAAM,EAAM,QAAQ,GAAG,GAAE,GAAO;;MAEtF;;KACL,kBAAC,KAAD;MAAG,WAAU;MAAmC,OAAO;MAAe,UAAA,EAAM;KAAW,CAAA;KACvF,kBAAC,QAAD;MAAM,WAAU;MAAhB,UAAA;OACE,kBAAC,QAAD;QAAM,WAAU;QAAiC,UAAA,EAAM,OAAO;OAAW,CAAA;OACzE,kBAAC,QAAD;QAAM,WAAU;QAAuC,OAAO,EAAM,OAAO;QACxE,UAAA,EAAM,OAAO;OACV,CAAA;OACL,EAAM,OAAO,SAAS,KAAA,KACrB,kBAAC,QAAD;QAAM,WAAU;QAAhB,UAAA;SAAiD,EAAK;SAAK;SAAE,EAAM,OAAO;QAAW;;MAEnF;;IACN,EAAA,CAAA,GAEE,IAAY,EAChB,iCACA,KAAY,8CACZ,KAAY,yCACd;IACA,OACE,kBAAC,MAAD;KAAmB,WAAU;KAC1B,UAAA,IACC,kBAAC,UAAD;MAAQ,MAAK;MAAS,WAAW;MAAW,gBAAc;MAAU,eAAe,EAAS,CAAK;MAC9F,UAAA;KACK,CAAA,IAER,kBAAC,OAAD;MAAK,WAAW;MAAY,UAAA;KAAW,CAAA;IAEvC,GARK,EAAM,EAQX;GAER,CAAC;EACC,CAAA,CAEH;;AAET"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type DiffTableColumn = {
|
|
3
|
+
key: string;
|
|
4
|
+
label: React.ReactNode;
|
|
5
|
+
align?: 'left' | 'right';
|
|
6
|
+
/** Render the cell in the mono font (IDs, SKUs). */
|
|
7
|
+
mono?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export type DiffCellValue = string | number | null;
|
|
10
|
+
/** A plain value is unchanged; an object describes a `before → after` edit. */
|
|
11
|
+
export type DiffCell = DiffCellValue | {
|
|
12
|
+
before?: DiffCellValue;
|
|
13
|
+
after?: DiffCellValue;
|
|
14
|
+
};
|
|
15
|
+
export type DiffRowChange = 'added' | 'removed' | 'modified';
|
|
16
|
+
export type DiffRow = {
|
|
17
|
+
id: string;
|
|
18
|
+
cells: Record<string, DiffCell>;
|
|
19
|
+
/** Row-level change. Omitted rows are inferred as `modified` when any cell is an edit. */
|
|
20
|
+
change?: DiffRowChange;
|
|
21
|
+
};
|
|
22
|
+
export type DiffDecision = 'accepted' | 'rejected';
|
|
23
|
+
export type DiffTableProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'title' | 'summary'> & {
|
|
24
|
+
columns: DiffTableColumn[];
|
|
25
|
+
rows: DiffRow[];
|
|
26
|
+
title?: React.ReactNode;
|
|
27
|
+
/** Summary line under the title. Auto-computed (`3 changes across 2 rows`) when omitted. */
|
|
28
|
+
summary?: React.ReactNode;
|
|
29
|
+
/** Reveal changed rows one by one, top to bottom. */
|
|
30
|
+
sweeping?: boolean;
|
|
31
|
+
/** Milliseconds between each revealed row while sweeping. */
|
|
32
|
+
sweepIntervalMs?: number;
|
|
33
|
+
onAcceptAll?: () => void;
|
|
34
|
+
onRejectAll?: () => void;
|
|
35
|
+
onAcceptRow?: (row: DiffRow) => void;
|
|
36
|
+
onRejectRow?: (row: DiffRow) => void;
|
|
37
|
+
/** Controlled per-row decisions, keyed by row id. */
|
|
38
|
+
decisions?: Record<string, DiffDecision>;
|
|
39
|
+
dense?: boolean;
|
|
40
|
+
/** Text overrides. */
|
|
41
|
+
labels?: Partial<typeof DEFAULT_LABELS>;
|
|
42
|
+
};
|
|
43
|
+
declare const DEFAULT_LABELS: {
|
|
44
|
+
added: string;
|
|
45
|
+
removed: string;
|
|
46
|
+
modified: string;
|
|
47
|
+
unchanged: string;
|
|
48
|
+
acceptAll: string;
|
|
49
|
+
rejectAll: string;
|
|
50
|
+
accept: string;
|
|
51
|
+
reject: string;
|
|
52
|
+
accepted: string;
|
|
53
|
+
rejected: string;
|
|
54
|
+
status: string;
|
|
55
|
+
actions: string;
|
|
56
|
+
empty: string;
|
|
57
|
+
};
|
|
58
|
+
export declare function isDiffCellChange(cell: DiffCell): cell is {
|
|
59
|
+
before?: DiffCellValue;
|
|
60
|
+
after?: DiffCellValue;
|
|
61
|
+
};
|
|
62
|
+
/** Infer the row's change kind from its explicit flag or its cells. */
|
|
63
|
+
export declare function diffRowChange(row: DiffRow): DiffRowChange | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* AI-proposed edits sweeping through tabular data. Changed cells show the
|
|
66
|
+
* old value struck through next to the new one; added/removed rows are
|
|
67
|
+
* tinted and always labelled in the leading status column.
|
|
68
|
+
*/
|
|
69
|
+
export default function DiffTable({ columns, rows, title, summary, sweeping: sweepingProp, sweepIntervalMs, onAcceptAll, onRejectAll, onAcceptRow, onRejectRow, decisions, dense, labels: labelOverrides, className, ...rest }: DiffTableProps): React.JSX.Element;
|
|
70
|
+
export {};
|