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.
Files changed (106) hide show
  1. package/dist/.release-verified.json +6 -0
  2. package/dist/ai.js +22 -0
  3. package/dist/components/Card/Metric2.js +11 -11
  4. package/dist/components/Card/Metric2.js.map +1 -1
  5. package/dist/components/Card/index.d.ts +20 -0
  6. package/dist/components/Card/index.js +184 -179
  7. package/dist/components/Card/index.js.map +1 -1
  8. package/dist/components/GroupButton/index.js +4 -4
  9. package/dist/components/GroupButton/index.js.map +1 -1
  10. package/dist/components/GroupedTable/index.js +10 -10
  11. package/dist/components/GroupedTable/index.js.map +1 -1
  12. package/dist/components/NavigationList/index.js +9 -9
  13. package/dist/components/NavigationList/index.js.map +1 -1
  14. package/dist/components/Section/index.js +11 -11
  15. package/dist/components/Section/index.js.map +1 -1
  16. package/dist/components/Skeleton/index.js +1 -1
  17. package/dist/components/Skeleton/index.js.map +1 -1
  18. package/dist/components/Table/index.d.ts +23 -2
  19. package/dist/components/Table/index.js +153 -101
  20. package/dist/components/Table/index.js.map +1 -1
  21. package/dist/components/ai/AgentChat/index.d.ts +54 -0
  22. package/dist/components/ai/AgentChat/index.js +176 -0
  23. package/dist/components/ai/AgentChat/index.js.map +1 -0
  24. package/dist/components/ai/AgentScreen/index.d.ts +50 -0
  25. package/dist/components/ai/AgentScreen/index.js +233 -0
  26. package/dist/components/ai/AgentScreen/index.js.map +1 -0
  27. package/dist/components/ai/ApprovalCard/index.d.ts +26 -0
  28. package/dist/components/ai/ApprovalCard/index.js +89 -0
  29. package/dist/components/ai/ApprovalCard/index.js.map +1 -0
  30. package/dist/components/ai/CodeView/index.d.ts +30 -0
  31. package/dist/components/ai/CodeView/index.js +149 -0
  32. package/dist/components/ai/CodeView/index.js.map +1 -0
  33. package/dist/components/ai/CommandSearch/index.d.ts +39 -0
  34. package/dist/components/ai/CommandSearch/index.js +217 -0
  35. package/dist/components/ai/CommandSearch/index.js.map +1 -0
  36. package/dist/components/ai/ContextCards/index.d.ts +42 -0
  37. package/dist/components/ai/ContextCards/index.js +106 -0
  38. package/dist/components/ai/ContextCards/index.js.map +1 -0
  39. package/dist/components/ai/DiffTable/index.d.ts +70 -0
  40. package/dist/components/ai/DiffTable/index.js +235 -0
  41. package/dist/components/ai/DiffTable/index.js.map +1 -0
  42. package/dist/components/ai/FilterTable/index.d.ts +35 -0
  43. package/dist/components/ai/FilterTable/index.js +86 -0
  44. package/dist/components/ai/FilterTable/index.js.map +1 -0
  45. package/dist/components/ai/FineTuneCard/index.d.ts +24 -0
  46. package/dist/components/ai/FineTuneCard/index.js +75 -0
  47. package/dist/components/ai/FineTuneCard/index.js.map +1 -0
  48. package/dist/components/ai/InsightCards/index.d.ts +23 -0
  49. package/dist/components/ai/InsightCards/index.js +64 -0
  50. package/dist/components/ai/InsightCards/index.js.map +1 -0
  51. package/dist/components/ai/LoadingState/index.d.ts +22 -0
  52. package/dist/components/ai/LoadingState/index.js +80 -0
  53. package/dist/components/ai/LoadingState/index.js.map +1 -0
  54. package/dist/components/ai/PromptBar/index.d.ts +26 -0
  55. package/dist/components/ai/PromptBar/index.js +117 -0
  56. package/dist/components/ai/PromptBar/index.js.map +1 -0
  57. package/dist/components/ai/RecommendationCard/index.d.ts +44 -0
  58. package/dist/components/ai/RecommendationCard/index.js +142 -0
  59. package/dist/components/ai/RecommendationCard/index.js.map +1 -0
  60. package/dist/components/ai/RecordsTable/index.d.ts +65 -0
  61. package/dist/components/ai/RecordsTable/index.js +334 -0
  62. package/dist/components/ai/RecordsTable/index.js.map +1 -0
  63. package/dist/components/ai/SelectionActions/index.d.ts +19 -0
  64. package/dist/components/ai/SelectionActions/index.js +40 -0
  65. package/dist/components/ai/SelectionActions/index.js.map +1 -0
  66. package/dist/components/ai/StateFlow/index.d.ts +24 -0
  67. package/dist/components/ai/StateFlow/index.js +50 -0
  68. package/dist/components/ai/StateFlow/index.js.map +1 -0
  69. package/dist/components/ai/StreamingText/index.d.ts +44 -0
  70. package/dist/components/ai/StreamingText/index.js +211 -0
  71. package/dist/components/ai/StreamingText/index.js.map +1 -0
  72. package/dist/components/ai/TaskRows/index.d.ts +53 -0
  73. package/dist/components/ai/TaskRows/index.js +186 -0
  74. package/dist/components/ai/TaskRows/index.js.map +1 -0
  75. package/dist/components/ai/Thinking/index.d.ts +47 -0
  76. package/dist/components/ai/Thinking/index.js +197 -0
  77. package/dist/components/ai/Thinking/index.js.map +1 -0
  78. package/dist/components/ai/ToolChips/index.d.ts +21 -0
  79. package/dist/components/ai/ToolChips/index.js +63 -0
  80. package/dist/components/ai/ToolChips/index.js.map +1 -0
  81. package/dist/components/ai/index.d.ts +50 -0
  82. package/dist/components/ai/shared.d.ts +13 -0
  83. package/dist/components/ai/shared.js +25 -0
  84. package/dist/components/ai/shared.js.map +1 -0
  85. package/dist/components/pro/DataTable/DataTable.js +70 -51
  86. package/dist/components/pro/DataTable/DataTable.js.map +1 -1
  87. package/dist/components/pro/DataTable/components/TableBody.d.ts +3 -1
  88. package/dist/components/pro/DataTable/components/TableBody.js +41 -39
  89. package/dist/components/pro/DataTable/components/TableBody.js.map +1 -1
  90. package/dist/components/pro/DataTable/components/TableToolbar.d.ts +2 -1
  91. package/dist/components/pro/DataTable/components/TableToolbar.js +25 -19
  92. package/dist/components/pro/DataTable/components/TableToolbar.js.map +1 -1
  93. package/dist/components/pro/DataTable/index.d.ts +1 -1
  94. package/dist/components/pro/DataTable/rowDetailExtension.js +1 -1
  95. package/dist/components/pro/DataTable/rowDetailExtension.js.map +1 -1
  96. package/dist/components/pro/DataTable/types.d.ts +19 -0
  97. package/dist/data-table.js.map +1 -1
  98. package/dist/dishui.css +1 -1
  99. package/dist/index.d.ts +5 -4
  100. package/dist/index.js +128 -107
  101. package/dist/layouts/Sidebar.d.ts +16 -0
  102. package/dist/layouts/Sidebar.js +85 -52
  103. package/dist/layouts/Sidebar.js.map +1 -1
  104. package/dist/lite.d.ts +2 -0
  105. package/dist/lite.js +22 -21
  106. package/package.json +10 -3
@@ -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 {};
@@ -0,0 +1,235 @@
1
+ import { cn as e } from "../../../utils/cn.js";
2
+ import t from "../../Button/index.js";
3
+ /* empty css */
4
+ import { useEffect as n, useMemo as r, useState as i, useSyncExternalStore as a } from "react";
5
+ import { jsx as o, jsxs as s } from "react/jsx-runtime";
6
+ //#region src/components/ai/DiffTable/index.tsx
7
+ var c = {
8
+ added: "Added",
9
+ removed: "Removed",
10
+ modified: "Changed",
11
+ unchanged: "—",
12
+ acceptAll: "Accept all",
13
+ rejectAll: "Reject all",
14
+ accept: "Accept",
15
+ reject: "Reject",
16
+ accepted: "Accepted",
17
+ rejected: "Rejected",
18
+ status: "Status",
19
+ actions: "Actions",
20
+ empty: "∅"
21
+ };
22
+ function l(e) {
23
+ return typeof e == "object" && !!e;
24
+ }
25
+ function u(e) {
26
+ return e.change ? e.change : Object.values(e.cells).some(l) ? "modified" : void 0;
27
+ }
28
+ function d(e) {
29
+ let t = e.change;
30
+ return t === "added" || t === "removed" ? 1 : Object.values(e.cells).filter(l).length;
31
+ }
32
+ var f = (e, t) => `${e} ${t}${e === 1 ? "" : "s"}`, p = "(prefers-reduced-motion: reduce)", m = (e) => {
33
+ if (typeof window > "u" || !window.matchMedia) return () => {};
34
+ let t = window.matchMedia(p);
35
+ return t.addEventListener("change", e), () => t.removeEventListener("change", e);
36
+ }, h = () => typeof window < "u" && !!window.matchMedia && window.matchMedia(p).matches, g = () => a(m, h, () => !1), _ = () => /* @__PURE__ */ o("svg", {
37
+ width: "14",
38
+ height: "14",
39
+ viewBox: "0 0 24 24",
40
+ fill: "none",
41
+ stroke: "currentColor",
42
+ strokeWidth: "2",
43
+ strokeLinecap: "round",
44
+ strokeLinejoin: "round",
45
+ "aria-hidden": "true",
46
+ children: /* @__PURE__ */ o("path", { d: "M20 6 9 17l-5-5" })
47
+ }), v = () => /* @__PURE__ */ o("svg", {
48
+ width: "14",
49
+ height: "14",
50
+ viewBox: "0 0 24 24",
51
+ fill: "none",
52
+ stroke: "currentColor",
53
+ strokeWidth: "2",
54
+ strokeLinecap: "round",
55
+ strokeLinejoin: "round",
56
+ "aria-hidden": "true",
57
+ children: /* @__PURE__ */ o("path", { d: "M18 6 6 18M6 6l12 12" })
58
+ }), y = (e, t) => e == null || e === "" ? /* @__PURE__ */ o("span", {
59
+ className: "dishui-ai-diff-table__empty",
60
+ children: t
61
+ }) : String(e);
62
+ function b({ columns: a, rows: p, title: m, summary: h, sweeping: b = !1, sweepIntervalMs: x = 220, onAcceptAll: S, onRejectAll: C, onAcceptRow: w, onRejectRow: T, decisions: E, dense: D = !1, labels: O, className: k, ...A }) {
63
+ let j = {
64
+ ...c,
65
+ ...O
66
+ }, M = r(() => p.filter((e) => u(e)).map((e) => e.id), [p]), N = r(() => p.reduce((e, t) => e + d(t), 0), [p]), P = g(), F = b && !P, [I, L] = i(0);
67
+ n(() => {
68
+ if (!F) return;
69
+ let e = M.length, t = window.setInterval(() => {
70
+ L((n) => (n + 1 >= e && window.clearInterval(t), Math.min(n + 1, e)));
71
+ }, Math.max(16, x));
72
+ return () => {
73
+ window.clearInterval(t), L(0);
74
+ };
75
+ }, [
76
+ F,
77
+ x,
78
+ M.length
79
+ ]);
80
+ let R = r(() => F ? new Set(M.slice(0, I)) : null, [
81
+ F,
82
+ M,
83
+ I
84
+ ]), z = !F || I >= M.length, B = !!(w || T), V = !!(S || C), H = `${f(N, "change")} across ${f(M.length, "row")}`;
85
+ return /* @__PURE__ */ s("div", {
86
+ ...A,
87
+ className: e("dishui-ai-diff-table", D && "dishui-ai-diff-table--dense", F && !z && "dishui-ai-diff-table--sweeping", k),
88
+ children: [
89
+ (m || h !== null) && /* @__PURE__ */ s("div", {
90
+ className: "dishui-ai-diff-table__header",
91
+ children: [m && /* @__PURE__ */ o("div", {
92
+ className: "dishui-ai-diff-table__title",
93
+ children: m
94
+ }), /* @__PURE__ */ o("div", {
95
+ className: "dishui-ai-diff-table__summary",
96
+ "aria-live": "polite",
97
+ children: h ?? H
98
+ })]
99
+ }),
100
+ /* @__PURE__ */ o("div", {
101
+ className: "dishui-ai-diff-table__scroll",
102
+ children: /* @__PURE__ */ s("table", {
103
+ className: "dishui-ai-diff-table__table",
104
+ children: [/* @__PURE__ */ o("thead", { children: /* @__PURE__ */ s("tr", { children: [
105
+ /* @__PURE__ */ o("th", {
106
+ scope: "col",
107
+ className: "dishui-ai-diff-table__th dishui-ai-diff-table__th--status",
108
+ children: j.status
109
+ }),
110
+ a.map((t) => /* @__PURE__ */ o("th", {
111
+ scope: "col",
112
+ className: e("dishui-ai-diff-table__th", t.align === "right" && "dishui-ai-diff-table__th--right"),
113
+ children: t.label
114
+ }, t.key)),
115
+ B && /* @__PURE__ */ o("th", {
116
+ scope: "col",
117
+ className: "dishui-ai-diff-table__th dishui-ai-diff-table__th--actions",
118
+ children: /* @__PURE__ */ o("span", {
119
+ className: "dishui-ai-diff-table__sr",
120
+ children: j.actions
121
+ })
122
+ })
123
+ ] }) }), /* @__PURE__ */ o("tbody", { children: p.map((t) => {
124
+ let n = u(t), r = !n || !R || R.has(t.id), i = E?.[t.id];
125
+ return /* @__PURE__ */ s("tr", {
126
+ className: e("dishui-ai-diff-table__row", n && `dishui-ai-diff-table__row--${n}`, n && r && "dishui-ai-diff-table__row--revealed", i && `dishui-ai-diff-table__row--${i}`),
127
+ "data-change": n,
128
+ children: [
129
+ /* @__PURE__ */ o("td", {
130
+ className: "dishui-ai-diff-table__td dishui-ai-diff-table__td--status",
131
+ children: n && r ? /* @__PURE__ */ o("span", {
132
+ className: e("dishui-ai-diff-table__badge", `dishui-ai-diff-table__badge--${n}`),
133
+ children: j[n]
134
+ }) : /* @__PURE__ */ o("span", {
135
+ className: "dishui-ai-diff-table__badge dishui-ai-diff-table__badge--none",
136
+ "aria-hidden": "true",
137
+ children: j.unchanged
138
+ })
139
+ }),
140
+ a.map((i) => {
141
+ let a = t.cells[i.key], c = r && l(a), u = e("dishui-ai-diff-table__td", i.align === "right" && "dishui-ai-diff-table__td--right", i.mono && "dishui-ai-diff-table__td--mono", c && "dishui-ai-diff-table__td--changed");
142
+ return l(a) ? r ? /* @__PURE__ */ o("td", {
143
+ className: u,
144
+ children: /* @__PURE__ */ s("span", {
145
+ className: "dishui-ai-diff-table__change",
146
+ children: [
147
+ /* @__PURE__ */ o("del", {
148
+ className: "dishui-ai-diff-table__before",
149
+ children: y(a.before, j.empty)
150
+ }),
151
+ /* @__PURE__ */ o("span", {
152
+ className: "dishui-ai-diff-table__arrow",
153
+ "aria-hidden": "true",
154
+ children: "→"
155
+ }),
156
+ /* @__PURE__ */ o("ins", {
157
+ className: "dishui-ai-diff-table__after",
158
+ children: y(a.after, j.empty)
159
+ })
160
+ ]
161
+ })
162
+ }, i.key) : /* @__PURE__ */ o("td", {
163
+ className: u,
164
+ children: y(a.before, j.empty)
165
+ }, i.key) : /* @__PURE__ */ o("td", {
166
+ className: u,
167
+ children: n === "removed" && r ? /* @__PURE__ */ o("del", {
168
+ className: "dishui-ai-diff-table__before",
169
+ children: y(a, j.empty)
170
+ }) : n === "added" && r ? /* @__PURE__ */ o("ins", {
171
+ className: "dishui-ai-diff-table__after",
172
+ children: y(a, j.empty)
173
+ }) : y(a, j.empty)
174
+ }, i.key);
175
+ }),
176
+ B && /* @__PURE__ */ o("td", {
177
+ className: "dishui-ai-diff-table__td dishui-ai-diff-table__td--actions",
178
+ children: n && r && (i ? /* @__PURE__ */ s("span", {
179
+ className: e("dishui-ai-diff-table__decision", `dishui-ai-diff-table__decision--${i}`),
180
+ children: [o(i === "accepted" ? _ : v, {}), j[i]]
181
+ }) : /* @__PURE__ */ s("span", {
182
+ className: "dishui-ai-diff-table__row-actions",
183
+ children: [w && /* @__PURE__ */ o("button", {
184
+ type: "button",
185
+ className: "dishui-ai-diff-table__icon-btn",
186
+ "aria-label": j.accept,
187
+ title: j.accept,
188
+ onClick: () => w(t),
189
+ children: /* @__PURE__ */ o(_, {})
190
+ }), T && /* @__PURE__ */ o("button", {
191
+ type: "button",
192
+ className: "dishui-ai-diff-table__icon-btn",
193
+ "aria-label": j.reject,
194
+ title: j.reject,
195
+ onClick: () => T(t),
196
+ children: /* @__PURE__ */ o(v, {})
197
+ })]
198
+ }))
199
+ })
200
+ ]
201
+ }, t.id);
202
+ }) })]
203
+ })
204
+ }),
205
+ V && /* @__PURE__ */ s("div", {
206
+ className: "dishui-ai-diff-table__footer",
207
+ children: [/* @__PURE__ */ o("span", {
208
+ className: "dishui-ai-diff-table__footer-meta",
209
+ children: z ? H : "Reviewing…"
210
+ }), /* @__PURE__ */ s("span", {
211
+ className: "dishui-ai-diff-table__footer-actions",
212
+ children: [C && /* @__PURE__ */ o(t, {
213
+ type: "button",
214
+ variant: "secondary",
215
+ size: "sm",
216
+ onClick: C,
217
+ disabled: !z,
218
+ children: j.rejectAll
219
+ }), S && /* @__PURE__ */ o(t, {
220
+ type: "button",
221
+ variant: "primary",
222
+ size: "sm",
223
+ onClick: S,
224
+ disabled: !z,
225
+ children: j.acceptAll
226
+ })]
227
+ })]
228
+ })
229
+ ]
230
+ });
231
+ }
232
+ //#endregion
233
+ export { b as default, u as diffRowChange, l as isDiffCellChange };
234
+
235
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/DiffTable/index.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useState, useSyncExternalStore } from 'react';\nimport { cn } from '../../../utils/cn';\nimport Button from '../../Button';\nimport './DiffTable.css';\n\nexport type DiffTableColumn = {\n key: string;\n label: React.ReactNode;\n align?: 'left' | 'right';\n /** Render the cell in the mono font (IDs, SKUs). */\n mono?: boolean;\n};\n\nexport type DiffCellValue = string | number | null;\n\n/** A plain value is unchanged; an object describes a `before → after` edit. */\nexport type DiffCell = DiffCellValue | { before?: DiffCellValue; after?: DiffCellValue };\n\nexport type DiffRowChange = 'added' | 'removed' | 'modified';\n\nexport type DiffRow = {\n id: string;\n cells: Record<string, DiffCell>;\n /** Row-level change. Omitted rows are inferred as `modified` when any cell is an edit. */\n change?: DiffRowChange;\n};\n\nexport type DiffDecision = 'accepted' | 'rejected';\n\nexport type DiffTableProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'title' | 'summary'> & {\n columns: DiffTableColumn[];\n rows: DiffRow[];\n title?: React.ReactNode;\n /** Summary line under the title. Auto-computed (`3 changes across 2 rows`) when omitted. */\n summary?: React.ReactNode;\n /** Reveal changed rows one by one, top to bottom. */\n sweeping?: boolean;\n /** Milliseconds between each revealed row while sweeping. */\n sweepIntervalMs?: number;\n onAcceptAll?: () => void;\n onRejectAll?: () => void;\n onAcceptRow?: (row: DiffRow) => void;\n onRejectRow?: (row: DiffRow) => void;\n /** Controlled per-row decisions, keyed by row id. */\n decisions?: Record<string, DiffDecision>;\n dense?: boolean;\n /** Text overrides. */\n labels?: Partial<typeof DEFAULT_LABELS>;\n};\n\nconst DEFAULT_LABELS = {\n added: 'Added',\n removed: 'Removed',\n modified: 'Changed',\n unchanged: '—',\n acceptAll: 'Accept all',\n rejectAll: 'Reject all',\n accept: 'Accept',\n reject: 'Reject',\n accepted: 'Accepted',\n rejected: 'Rejected',\n status: 'Status',\n actions: 'Actions',\n empty: '∅',\n};\n\nexport function isDiffCellChange(cell: DiffCell): cell is { before?: DiffCellValue; after?: DiffCellValue } {\n return typeof cell === 'object' && cell !== null;\n}\n\n/** Infer the row's change kind from its explicit flag or its cells. */\nexport function diffRowChange(row: DiffRow): DiffRowChange | undefined {\n if (row.change) return row.change;\n return Object.values(row.cells).some(isDiffCellChange) ? 'modified' : undefined;\n}\n\n/** Number of changed cells in a row (whole row counts as one for added/removed). */\nfunction countRowChanges(row: DiffRow): number {\n const change = row.change;\n if (change === 'added' || change === 'removed') return 1;\n return Object.values(row.cells).filter(isDiffCellChange).length;\n}\n\nconst plural = (n: number, word: string) => `${n} ${word}${n === 1 ? '' : 's'}`;\n\nconst REDUCED_MOTION = '(prefers-reduced-motion: reduce)';\nconst subscribeReducedMotion = (onChange: () => void) => {\n if (typeof window === 'undefined' || !window.matchMedia) return () => {};\n const mq = window.matchMedia(REDUCED_MOTION);\n mq.addEventListener('change', onChange);\n return () => mq.removeEventListener('change', onChange);\n};\nconst getReducedMotion = () => typeof window !== 'undefined' && !!window.matchMedia && window.matchMedia(REDUCED_MOTION).matches;\nconst usePrefersReducedMotion = () => useSyncExternalStore(subscribeReducedMotion, getReducedMotion, () => false);\n\nconst CheckIcon = () => (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n);\nconst XIcon = () => (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n);\n\nconst renderValue = (value: DiffCellValue | undefined, empty: string) =>\n value === null || value === undefined || value === '' ? <span className=\"dishui-ai-diff-table__empty\">{empty}</span> : String(value);\n\n/**\n * AI-proposed edits sweeping through tabular data. Changed cells show the\n * old value struck through next to the new one; added/removed rows are\n * tinted and always labelled in the leading status column.\n */\nexport default function DiffTable({\n columns,\n rows,\n title,\n summary,\n sweeping: sweepingProp = false,\n sweepIntervalMs = 220,\n onAcceptAll,\n onRejectAll,\n onAcceptRow,\n onRejectRow,\n decisions,\n dense = false,\n labels: labelOverrides,\n className,\n ...rest\n}: DiffTableProps) {\n const labels = { ...DEFAULT_LABELS, ...labelOverrides };\n\n const changedIds = useMemo(() => rows.filter(r => diffRowChange(r)).map(r => r.id), [rows]);\n const changeCount = useMemo(() => rows.reduce((n, r) => n + countRowChanges(r), 0), [rows]);\n\n // Reduced motion: skip the sweep and show every change at once.\n const reducedMotion = usePrefersReducedMotion();\n const sweeping = sweepingProp && !reducedMotion;\n\n // Sweep: reveal one changed row per interval. `revealed` counts changed rows (top to bottom).\n const [revealed, setRevealed] = useState(0);\n useEffect(() => {\n if (!sweeping) return;\n const total = changedIds.length;\n const id = window.setInterval(() => {\n setRevealed(n => {\n if (n + 1 >= total) window.clearInterval(id);\n return Math.min(n + 1, total);\n });\n }, Math.max(16, sweepIntervalMs));\n return () => {\n window.clearInterval(id);\n // Restart from the top the next time a sweep begins.\n setRevealed(0);\n };\n }, [sweeping, sweepIntervalMs, changedIds.length]);\n\n const revealedIds = useMemo(() => {\n if (!sweeping) return null;\n return new Set(changedIds.slice(0, revealed));\n }, [sweeping, changedIds, revealed]);\n\n const done = !sweeping || revealed >= changedIds.length;\n const hasRowActions = Boolean(onAcceptRow || onRejectRow);\n const hasFooter = Boolean(onAcceptAll || onRejectAll);\n\n const autoSummary = `${plural(changeCount, 'change')} across ${plural(changedIds.length, 'row')}`;\n\n return (\n <div\n {...rest}\n className={cn('dishui-ai-diff-table', dense && 'dishui-ai-diff-table--dense', sweeping && !done && 'dishui-ai-diff-table--sweeping', className)}\n >\n {(title || summary !== null) && (\n <div className=\"dishui-ai-diff-table__header\">\n {title && <div className=\"dishui-ai-diff-table__title\">{title}</div>}\n <div className=\"dishui-ai-diff-table__summary\" aria-live=\"polite\">\n {summary ?? autoSummary}\n </div>\n </div>\n )}\n\n <div className=\"dishui-ai-diff-table__scroll\">\n <table className=\"dishui-ai-diff-table__table\">\n <thead>\n <tr>\n <th scope=\"col\" className=\"dishui-ai-diff-table__th dishui-ai-diff-table__th--status\">{labels.status}</th>\n {columns.map(col => (\n <th\n key={col.key}\n scope=\"col\"\n className={cn('dishui-ai-diff-table__th', col.align === 'right' && 'dishui-ai-diff-table__th--right')}\n >\n {col.label}\n </th>\n ))}\n {hasRowActions && (\n <th scope=\"col\" className=\"dishui-ai-diff-table__th dishui-ai-diff-table__th--actions\">\n <span className=\"dishui-ai-diff-table__sr\">{labels.actions}</span>\n </th>\n )}\n </tr>\n </thead>\n <tbody>\n {rows.map(row => {\n const change = diffRowChange(row);\n const visible = !change || !revealedIds || revealedIds.has(row.id);\n const decision = decisions?.[row.id];\n return (\n <tr\n key={row.id}\n className={cn(\n 'dishui-ai-diff-table__row',\n change && `dishui-ai-diff-table__row--${change}`,\n change && visible && 'dishui-ai-diff-table__row--revealed',\n decision && `dishui-ai-diff-table__row--${decision}`,\n )}\n data-change={change}\n >\n <td className=\"dishui-ai-diff-table__td dishui-ai-diff-table__td--status\">\n {change && visible ? (\n <span className={cn('dishui-ai-diff-table__badge', `dishui-ai-diff-table__badge--${change}`)}>\n {labels[change]}\n </span>\n ) : (\n <span className=\"dishui-ai-diff-table__badge dishui-ai-diff-table__badge--none\" aria-hidden=\"true\">\n {labels.unchanged}\n </span>\n )}\n </td>\n {columns.map(col => {\n const cell = row.cells[col.key];\n const changed = visible && isDiffCellChange(cell);\n const tdClass = cn(\n 'dishui-ai-diff-table__td',\n col.align === 'right' && 'dishui-ai-diff-table__td--right',\n col.mono && 'dishui-ai-diff-table__td--mono',\n changed && 'dishui-ai-diff-table__td--changed',\n );\n if (isDiffCellChange(cell)) {\n if (!visible) {\n return <td key={col.key} className={tdClass}>{renderValue(cell.before, labels.empty)}</td>;\n }\n return (\n <td key={col.key} className={tdClass}>\n <span className=\"dishui-ai-diff-table__change\">\n <del className=\"dishui-ai-diff-table__before\">{renderValue(cell.before, labels.empty)}</del>\n <span className=\"dishui-ai-diff-table__arrow\" aria-hidden=\"true\">→</span>\n <ins className=\"dishui-ai-diff-table__after\">{renderValue(cell.after, labels.empty)}</ins>\n </span>\n </td>\n );\n }\n return (\n <td key={col.key} className={tdClass}>\n {change === 'removed' && visible ? (\n <del className=\"dishui-ai-diff-table__before\">{renderValue(cell, labels.empty)}</del>\n ) : change === 'added' && visible ? (\n <ins className=\"dishui-ai-diff-table__after\">{renderValue(cell, labels.empty)}</ins>\n ) : (\n renderValue(cell, labels.empty)\n )}\n </td>\n );\n })}\n {hasRowActions && (\n <td className=\"dishui-ai-diff-table__td dishui-ai-diff-table__td--actions\">\n {change && visible && (\n decision ? (\n <span className={cn('dishui-ai-diff-table__decision', `dishui-ai-diff-table__decision--${decision}`)}>\n {decision === 'accepted' ? <CheckIcon /> : <XIcon />}\n {labels[decision]}\n </span>\n ) : (\n <span className=\"dishui-ai-diff-table__row-actions\">\n {onAcceptRow && (\n <button type=\"button\" className=\"dishui-ai-diff-table__icon-btn\" aria-label={labels.accept} title={labels.accept} onClick={() => onAcceptRow(row)}>\n <CheckIcon />\n </button>\n )}\n {onRejectRow && (\n <button type=\"button\" className=\"dishui-ai-diff-table__icon-btn\" aria-label={labels.reject} title={labels.reject} onClick={() => onRejectRow(row)}>\n <XIcon />\n </button>\n )}\n </span>\n )\n )}\n </td>\n )}\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n\n {hasFooter && (\n <div className=\"dishui-ai-diff-table__footer\">\n <span className=\"dishui-ai-diff-table__footer-meta\">{done ? autoSummary : 'Reviewing…'}</span>\n <span className=\"dishui-ai-diff-table__footer-actions\">\n {onRejectAll && (\n <Button type=\"button\" variant=\"secondary\" size=\"sm\" onClick={onRejectAll} disabled={!done}>\n {labels.rejectAll}\n </Button>\n )}\n {onAcceptAll && (\n <Button type=\"button\" variant=\"primary\" size=\"sm\" onClick={onAcceptAll} disabled={!done}>\n {labels.acceptAll}\n </Button>\n )}\n </span>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;AAkDA,IAAM,IAAiB;CACrB,OAAO;CACP,SAAS;CACT,UAAU;CACV,WAAW;CACX,WAAW;CACX,WAAW;CACX,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,UAAU;CACV,QAAQ;CACR,SAAS;CACT,OAAO;AACT;AAEA,SAAgB,EAAiB,GAA2E;CAC1G,OAAO,OAAO,KAAS,cAAY;AACrC;AAGA,SAAgB,EAAc,GAAyC;CAErE,OADI,EAAI,SAAe,EAAI,SACpB,OAAO,OAAO,EAAI,KAAK,CAAC,CAAC,KAAK,CAAgB,IAAI,aAAa,KAAA;AACxE;AAGA,SAAS,EAAgB,GAAsB;CAC7C,IAAM,IAAS,EAAI;CAEnB,OADI,MAAW,WAAW,MAAW,YAAkB,IAChD,OAAO,OAAO,EAAI,KAAK,CAAC,CAAC,OAAO,CAAgB,CAAC,CAAC;AAC3D;AAEA,IAAM,KAAU,GAAW,MAAiB,GAAG,EAAE,GAAG,IAAO,MAAM,IAAI,KAAK,OAEpE,IAAiB,oCACjB,KAA0B,MAAyB;CACvD,IAAI,OAAO,SAAW,OAAe,CAAC,OAAO,YAAY,aAAa,CAAC;CACvE,IAAM,IAAK,OAAO,WAAW,CAAc;CAE3C,OADA,EAAG,iBAAiB,UAAU,CAAQ,SACzB,EAAG,oBAAoB,UAAU,CAAQ;AACxD,GACM,UAAyB,OAAO,SAAW,OAAe,CAAC,CAAC,OAAO,cAAc,OAAO,WAAW,CAAc,CAAC,CAAC,SACnH,UAAgC,EAAqB,GAAwB,SAAwB,EAAK,GAE1G,UACJ,kBAAC,OAAD;CAAK,OAAM;CAAK,QAAO;CAAK,SAAQ;CAAY,MAAK;CAAO,QAAO;CAAe,aAAY;CAAI,eAAc;CAAQ,gBAAe;CAAQ,eAAY;CACzJ,UAAA,kBAAC,QAAD,EAAM,GAAE,kBAAmB,CAAA;AACxB,CAAA,GAED,UACJ,kBAAC,OAAD;CAAK,OAAM;CAAK,QAAO;CAAK,SAAQ;CAAY,MAAK;CAAO,QAAO;CAAe,aAAY;CAAI,eAAc;CAAQ,gBAAe;CAAQ,eAAY;CACzJ,UAAA,kBAAC,QAAD,EAAM,GAAE,uBAAwB,CAAA;AAC7B,CAAA,GAGD,KAAe,GAAkC,MACrD,KAAU,QAA+B,MAAU,KAAK,kBAAC,QAAD;CAAM,WAAU;CAA+B,UAAA;AAAY,CAAA,IAAI,OAAO,CAAK;AAOrI,SAAwB,EAAU,EAChC,YACA,SACA,UACA,YACA,UAAU,IAAe,IACzB,qBAAkB,KAClB,gBACA,gBACA,gBACA,gBACA,cACA,WAAQ,IACR,QAAQ,GACR,cACA,GAAG,KACc;CACjB,IAAM,IAAS;EAAE,GAAG;EAAgB,GAAG;CAAe,GAEhD,IAAa,QAAc,EAAK,QAAO,MAAK,EAAc,CAAC,CAAC,CAAC,CAAC,KAAI,MAAK,EAAE,EAAE,GAAG,CAAC,CAAI,CAAC,GACpF,IAAc,QAAc,EAAK,QAAQ,GAAG,MAAM,IAAI,EAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAI,CAAC,GAGpF,IAAgB,EAAwB,GACxC,IAAW,KAAgB,CAAC,GAG5B,CAAC,GAAU,KAAe,EAAS,CAAC;CAC1C,QAAgB;EACd,IAAI,CAAC,GAAU;EACf,IAAM,IAAQ,EAAW,QACnB,IAAK,OAAO,kBAAkB;GAClC,GAAY,OACN,IAAI,KAAK,KAAO,OAAO,cAAc,CAAE,GACpC,KAAK,IAAI,IAAI,GAAG,CAAK,EAC7B;EACH,GAAG,KAAK,IAAI,IAAI,CAAe,CAAC;EAChC,aAAa;GAGX,AAFA,OAAO,cAAc,CAAE,GAEvB,EAAY,CAAC;EACf;CACF,GAAG;EAAC;EAAU;EAAiB,EAAW;CAAM,CAAC;CAEjD,IAAM,IAAc,QACb,IACE,IAAI,IAAI,EAAW,MAAM,GAAG,CAAQ,CAAC,IADtB,MAErB;EAAC;EAAU;EAAY;CAAQ,CAAC,GAE7B,IAAO,CAAC,KAAY,KAAY,EAAW,QAC3C,IAAgB,GAAQ,KAAe,IACvC,IAAY,GAAQ,KAAe,IAEnC,IAAc,GAAG,EAAO,GAAa,QAAQ,EAAE,UAAU,EAAO,EAAW,QAAQ,KAAK;CAE9F,OACE,kBAAC,OAAD;EACE,GAAI;EACJ,WAAW,EAAG,wBAAwB,KAAS,+BAA+B,KAAY,CAAC,KAAQ,kCAAkC,CAAS;EAFhJ,UAAA;IAII,KAAS,MAAY,SACrB,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACG,KAAS,kBAAC,OAAD;KAAK,WAAU;KAA+B,UAAA;IAAW,CAAA,GACnE,kBAAC,OAAD;KAAK,WAAU;KAAgC,aAAU;KACtD,UAAA,KAAW;IACT,CAAA,CACF;;GAGP,kBAAC,OAAD;IAAK,WAAU;IACb,UAAA,kBAAC,SAAD;KAAO,WAAU;KAAjB,UAAA,CACE,kBAAC,SAAD,EAAA,UACE,kBAAC,MAAD,EAAA,UAAA;MACE,kBAAC,MAAD;OAAI,OAAM;OAAM,WAAU;OAA6D,UAAA,EAAO;MAAW,CAAA;MACxG,EAAQ,KAAI,MACX,kBAAC,MAAD;OAEE,OAAM;OACN,WAAW,EAAG,4BAA4B,EAAI,UAAU,WAAW,iCAAiC;OAEnG,UAAA,EAAI;MACH,GALG,EAAI,GAKP,CACL;MACA,KACC,kBAAC,MAAD;OAAI,OAAM;OAAM,WAAU;OACxB,UAAA,kBAAC,QAAD;QAAM,WAAU;QAA4B,UAAA,EAAO;OAAc,CAAA;MAC/D,CAAA;KAEJ,EAAA,CAAA,EACC,CAAA,GACP,kBAAC,SAAD,EAAA,UACG,EAAK,KAAI,MAAO;MACf,IAAM,IAAS,EAAc,CAAG,GAC1B,IAAU,CAAC,KAAU,CAAC,KAAe,EAAY,IAAI,EAAI,EAAE,GAC3D,IAAW,IAAY,EAAI;MACjC,OACE,kBAAC,MAAD;OAEE,WAAW,EACT,6BACA,KAAU,8BAA8B,KACxC,KAAU,KAAW,uCACrB,KAAY,8BAA8B,GAC5C;OACA,eAAa;OARf,UAAA;QAUE,kBAAC,MAAD;SAAI,WAAU;SACX,UAAA,KAAU,IACT,kBAAC,QAAD;UAAM,WAAW,EAAG,+BAA+B,gCAAgC,GAAQ;UACxF,UAAA,EAAO;SACJ,CAAA,IAEN,kBAAC,QAAD;UAAM,WAAU;UAAgE,eAAY;UACzF,UAAA,EAAO;SACJ,CAAA;QAEN,CAAA;QACH,EAAQ,KAAI,MAAO;SAClB,IAAM,IAAO,EAAI,MAAM,EAAI,MACrB,IAAU,KAAW,EAAiB,CAAI,GAC1C,IAAU,EACd,4BACA,EAAI,UAAU,WAAW,mCACzB,EAAI,QAAQ,kCACZ,KAAW,mCACb;SAeA,OAdI,EAAiB,CAAI,IAClB,IAIH,kBAAC,MAAD;UAAkB,WAAW;UAC3B,UAAA,kBAAC,QAAD;WAAM,WAAU;WAAhB,UAAA;YACE,kBAAC,OAAD;aAAK,WAAU;aAAgC,UAAA,EAAY,EAAK,QAAQ,EAAO,KAAK;YAAO,CAAA;YAC3F,kBAAC,QAAD;aAAM,WAAU;aAA8B,eAAY;aAAO,UAAA;YAAO,CAAA;YACxE,kBAAC,OAAD;aAAK,WAAU;aAA+B,UAAA,EAAY,EAAK,OAAO,EAAO,KAAK;YAAO,CAAA;WACrF;;SACJ,GANK,EAAI,GAMT,IATG,kBAAC,MAAD;UAAkB,WAAW;UAAU,UAAA,EAAY,EAAK,QAAQ,EAAO,KAAK;SAAM,GAAzE,EAAI,GAAqE,IAa3F,kBAAC,MAAD;UAAkB,WAAW;UAC1B,UAAA,MAAW,aAAa,IACvB,kBAAC,OAAD;WAAK,WAAU;WAAgC,UAAA,EAAY,GAAM,EAAO,KAAK;UAAO,CAAA,IAClF,MAAW,WAAW,IACxB,kBAAC,OAAD;WAAK,WAAU;WAA+B,UAAA,EAAY,GAAM,EAAO,KAAK;UAAO,CAAA,IAEnF,EAAY,GAAM,EAAO,KAAK;SAE9B,GARK,EAAI,GAQT;QAER,CAAC;QACA,KACC,kBAAC,MAAD;SAAI,WAAU;SACX,UAAA,KAAU,MACT,IACE,kBAAC,QAAD;UAAM,WAAW,EAAG,kCAAkC,mCAAmC,GAAU;UAAnG,UAAA,CAC6B,EAA1B,MAAa,aAAc,IAAgB,GAAjB,CAAY,CAAY,GAClD,EAAO,EACJ;SAEN,CAAA,IAAA,kBAAC,QAAD;UAAM,WAAU;UAAhB,UAAA,CACG,KACC,kBAAC,UAAD;WAAQ,MAAK;WAAS,WAAU;WAAiC,cAAY,EAAO;WAAQ,OAAO,EAAO;WAAQ,eAAe,EAAY,CAAG;WAC9I,UAAA,kBAAC,GAAD,CAAY,CAAA;UACN,CAAA,GAET,KACC,kBAAC,UAAD;WAAQ,MAAK;WAAS,WAAU;WAAiC,cAAY,EAAO;WAAQ,OAAO,EAAO;WAAQ,eAAe,EAAY,CAAG;WAC9I,UAAA,kBAAC,GAAD,CAAQ,CAAA;UACF,CAAA,CAEN;;QAGR,CAAA;OAEJ;MAhFG,GAAA,EAAI,EAgFP;KAER,CAAC,EACI,CAAA,CACF;;GACJ,CAAA;GAEJ,KACC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,QAAD;KAAM,WAAU;KAAqC,UAAA,IAAO,IAAc;IAAmB,CAAA,GAC7F,kBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA,CACG,KACC,kBAAC,GAAD;MAAQ,MAAK;MAAS,SAAQ;MAAY,MAAK;MAAK,SAAS;MAAa,UAAU,CAAC;MAClF,UAAA,EAAO;KACF,CAAA,GAET,KACC,kBAAC,GAAD;MAAQ,MAAK;MAAS,SAAQ;MAAU,MAAK;MAAK,SAAS;MAAa,UAAU,CAAC;MAChF,UAAA,EAAO;KACF,CAAA,CAEN;IACH,CAAA,CAAA;;EAEJ;;AAET"}
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ export type FilterTableColumn<Row> = {
3
+ key: string;
4
+ label: React.ReactNode;
5
+ render?: (row: Row) => React.ReactNode;
6
+ value?: (row: Row) => string | number;
7
+ align?: 'left' | 'right';
8
+ mono?: boolean;
9
+ };
10
+ export type FilterTableFilter<Row> = {
11
+ id: string;
12
+ label: string;
13
+ predicate: (row: Row) => boolean;
14
+ };
15
+ export type FilterTableProps<Row extends {
16
+ id: string;
17
+ }> = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {
18
+ rows: Row[];
19
+ columns: FilterTableColumn<Row>[];
20
+ filters?: FilterTableFilter<Row>[];
21
+ value?: string;
22
+ defaultValue?: string;
23
+ onChange?: (id: string) => void;
24
+ search?: string;
25
+ defaultSearch?: string;
26
+ onSearchChange?: (query: string) => void;
27
+ searchPlaceholder?: string;
28
+ emptyText?: React.ReactNode;
29
+ noResultsText?: React.ReactNode;
30
+ caption?: React.ReactNode;
31
+ loading?: boolean;
32
+ };
33
+ export default function FilterTable<Row extends {
34
+ id: string;
35
+ }>({ rows, columns, filters, value, defaultValue, onChange, search, defaultSearch, onSearchChange, searchPlaceholder, emptyText, noResultsText, caption, loading, className, ...rest }: FilterTableProps<Row>): React.JSX.Element;
@@ -0,0 +1,86 @@
1
+ import { cn as e } from "../../../utils/cn.js";
2
+ import t from "../../Table/index.js";
3
+ import n from "../../Skeleton/index.js";
4
+ /* empty css */
5
+ import { useMemo as r, useState as i } from "react";
6
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
7
+ //#region src/components/ai/FilterTable/index.tsx
8
+ var s = [];
9
+ function c({ rows: c, columns: l, filters: u = s, value: d, defaultValue: f = "all", onChange: p, search: m, defaultSearch: h = "", onSearchChange: g, searchPlaceholder: _ = "Filter records…", emptyText: v = "No records yet", noResultsText: y = "No matching records", caption: b, loading: x = !1, className: S, ...C }) {
10
+ let [w, T] = i(f), [E, D] = i(h), O = d ?? w, k = m ?? E, A = r(() => c.filter((e) => {
11
+ let t = u.find((e) => e.id === O);
12
+ return t && !t.predicate(e) ? !1 : !k.trim() || l.some((t) => String(t.value?.(e) ?? e[t.key] ?? "").toLowerCase().includes(k.trim().toLowerCase()));
13
+ }), [
14
+ c,
15
+ l,
16
+ u,
17
+ O,
18
+ k
19
+ ]), j = (e) => {
20
+ d === void 0 && T(e), p?.(e);
21
+ }, M = (e) => {
22
+ m === void 0 && D(e), g?.(e);
23
+ };
24
+ return /* @__PURE__ */ o("div", {
25
+ ...C,
26
+ className: e("dishui-ai-filter-table", S),
27
+ "aria-busy": x || void 0,
28
+ children: [/* @__PURE__ */ o("div", {
29
+ className: "dishui-ai-filter-table__toolbar",
30
+ children: [/* @__PURE__ */ o("div", {
31
+ className: "dishui-ai-filter-table__filters",
32
+ role: "group",
33
+ "aria-label": "Table filters",
34
+ children: [/* @__PURE__ */ o("button", {
35
+ type: "button",
36
+ "aria-pressed": O === "all",
37
+ onClick: () => j("all"),
38
+ children: ["All ", /* @__PURE__ */ a("span", { children: c.length })]
39
+ }), u.map((e) => /* @__PURE__ */ o("button", {
40
+ type: "button",
41
+ "aria-pressed": O === e.id,
42
+ onClick: () => j(e.id),
43
+ children: [
44
+ e.label,
45
+ " ",
46
+ /* @__PURE__ */ a("span", { children: c.filter(e.predicate).length })
47
+ ]
48
+ }, e.id))]
49
+ }), /* @__PURE__ */ a("input", {
50
+ type: "search",
51
+ "aria-label": _,
52
+ placeholder: _,
53
+ value: k,
54
+ onChange: (e) => M(e.target.value)
55
+ })]
56
+ }), /* @__PURE__ */ a("div", {
57
+ className: "dishui-ai-filter-table__scroll",
58
+ children: /* @__PURE__ */ o(t, { children: [
59
+ b && /* @__PURE__ */ a("caption", { children: b }),
60
+ /* @__PURE__ */ a(t.Head, { children: /* @__PURE__ */ a(t.Row, { children: l.map((e) => /* @__PURE__ */ a(t.HeaderCell, {
61
+ className: e.align === "right" ? "dishui-ai-filter-table__right" : void 0,
62
+ children: e.label
63
+ }, e.key)) }) }),
64
+ /* @__PURE__ */ o(t.Body, { children: [x ? [
65
+ "one",
66
+ "two",
67
+ "three"
68
+ ].map((e) => /* @__PURE__ */ a(t.Row, {
69
+ "aria-hidden": "true",
70
+ children: l.map((e) => /* @__PURE__ */ a(t.Cell, { children: /* @__PURE__ */ a(n, { className: "dishui-ai-filter-table__skeleton" }) }, e.key))
71
+ }, e)) : A.map((n) => /* @__PURE__ */ a(t.Row, { children: l.map((r) => /* @__PURE__ */ a(t.Cell, {
72
+ className: e(r.align === "right" && "dishui-ai-filter-table__right", r.mono && "dishui-ai-filter-table__mono"),
73
+ children: r.render ? r.render(n) : String(r.value?.(n) ?? n[r.key] ?? "—")
74
+ }, r.key)) }, n.id)), !x && A.length === 0 && /* @__PURE__ */ a(t.Row, { children: /* @__PURE__ */ a(t.Cell, {
75
+ className: "dishui-ai-filter-table__empty",
76
+ colSpan: l.length,
77
+ children: c.length ? y : v
78
+ }) })] })
79
+ ] })
80
+ })]
81
+ });
82
+ }
83
+ //#endregion
84
+ export { c as default };
85
+
86
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/FilterTable/index.tsx"],"sourcesContent":["import React, { useMemo, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport Table from '../../Table';\nimport Skeleton from '../../Skeleton';\nimport './FilterTable.css';\n\nconst EMPTY_FILTERS: FilterTableFilter<never>[] = [];\n\nexport type FilterTableColumn<Row> = { key: string; label: React.ReactNode; render?: (row: Row) => React.ReactNode; value?: (row: Row) => string | number; align?: 'left' | 'right'; mono?: boolean };\nexport type FilterTableFilter<Row> = { id: string; label: string; predicate: (row: Row) => boolean };\nexport type FilterTableProps<Row extends { id: string }> = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & { rows: Row[]; columns: FilterTableColumn<Row>[]; filters?: FilterTableFilter<Row>[]; value?: string; defaultValue?: string; onChange?: (id: string) => void; search?: string; defaultSearch?: string; onSearchChange?: (query: string) => void; searchPlaceholder?: string; emptyText?: React.ReactNode; noResultsText?: React.ReactNode; caption?: React.ReactNode; loading?: boolean };\n\nexport default function FilterTable<Row extends { id: string }>({ rows, columns, filters = EMPTY_FILTERS as FilterTableFilter<Row>[], value, defaultValue = 'all', onChange, search, defaultSearch = '', onSearchChange, searchPlaceholder = 'Filter records…', emptyText = 'No records yet', noResultsText = 'No matching records', caption, loading = false, className, ...rest }: FilterTableProps<Row>) {\n const [internalFilter, setInternalFilter] = useState(defaultValue); const [internalSearch, setInternalSearch] = useState(defaultSearch); const active = value ?? internalFilter; const query = search ?? internalSearch;\n const shown = useMemo(() => rows.filter(row => { const filter = filters.find(x => x.id === active); if (filter && !filter.predicate(row)) return false; if (!query.trim()) return true; return columns.some(col => String(col.value?.(row) ?? (row as Record<string, unknown>)[col.key] ?? '').toLowerCase().includes(query.trim().toLowerCase())); }), [rows, columns, filters, active, query]);\n const setFilter = (id: string) => { if (value === undefined) setInternalFilter(id); onChange?.(id); };\n const setSearch = (next: string) => { if (search === undefined) setInternalSearch(next); onSearchChange?.(next); };\n return <div {...rest} className={cn('dishui-ai-filter-table', className)} aria-busy={loading || undefined}><div className=\"dishui-ai-filter-table__toolbar\"><div className=\"dishui-ai-filter-table__filters\" role=\"group\" aria-label=\"Table filters\"><button type=\"button\" aria-pressed={active === 'all'} onClick={() => setFilter('all')}>All <span>{rows.length}</span></button>{filters.map(filter => <button key={filter.id} type=\"button\" aria-pressed={active === filter.id} onClick={() => setFilter(filter.id)}>{filter.label} <span>{rows.filter(filter.predicate).length}</span></button>)}</div><input type=\"search\" aria-label={searchPlaceholder} placeholder={searchPlaceholder} value={query} onChange={e => setSearch(e.target.value)}/></div><div className=\"dishui-ai-filter-table__scroll\"><Table>{caption && <caption>{caption}</caption>}<Table.Head><Table.Row>{columns.map(col => <Table.HeaderCell key={col.key} className={col.align === 'right' ? 'dishui-ai-filter-table__right' : undefined}>{col.label}</Table.HeaderCell>)}</Table.Row></Table.Head><Table.Body>{loading ? ['one', 'two', 'three'].map(rowKey => <Table.Row key={rowKey} aria-hidden=\"true\">{columns.map(col => <Table.Cell key={col.key}><Skeleton className=\"dishui-ai-filter-table__skeleton\" /></Table.Cell>)}</Table.Row>) : shown.map(row => <Table.Row key={row.id}>{columns.map(col => <Table.Cell key={col.key} className={cn(col.align === 'right' && 'dishui-ai-filter-table__right', col.mono && 'dishui-ai-filter-table__mono')}>{col.render ? col.render(row) : String(col.value?.(row) ?? (row as Record<string, unknown>)[col.key] ?? '—')}</Table.Cell>)}</Table.Row>)}{!loading && shown.length === 0 && <Table.Row><Table.Cell className=\"dishui-ai-filter-table__empty\" colSpan={columns.length}>{rows.length ? noResultsText : emptyText}</Table.Cell></Table.Row>}</Table.Body></Table></div></div>;\n}\n"],"mappings":";;;;;;;AAMA,IAAM,IAA4C,CAAC;AAMnD,SAAwB,EAAwC,EAAE,SAAM,YAAS,aAAU,GAA2C,UAAO,kBAAe,OAAO,aAAU,WAAQ,mBAAgB,IAAI,mBAAgB,uBAAoB,mBAAmB,eAAY,kBAAkB,mBAAgB,uBAAuB,YAAS,aAAU,IAAO,cAAW,GAAG,KAA+B;CAC1Y,IAAM,CAAC,GAAgB,KAAqB,EAAS,CAAY,GAAS,CAAC,GAAgB,KAAqB,EAAS,CAAa,GAAS,IAAS,KAAS,GAAsB,IAAQ,KAAU,GACnM,IAAQ,QAAc,EAAK,QAAO,MAAO;EAAE,IAAM,IAAS,EAAQ,MAAK,MAAK,EAAE,OAAO,CAAM;EAAuF,OAAhF,KAAU,CAAC,EAAO,UAAU,CAAG,IAAU,KAAO,CAAK,EAAM,KAAK,KAAuB,EAAQ,MAAK,MAAO,OAAO,EAAI,QAAQ,CAAG,KAAM,EAAgC,EAAI,QAAQ,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC,SAAS,EAAM,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC;CAAG,CAAC,GAAG;EAAC;EAAM;EAAS;EAAS;EAAQ;CAAK,CAAC,GACzX,KAAa,MAAe;EAAkD,AAA5C,MAAU,KAAA,KAAW,EAAkB,CAAE,GAAG,IAAW,CAAE;CAAG,GAC9F,KAAa,MAAiB;EAAqD,AAA/C,MAAW,KAAA,KAAW,EAAkB,CAAI,GAAG,IAAiB,CAAI;CAAG;CACjH,OAAO,kBAAC,OAAD;EAAK,GAAI;EAAM,WAAW,EAAG,0BAA0B,CAAS;EAAG,aAAW,KAAW,KAAA;EAAzF,UAAA,CAAoG,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CAAiD,kBAAC,OAAD;IAAK,WAAU;IAAkC,MAAK;IAAQ,cAAW;IAAzE,UAAA,CAAyF,kBAAC,UAAD;KAAQ,MAAK;KAAS,gBAAc,MAAW;KAAO,eAAe,EAAU,KAAK;KAApF,UAAA,CAAuF,QAAI,kBAAC,QAAD,EAAA,UAAO,EAAK,OAAa,CAAA,CAAS;IAAE,CAAA,GAAA,EAAQ,KAAI,MAAU,kBAAC,UAAD;KAAwB,MAAK;KAAS,gBAAc,MAAW,EAAO;KAAI,eAAe,EAAU,EAAO,EAAE;KAA5G,UAAA;MAAgH,EAAO;MAAM;MAAC,kBAAC,QAAD,EAAA,UAAO,EAAK,OAAO,EAAO,SAAS,CAAC,CAAC,OAAa,CAAA;KAAS;IAA5K,GAAA,EAAO,EAAqK,CAAC,CAAO;GAAC,CAAA,GAAA,kBAAC,SAAD;IAAO,MAAK;IAAS,cAAY;IAAmB,aAAa;IAAmB,OAAO;IAAO,WAAU,MAAK,EAAU,EAAE,OAAO,KAAK;GAAG,CAAA,CAAM;EAAC,CAAA,GAAA,kBAAC,OAAD;GAAK,WAAU;GAAiC,UAAA,kBAAC,GAAD,EAAA,UAAA;IAAQ,KAAW,kBAAC,WAAD,EAAA,UAAU,EAAiB,CAAA;IAAE,kBAAC,EAAM,MAAP,EAAA,UAAY,kBAAC,EAAM,KAAP,EAAA,UAAY,EAAQ,KAAI,MAAO,kBAAC,EAAM,YAAP;KAAgC,WAAW,EAAI,UAAU,UAAU,kCAAkC,KAAA;KAAY,UAAA,EAAI;IAAwB,GAAtH,EAAI,GAAkH,CAAC,EAAa,CAAA,EAAa,CAAA;IAAC,kBAAC,EAAM,MAAP,EAAA,UAAA,CAAa,IAAU;KAAC;KAAO;KAAO;IAAO,CAAC,CAAC,KAAI,MAAU,kBAAC,EAAM,KAAP;KAAwB,eAAY;KAAQ,UAAA,EAAQ,KAAI,MAAO,kBAAC,EAAM,MAAP,EAAA,UAA0B,kBAAC,GAAD,EAAU,WAAU,mCAAoC,CAAA,EAAa,GAA9E,EAAI,GAA0E,CAAC;IAAa,GAA5J,CAA4J,CAAC,IAAI,EAAM,KAAI,MAAO,kBAAC,EAAM,KAAP,EAAA,UAAyB,EAAQ,KAAI,MAAO,kBAAC,EAAM,MAAP;KAA0B,WAAW,EAAG,EAAI,UAAU,WAAW,iCAAiC,EAAI,QAAQ,8BAA8B;KAAI,UAAA,EAAI,SAAS,EAAI,OAAO,CAAG,IAAI,OAAO,EAAI,QAAQ,CAAG,KAAM,EAAgC,EAAI,QAAQ,GAAG;IAAc,GAAvP,EAAI,GAAmP,CAAC,EAAa,GAAlT,EAAI,EAA8S,CAAC,GAAG,CAAC,KAAW,EAAM,WAAW,KAAK,kBAAC,EAAM,KAAP,EAAA,UAAW,kBAAC,EAAM,MAAP;KAAY,WAAU;KAAgC,SAAS,EAAQ;KAAS,UAAA,EAAK,SAAS,IAAgB;IAAsB,CAAA,EAAY,CAAA,CAAc,EAAA,CAAA;GAAQ,EAAA,CAAA;EAAM,CAAA,CAAM;;AACzzD"}
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ export type FineTuneMetric = {
3
+ label: React.ReactNode;
4
+ value: React.ReactNode;
5
+ };
6
+ export type FineTuneCardProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> & {
7
+ title: React.ReactNode;
8
+ model?: string;
9
+ description?: React.ReactNode;
10
+ status?: 'draft' | 'queued' | 'training' | 'ready' | 'failed';
11
+ progress?: number;
12
+ metrics?: FineTuneMetric[];
13
+ error?: React.ReactNode;
14
+ onStart?: () => void;
15
+ onCancel?: () => void;
16
+ onRetry?: () => void;
17
+ disabled?: boolean;
18
+ labels?: {
19
+ start?: string;
20
+ cancel?: string;
21
+ retry?: string;
22
+ };
23
+ };
24
+ export default function FineTuneCard({ title, model, description, status, progress, metrics, error, onStart, onCancel, onRetry, disabled, labels, className, ...rest }: FineTuneCardProps): React.JSX.Element;
@@ -0,0 +1,75 @@
1
+ import { cn as e } from "../../../utils/cn.js";
2
+ import t from "../../Button/index.js";
3
+ import { clamp as n } from "../shared.js";
4
+ /* empty css */
5
+ import "react";
6
+ import { jsx as r, jsxs as i } from "react/jsx-runtime";
7
+ //#region src/components/ai/FineTuneCard/index.tsx
8
+ var a = {
9
+ draft: "Draft",
10
+ queued: "Queued",
11
+ training: "Training",
12
+ ready: "Ready",
13
+ failed: "Failed"
14
+ }, o = [];
15
+ function s({ title: s, model: c, description: l, status: u = "draft", progress: d = 0, metrics: f = o, error: p, onStart: m, onCancel: h, onRetry: g, disabled: _ = !1, labels: v, className: y, ...b }) {
16
+ let x = Math.round(n(d, 0, 1) * 100), S = u === "queued" || u === "training";
17
+ return /* @__PURE__ */ i("article", {
18
+ ...b,
19
+ className: e("dishui-ai-fine-tune-card", `dishui-ai-fine-tune-card--${u}`, y),
20
+ children: [
21
+ /* @__PURE__ */ i("header", { children: [/* @__PURE__ */ i("div", { children: [/* @__PURE__ */ r("h3", { children: s }), c && /* @__PURE__ */ r("code", { children: c })] }), /* @__PURE__ */ r("span", {
22
+ className: "dishui-ai-fine-tune-card__status",
23
+ children: a[u]
24
+ })] }),
25
+ l && /* @__PURE__ */ r("div", {
26
+ className: "dishui-ai-fine-tune-card__description",
27
+ children: l
28
+ }),
29
+ S && /* @__PURE__ */ i("div", {
30
+ className: "dishui-ai-fine-tune-card__progress",
31
+ children: [/* @__PURE__ */ i("div", { children: [/* @__PURE__ */ r("span", { children: "Training progress" }), /* @__PURE__ */ i("strong", { children: [x, "%"] })] }), /* @__PURE__ */ i("progress", {
32
+ max: 100,
33
+ value: x,
34
+ children: [x, "%"]
35
+ })]
36
+ }),
37
+ f.length > 0 && /* @__PURE__ */ r("dl", { children: f.map((e) => /* @__PURE__ */ i("div", { children: [/* @__PURE__ */ r("dt", { children: e.label }), /* @__PURE__ */ r("dd", { children: e.value })] }, `${String(e.label)}-${String(e.value)}`)) }),
38
+ u === "failed" && p && /* @__PURE__ */ r("div", {
39
+ role: "alert",
40
+ className: "dishui-ai-fine-tune-card__error",
41
+ children: p
42
+ }),
43
+ /* @__PURE__ */ i("footer", { children: [
44
+ u === "draft" && m && /* @__PURE__ */ r(t, {
45
+ type: "button",
46
+ variant: "primary",
47
+ size: "sm",
48
+ disabled: _,
49
+ onClick: m,
50
+ children: v?.start ?? "Start training"
51
+ }),
52
+ S && h && /* @__PURE__ */ r(t, {
53
+ type: "button",
54
+ variant: "secondary",
55
+ size: "sm",
56
+ disabled: _,
57
+ onClick: h,
58
+ children: v?.cancel ?? "Cancel"
59
+ }),
60
+ u === "failed" && g && /* @__PURE__ */ r(t, {
61
+ type: "button",
62
+ variant: "primary",
63
+ size: "sm",
64
+ disabled: _,
65
+ onClick: g,
66
+ children: v?.retry ?? "Retry"
67
+ })
68
+ ] })
69
+ ]
70
+ });
71
+ }
72
+ //#endregion
73
+ export { s as default };
74
+
75
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/FineTuneCard/index.tsx"],"sourcesContent":["import React from 'react';\nimport { cn } from '../../../utils/cn';\nimport Button from '../../Button';\nimport { clamp } from '../shared';\nimport './FineTuneCard.css';\n\nexport type FineTuneMetric = {\n label: React.ReactNode;\n value: React.ReactNode;\n};\n\nexport type FineTuneCardProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> & {\n title: React.ReactNode;\n model?: string;\n description?: React.ReactNode;\n status?: 'draft' | 'queued' | 'training' | 'ready' | 'failed';\n progress?: number;\n metrics?: FineTuneMetric[];\n error?: React.ReactNode;\n onStart?: () => void;\n onCancel?: () => void;\n onRetry?: () => void;\n disabled?: boolean;\n labels?: { start?: string; cancel?: string; retry?: string };\n};\n\nconst STATUS = {\n draft: 'Draft',\n queued: 'Queued',\n training: 'Training',\n ready: 'Ready',\n failed: 'Failed',\n} as const;\nconst EMPTY_METRICS: FineTuneMetric[] = [];\n\nexport default function FineTuneCard({\n title,\n model,\n description,\n status = 'draft',\n progress = 0,\n metrics = EMPTY_METRICS,\n error,\n onStart,\n onCancel,\n onRetry,\n disabled = false,\n labels,\n className,\n ...rest\n}: FineTuneCardProps) {\n const pct = Math.round(clamp(progress, 0, 1) * 100);\n const active = status === 'queued' || status === 'training';\n\n return (\n <article {...rest} className={cn('dishui-ai-fine-tune-card', `dishui-ai-fine-tune-card--${status}`, className)}>\n <header>\n <div>\n <h3>{title}</h3>\n {model && <code>{model}</code>}\n </div>\n <span className=\"dishui-ai-fine-tune-card__status\">{STATUS[status]}</span>\n </header>\n\n {description && <div className=\"dishui-ai-fine-tune-card__description\">{description}</div>}\n\n {active && (\n <div className=\"dishui-ai-fine-tune-card__progress\">\n <div><span>Training progress</span><strong>{pct}%</strong></div>\n <progress max={100} value={pct}>{pct}%</progress>\n </div>\n )}\n\n {metrics.length > 0 && (\n <dl>\n {metrics.map(metric => (\n <div key={`${String(metric.label)}-${String(metric.value)}`}>\n <dt>{metric.label}</dt>\n <dd>{metric.value}</dd>\n </div>\n ))}\n </dl>\n )}\n\n {status === 'failed' && error && (\n <div role=\"alert\" className=\"dishui-ai-fine-tune-card__error\">{error}</div>\n )}\n\n <footer>\n {status === 'draft' && onStart && (\n <Button type=\"button\" variant=\"primary\" size=\"sm\" disabled={disabled} onClick={onStart}>\n {labels?.start ?? 'Start training'}\n </Button>\n )}\n {active && onCancel && (\n <Button type=\"button\" variant=\"secondary\" size=\"sm\" disabled={disabled} onClick={onCancel}>\n {labels?.cancel ?? 'Cancel'}\n </Button>\n )}\n {status === 'failed' && onRetry && (\n <Button type=\"button\" variant=\"primary\" size=\"sm\" disabled={disabled} onClick={onRetry}>\n {labels?.retry ?? 'Retry'}\n </Button>\n )}\n </footer>\n </article>\n );\n}\n"],"mappings":";;;;;;;AA0BA,IAAM,IAAS;CACb,OAAO;CACP,QAAQ;CACR,UAAU;CACV,OAAO;CACP,QAAQ;AACV,GACM,IAAkC,CAAC;AAEzC,SAAwB,EAAa,EACnC,UACA,UACA,gBACA,YAAS,SACT,cAAW,GACX,aAAU,GACV,UACA,YACA,aACA,YACA,cAAW,IACX,WACA,cACA,GAAG,KACiB;CACpB,IAAM,IAAM,KAAK,MAAM,EAAM,GAAU,GAAG,CAAC,IAAI,GAAG,GAC5C,IAAS,MAAW,YAAY,MAAW;CAEjD,OACE,kBAAC,WAAD;EAAS,GAAI;EAAM,WAAW,EAAG,4BAA4B,6BAA6B,KAAU,CAAS;EAA7G,UAAA;GACE,kBAAC,UAAD,EAAA,UAAA,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD,EAAA,UAAK,EAAU,CAAA,GACd,KAAS,kBAAC,QAAD,EAAA,UAAO,EAAY,CAAA,CAC1B,EAAA,CAAA,GACL,kBAAC,QAAD;IAAM,WAAU;IAAoC,UAAA,EAAO;GAAc,CAAA,CACnE,EAAA,CAAA;GAEP,KAAe,kBAAC,OAAD;IAAK,WAAU;IAAyC,UAAA;GAAiB,CAAA;GAExF,KACC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,OAAD,EAAA,UAAA,CAAK,kBAAC,QAAD,EAAA,UAAM,oBAAuB,CAAA,GAAC,kBAAC,UAAD,EAAA,UAAA,CAAS,GAAI,GAAS,EAAA,CAAA,CAAM,EAAA,CAAA,GAC/D,kBAAC,YAAD;KAAU,KAAK;KAAK,OAAO;KAA3B,UAAA,CAAiC,GAAI,GAAW;IAC7C,CAAA,CAAA;;GAGN,EAAQ,SAAS,KAChB,kBAAC,MAAD,EAAA,UACG,EAAQ,KAAI,MACX,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD,EAAA,UAAK,EAAO,MAAU,CAAA,GACtB,kBAAC,MAAD,EAAA,UAAK,EAAO,MAAU,CAAA,CACnB,EAAA,GAHK,GAAG,OAAO,EAAO,KAAK,EAAE,GAAG,OAAO,EAAO,KAAK,GAGnD,CACN,EACC,CAAA;GAGL,MAAW,YAAY,KACtB,kBAAC,OAAD;IAAK,MAAK;IAAQ,WAAU;IAAmC,UAAA;GAAW,CAAA;GAG5E,kBAAC,UAAD,EAAA,UAAA;IACG,MAAW,WAAW,KACrB,kBAAC,GAAD;KAAQ,MAAK;KAAS,SAAQ;KAAU,MAAK;KAAe;KAAU,SAAS;KAC5E,UAAA,GAAQ,SAAS;IACZ,CAAA;IAET,KAAU,KACT,kBAAC,GAAD;KAAQ,MAAK;KAAS,SAAQ;KAAY,MAAK;KAAe;KAAU,SAAS;KAC9E,UAAA,GAAQ,UAAU;IACb,CAAA;IAET,MAAW,YAAY,KACtB,kBAAC,GAAD;KAAQ,MAAK;KAAS,SAAQ;KAAU,MAAK;KAAe;KAAU,SAAS;KAC5E,UAAA,GAAQ,SAAS;IACZ,CAAA;GAEJ,EAAA,CAAA;EACD;;AAEb"}
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ export type InsightCardItem = {
3
+ id: string;
4
+ label: React.ReactNode;
5
+ value: React.ReactNode;
6
+ detail?: React.ReactNode;
7
+ trend?: {
8
+ value: string;
9
+ direction: 'up' | 'down' | 'flat';
10
+ label?: string;
11
+ };
12
+ status?: 'neutral' | 'success' | 'warning' | 'danger' | 'info';
13
+ };
14
+ export type InsightCardsProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'onSelect'> & {
15
+ items: InsightCardItem[];
16
+ columns?: 2 | 3 | 4;
17
+ selectedId?: string;
18
+ defaultSelectedId?: string;
19
+ onSelect?: (item: InsightCardItem) => void;
20
+ loading?: boolean;
21
+ emptyText?: React.ReactNode;
22
+ };
23
+ export default function InsightCards({ items, columns, selectedId, defaultSelectedId, onSelect, loading, emptyText, className, ...rest }: InsightCardsProps): React.JSX.Element;