@ai-matrx/content-ir-react 0.21.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/dist/db-component.cjs +39 -1
- package/dist/db-component.cjs.map +1 -1
- package/dist/db-component.d.cts +54 -9
- package/dist/db-component.d.ts +54 -9
- package/dist/db-component.js +39 -1
- package/dist/db-component.js.map +1 -1
- package/dist/{directive-host-CtFMuSZc.d.cts → directive-host-QjoZEeik.d.cts} +3 -3
- package/dist/{directive-host-CtFMuSZc.d.ts → directive-host-QjoZEeik.d.ts} +3 -3
- package/dist/directives.d.cts +9 -9
- package/dist/directives.d.ts +9 -9
- package/dist/{host-types-mMFt5-hQ.d.cts → host-types-B2Q8fiU8.d.cts} +1 -1
- package/dist/{host-types-CGcK8Nib.d.ts → host-types-DvZukz6J.d.ts} +1 -1
- package/dist/host.d.cts +5 -5
- package/dist/host.d.ts +5 -5
- package/dist/kind-kit.cjs +1035 -0
- package/dist/kind-kit.cjs.map +1 -0
- package/dist/kind-kit.d.cts +377 -0
- package/dist/kind-kit.d.ts +377 -0
- package/dist/kind-kit.js +1011 -0
- package/dist/kind-kit.js.map +1 -0
- package/dist/react.d.cts +11 -11
- package/dist/react.d.ts +11 -11
- package/package.json +15 -1
package/dist/kind-kit.js
ADDED
|
@@ -0,0 +1,1011 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// kind-kit/SortableList.tsx
|
|
4
|
+
import * as React3 from "react";
|
|
5
|
+
|
|
6
|
+
// kind-kit/icons.tsx
|
|
7
|
+
import "react";
|
|
8
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
function make(name, children) {
|
|
10
|
+
const Icon = ({ className }) => /* @__PURE__ */ jsx(
|
|
11
|
+
"svg",
|
|
12
|
+
{
|
|
13
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
14
|
+
width: "24",
|
|
15
|
+
height: "24",
|
|
16
|
+
viewBox: "0 0 24 24",
|
|
17
|
+
fill: "none",
|
|
18
|
+
stroke: "currentColor",
|
|
19
|
+
strokeWidth: "2",
|
|
20
|
+
strokeLinecap: "round",
|
|
21
|
+
strokeLinejoin: "round",
|
|
22
|
+
"aria-hidden": "true",
|
|
23
|
+
className,
|
|
24
|
+
children
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
Icon.displayName = name;
|
|
28
|
+
return Icon;
|
|
29
|
+
}
|
|
30
|
+
var Loader2 = make("Loader2", /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }));
|
|
31
|
+
var MoreHorizontal = make(
|
|
32
|
+
"MoreHorizontal",
|
|
33
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
34
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "1" }),
|
|
35
|
+
/* @__PURE__ */ jsx("circle", { cx: "19", cy: "12", r: "1" }),
|
|
36
|
+
/* @__PURE__ */ jsx("circle", { cx: "5", cy: "12", r: "1" })
|
|
37
|
+
] })
|
|
38
|
+
);
|
|
39
|
+
var ChevronDown = make("ChevronDown", /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" }));
|
|
40
|
+
var ChevronUp = make("ChevronUp", /* @__PURE__ */ jsx("path", { d: "m18 15-6-6-6 6" }));
|
|
41
|
+
var GripVertical = make(
|
|
42
|
+
"GripVertical",
|
|
43
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
44
|
+
/* @__PURE__ */ jsx("circle", { cx: "9", cy: "12", r: "1" }),
|
|
45
|
+
/* @__PURE__ */ jsx("circle", { cx: "9", cy: "5", r: "1" }),
|
|
46
|
+
/* @__PURE__ */ jsx("circle", { cx: "9", cy: "19", r: "1" }),
|
|
47
|
+
/* @__PURE__ */ jsx("circle", { cx: "15", cy: "12", r: "1" }),
|
|
48
|
+
/* @__PURE__ */ jsx("circle", { cx: "15", cy: "5", r: "1" }),
|
|
49
|
+
/* @__PURE__ */ jsx("circle", { cx: "15", cy: "19", r: "1" })
|
|
50
|
+
] })
|
|
51
|
+
);
|
|
52
|
+
var X = make(
|
|
53
|
+
"X",
|
|
54
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
55
|
+
/* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
|
|
56
|
+
/* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
|
|
57
|
+
] })
|
|
58
|
+
);
|
|
59
|
+
var Check = make("Check", /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }));
|
|
60
|
+
var Pencil = make(
|
|
61
|
+
"Pencil",
|
|
62
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
63
|
+
/* @__PURE__ */ jsx("path", { d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" }),
|
|
64
|
+
/* @__PURE__ */ jsx("path", { d: "m15 5 4 4" })
|
|
65
|
+
] })
|
|
66
|
+
);
|
|
67
|
+
var Plus = make(
|
|
68
|
+
"Plus",
|
|
69
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
70
|
+
/* @__PURE__ */ jsx("path", { d: "M5 12h14" }),
|
|
71
|
+
/* @__PURE__ */ jsx("path", { d: "M12 5v14" })
|
|
72
|
+
] })
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// kind-kit/SortableList.tsx
|
|
76
|
+
import { cn } from "@ai-matrx/design-system";
|
|
77
|
+
|
|
78
|
+
// kind-kit/kind-kit-host.tsx
|
|
79
|
+
import * as React2 from "react";
|
|
80
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
81
|
+
var KEY = /* @__PURE__ */ Symbol.for("ai-matrx.content-ir-react.kind-kit-host");
|
|
82
|
+
function resolveText(human, json) {
|
|
83
|
+
if (typeof human === "function") return human();
|
|
84
|
+
if (typeof human === "string") return human;
|
|
85
|
+
if (json !== void 0) return JSON.stringify(typeof json === "function" ? json() : json, null, 2);
|
|
86
|
+
return "";
|
|
87
|
+
}
|
|
88
|
+
function DefaultCopyButtons({ label, human, json, size, className }) {
|
|
89
|
+
const [state, setState] = React2.useState("idle");
|
|
90
|
+
const onClick = async () => {
|
|
91
|
+
try {
|
|
92
|
+
await navigator.clipboard.writeText(resolveText(human, json));
|
|
93
|
+
setState("copied");
|
|
94
|
+
} catch {
|
|
95
|
+
setState("failed");
|
|
96
|
+
}
|
|
97
|
+
setTimeout(() => setState("idle"), 1500);
|
|
98
|
+
};
|
|
99
|
+
return /* @__PURE__ */ jsx2(
|
|
100
|
+
"button",
|
|
101
|
+
{
|
|
102
|
+
type: "button",
|
|
103
|
+
onClick,
|
|
104
|
+
title: `Copy ${label}`,
|
|
105
|
+
"aria-label": `Copy ${label}`,
|
|
106
|
+
className: className ?? `inline-flex items-center rounded-md border border-border px-2 text-xs text-foreground hover:bg-muted ${size === "icon" ? "h-7" : "h-8"}`,
|
|
107
|
+
children: state === "copied" ? "Copied" : state === "failed" ? "Copy failed" : "Copy"
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
function RetryButton({ onRetry }) {
|
|
112
|
+
if (!onRetry) return null;
|
|
113
|
+
return /* @__PURE__ */ jsx2("button", { type: "button", onClick: onRetry, className: "ml-2 underline underline-offset-2", children: "Try again" });
|
|
114
|
+
}
|
|
115
|
+
function DefaultReadEmpty({ read, loading, children }) {
|
|
116
|
+
const status = read?.status ?? "ready";
|
|
117
|
+
const what = read?.what ?? "this list";
|
|
118
|
+
if (status === "loading") return /* @__PURE__ */ jsx2(Fragment2, { children: loading ?? /* @__PURE__ */ jsx2("div", { role: "status", className: "text-xs text-muted-foreground", children: `Loading ${what}\u2026` }) });
|
|
119
|
+
if (status === "error") {
|
|
120
|
+
return /* @__PURE__ */ jsxs2("div", { role: "alert", className: "text-xs text-destructive", children: [
|
|
121
|
+
`Could not load ${what}.`,
|
|
122
|
+
/* @__PURE__ */ jsx2(RetryButton, { onRetry: read?.onRetry })
|
|
123
|
+
] });
|
|
124
|
+
}
|
|
125
|
+
return /* @__PURE__ */ jsx2(Fragment2, { children: children ?? null });
|
|
126
|
+
}
|
|
127
|
+
function DefaultReadStaleNotice({ read, className }) {
|
|
128
|
+
if (read?.status !== "error") return null;
|
|
129
|
+
return /* @__PURE__ */ jsxs2("div", { role: "alert", className: `text-xs text-muted-foreground ${className ?? ""}`, children: [
|
|
130
|
+
`Showing earlier ${read.what ?? "results"}; the latest refresh failed.`,
|
|
131
|
+
/* @__PURE__ */ jsx2(RetryButton, { onRetry: read.onRetry })
|
|
132
|
+
] });
|
|
133
|
+
}
|
|
134
|
+
var DEFAULTS = {
|
|
135
|
+
CopyButtons: DefaultCopyButtons,
|
|
136
|
+
ReadEmpty: DefaultReadEmpty,
|
|
137
|
+
ReadStaleNotice: DefaultReadStaleNotice
|
|
138
|
+
};
|
|
139
|
+
function setKindKitHost(host) {
|
|
140
|
+
globalThis[KEY] = { ...globalThis[KEY], ...host };
|
|
141
|
+
}
|
|
142
|
+
function getKindKitHost() {
|
|
143
|
+
return { ...DEFAULTS, ...globalThis[KEY] };
|
|
144
|
+
}
|
|
145
|
+
function resetKindKitHost() {
|
|
146
|
+
delete globalThis[KEY];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// kind-kit/SortableList.tsx
|
|
150
|
+
import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
151
|
+
function defaultKey(item, index) {
|
|
152
|
+
if (typeof item === "string" || typeof item === "number") return String(item);
|
|
153
|
+
if (item && typeof item === "object") {
|
|
154
|
+
const rec = item;
|
|
155
|
+
if (typeof rec.id === "string" || typeof rec.id === "number")
|
|
156
|
+
return String(rec.id);
|
|
157
|
+
if (typeof rec.key === "string") return rec.key;
|
|
158
|
+
}
|
|
159
|
+
return String(index);
|
|
160
|
+
}
|
|
161
|
+
function defaultRender(item) {
|
|
162
|
+
if (typeof item === "string" || typeof item === "number") return String(item);
|
|
163
|
+
if (item && typeof item === "object") {
|
|
164
|
+
const rec = item;
|
|
165
|
+
for (const k of ["label", "title", "name", "text"]) {
|
|
166
|
+
if (typeof rec[k] === "string") return rec[k];
|
|
167
|
+
}
|
|
168
|
+
return JSON.stringify(item);
|
|
169
|
+
}
|
|
170
|
+
return String(item);
|
|
171
|
+
}
|
|
172
|
+
function moveItem(items, from, to) {
|
|
173
|
+
const next = items.slice();
|
|
174
|
+
const [moved] = next.splice(from, 1);
|
|
175
|
+
next.splice(to, 0, moved);
|
|
176
|
+
return next;
|
|
177
|
+
}
|
|
178
|
+
function SortableList({
|
|
179
|
+
items,
|
|
180
|
+
getKey = defaultKey,
|
|
181
|
+
onReorder,
|
|
182
|
+
renderItem,
|
|
183
|
+
onRemove,
|
|
184
|
+
disabled = false,
|
|
185
|
+
hideArrows = false,
|
|
186
|
+
emptyState,
|
|
187
|
+
read,
|
|
188
|
+
className,
|
|
189
|
+
itemClassName,
|
|
190
|
+
ariaLabel
|
|
191
|
+
}) {
|
|
192
|
+
const { ReadEmpty, ReadStaleNotice } = getKindKitHost();
|
|
193
|
+
const [drag, setDrag] = React3.useState(null);
|
|
194
|
+
const [armed, setArmed] = React3.useState(null);
|
|
195
|
+
const listRef = React3.useRef(null);
|
|
196
|
+
const rowRefs = React3.useRef([]);
|
|
197
|
+
const canInteract = !disabled;
|
|
198
|
+
const handleDragStart = (index) => (e) => {
|
|
199
|
+
if (!canInteract || armed !== index) {
|
|
200
|
+
e.preventDefault();
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
e.dataTransfer.effectAllowed = "move";
|
|
204
|
+
e.dataTransfer.setData("text/plain", String(index));
|
|
205
|
+
const listTop = listRef.current?.getBoundingClientRect().top ?? 0;
|
|
206
|
+
const rects = rowRefs.current.slice(0, items.length).map((el) => {
|
|
207
|
+
const r = el ? el.getBoundingClientRect() : new DOMRect();
|
|
208
|
+
return { top: r.top - listTop, bottom: r.bottom - listTop, height: r.height };
|
|
209
|
+
});
|
|
210
|
+
setDrag({ from: index, over: index, rects });
|
|
211
|
+
};
|
|
212
|
+
const handleDragOver = (e) => {
|
|
213
|
+
if (!drag) return;
|
|
214
|
+
e.preventDefault();
|
|
215
|
+
e.dataTransfer.dropEffect = "move";
|
|
216
|
+
const listTop = listRef.current?.getBoundingClientRect().top ?? 0;
|
|
217
|
+
const y = e.clientY - listTop;
|
|
218
|
+
let over = drag.rects.length - 1;
|
|
219
|
+
for (let i = 0; i < drag.rects.length; i++) {
|
|
220
|
+
const r = drag.rects[i];
|
|
221
|
+
if (r && y < r.bottom) {
|
|
222
|
+
over = i;
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (over !== drag.over) setDrag({ ...drag, over });
|
|
227
|
+
};
|
|
228
|
+
const finish = () => {
|
|
229
|
+
setDrag(null);
|
|
230
|
+
setArmed(null);
|
|
231
|
+
};
|
|
232
|
+
const handleDrop = (e) => {
|
|
233
|
+
e.preventDefault();
|
|
234
|
+
if (drag && drag.from !== drag.over) {
|
|
235
|
+
onReorder(moveItem(items, drag.from, drag.over));
|
|
236
|
+
}
|
|
237
|
+
finish();
|
|
238
|
+
};
|
|
239
|
+
const move = (from, to) => {
|
|
240
|
+
if (to < 0 || to >= items.length || from === to) return;
|
|
241
|
+
onReorder(moveItem(items, from, to));
|
|
242
|
+
};
|
|
243
|
+
const translateFor = (index) => {
|
|
244
|
+
if (!drag) return 0;
|
|
245
|
+
const { from, over, rects } = drag;
|
|
246
|
+
if (from === over) return 0;
|
|
247
|
+
const dragged = rects[from];
|
|
248
|
+
if (!dragged) return 0;
|
|
249
|
+
const neighbour = rects[from + 1] ?? rects[from - 1];
|
|
250
|
+
const gap = neighbour ? Math.max(
|
|
251
|
+
0,
|
|
252
|
+
from + 1 < rects.length ? neighbour.top - dragged.bottom : dragged.top - neighbour.bottom
|
|
253
|
+
) : 0;
|
|
254
|
+
const slot = dragged.height + gap;
|
|
255
|
+
if (index === from) {
|
|
256
|
+
const target = rects[over];
|
|
257
|
+
if (!target) return 0;
|
|
258
|
+
return over > from ? target.bottom - dragged.bottom : target.top - dragged.top;
|
|
259
|
+
}
|
|
260
|
+
if (from < over && index > from && index <= over) return -slot;
|
|
261
|
+
if (over < from && index >= over && index < from) return slot;
|
|
262
|
+
return 0;
|
|
263
|
+
};
|
|
264
|
+
if (items.length === 0) {
|
|
265
|
+
if (read && read.status !== "ready") return /* @__PURE__ */ jsx3(ReadEmpty, { read });
|
|
266
|
+
return emptyState !== void 0 ? /* @__PURE__ */ jsx3("div", { className: cn("text-xs text-muted-foreground", className), children: emptyState }) : null;
|
|
267
|
+
}
|
|
268
|
+
return /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
269
|
+
/* @__PURE__ */ jsx3(ReadStaleNotice, { read, className: "mb-1.5" }),
|
|
270
|
+
/* @__PURE__ */ jsx3(
|
|
271
|
+
"ul",
|
|
272
|
+
{
|
|
273
|
+
role: "list",
|
|
274
|
+
"aria-label": ariaLabel,
|
|
275
|
+
ref: listRef,
|
|
276
|
+
className: cn("flex flex-col gap-1.5", className),
|
|
277
|
+
onDragOver: handleDragOver,
|
|
278
|
+
onDrop: handleDrop,
|
|
279
|
+
children: items.map((item, index) => {
|
|
280
|
+
const key = getKey(item, index);
|
|
281
|
+
const isDragging = drag?.from === index;
|
|
282
|
+
const translate = translateFor(index);
|
|
283
|
+
return /* @__PURE__ */ jsxs3(
|
|
284
|
+
"li",
|
|
285
|
+
{
|
|
286
|
+
ref: (el) => {
|
|
287
|
+
rowRefs.current[index] = el;
|
|
288
|
+
},
|
|
289
|
+
draggable: canInteract && armed === index,
|
|
290
|
+
onDragStart: handleDragStart(index),
|
|
291
|
+
onDragEnd: finish,
|
|
292
|
+
style: {
|
|
293
|
+
transform: translate ? `translate3d(0, ${translate}px, 0)` : void 0
|
|
294
|
+
},
|
|
295
|
+
className: cn(
|
|
296
|
+
"flex items-center gap-1.5 rounded-md border px-2 py-1.5 text-sm text-foreground",
|
|
297
|
+
"transition-transform duration-150 ease-out will-change-transform",
|
|
298
|
+
isDragging ? "border-dashed border-primary/60 bg-primary/5 shadow-inner" : "border-border bg-card",
|
|
299
|
+
itemClassName
|
|
300
|
+
),
|
|
301
|
+
children: [
|
|
302
|
+
/* @__PURE__ */ jsx3(
|
|
303
|
+
"button",
|
|
304
|
+
{
|
|
305
|
+
type: "button",
|
|
306
|
+
"aria-label": "Drag to reorder",
|
|
307
|
+
disabled: !canInteract,
|
|
308
|
+
onPointerDown: () => canInteract && setArmed(index),
|
|
309
|
+
onPointerUp: () => !drag && setArmed(null),
|
|
310
|
+
className: cn(
|
|
311
|
+
"flex h-7 w-6 shrink-0 touch-none items-center justify-center rounded text-muted-foreground",
|
|
312
|
+
canInteract ? "cursor-grab hover:bg-muted hover:text-foreground active:cursor-grabbing" : "opacity-40"
|
|
313
|
+
),
|
|
314
|
+
children: /* @__PURE__ */ jsx3(GripVertical, { className: "h-4 w-4" })
|
|
315
|
+
}
|
|
316
|
+
),
|
|
317
|
+
/* @__PURE__ */ jsx3(
|
|
318
|
+
"div",
|
|
319
|
+
{
|
|
320
|
+
className: cn(
|
|
321
|
+
"min-w-0 flex-1 break-words",
|
|
322
|
+
isDragging && "opacity-40"
|
|
323
|
+
),
|
|
324
|
+
children: renderItem ? renderItem(item, { index, isDragging }) : defaultRender(item)
|
|
325
|
+
}
|
|
326
|
+
),
|
|
327
|
+
(!hideArrows || onRemove) && /*
|
|
328
|
+
* Controls sit IN FLOW at the row's end — never floating.
|
|
329
|
+
*
|
|
330
|
+
* A cluster that costs no layout width must, by construction,
|
|
331
|
+
* land on top of something when it appears, and it wins every
|
|
332
|
+
* click there because it is the layer above. Rows here carry the
|
|
333
|
+
* host component's own trailing controls (copy, edit, menus), so
|
|
334
|
+
* a floating cluster covered live buttons on every consumer:
|
|
335
|
+
* measured on `artisan_demo_reading_list`, it sat on "Copy for
|
|
336
|
+
* AI" and "Edit book". The kit cannot know what a row draws in
|
|
337
|
+
* its corner, so it takes its own width instead of borrowing the
|
|
338
|
+
* row's. Ruled 2026-08-30: overlap is never worth the density.
|
|
339
|
+
*/
|
|
340
|
+
/* @__PURE__ */ jsxs3(
|
|
341
|
+
"div",
|
|
342
|
+
{
|
|
343
|
+
className: cn(
|
|
344
|
+
"flex shrink-0 items-center gap-px self-start",
|
|
345
|
+
isDragging && "opacity-40"
|
|
346
|
+
),
|
|
347
|
+
children: [
|
|
348
|
+
!hideArrows && /* Chevrons stack so the pair costs one 20px column, not two. */
|
|
349
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex flex-col items-center pointer-coarse:flex-row", children: [
|
|
350
|
+
/* @__PURE__ */ jsx3(
|
|
351
|
+
"button",
|
|
352
|
+
{
|
|
353
|
+
type: "button",
|
|
354
|
+
"aria-label": "Move up",
|
|
355
|
+
disabled: !canInteract || index === 0,
|
|
356
|
+
onClick: () => move(index, index - 1),
|
|
357
|
+
className: "flex h-3.5 w-5 items-center justify-center rounded-sm text-muted-foreground/70 hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-30 pointer-coarse:h-7 pointer-coarse:w-7",
|
|
358
|
+
children: /* @__PURE__ */ jsx3(ChevronUp, { className: "h-3 w-3" })
|
|
359
|
+
}
|
|
360
|
+
),
|
|
361
|
+
/* @__PURE__ */ jsx3(
|
|
362
|
+
"button",
|
|
363
|
+
{
|
|
364
|
+
type: "button",
|
|
365
|
+
"aria-label": "Move down",
|
|
366
|
+
disabled: !canInteract || index === items.length - 1,
|
|
367
|
+
onClick: () => move(index, index + 1),
|
|
368
|
+
className: "flex h-3.5 w-5 items-center justify-center rounded-sm text-muted-foreground/70 hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-30 pointer-coarse:h-7 pointer-coarse:w-7",
|
|
369
|
+
children: /* @__PURE__ */ jsx3(ChevronDown, { className: "h-3 w-3" })
|
|
370
|
+
}
|
|
371
|
+
)
|
|
372
|
+
] }),
|
|
373
|
+
onRemove && /* @__PURE__ */ jsx3(
|
|
374
|
+
"button",
|
|
375
|
+
{
|
|
376
|
+
type: "button",
|
|
377
|
+
"aria-label": "Remove",
|
|
378
|
+
disabled: !canInteract,
|
|
379
|
+
onClick: () => onRemove(item, index),
|
|
380
|
+
className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground/70 hover:bg-muted hover:text-destructive disabled:pointer-events-none disabled:opacity-30 pointer-coarse:h-7 pointer-coarse:w-7",
|
|
381
|
+
children: /* @__PURE__ */ jsx3(X, { className: "h-3.5 w-3.5" })
|
|
382
|
+
}
|
|
383
|
+
)
|
|
384
|
+
]
|
|
385
|
+
}
|
|
386
|
+
)
|
|
387
|
+
]
|
|
388
|
+
},
|
|
389
|
+
key
|
|
390
|
+
);
|
|
391
|
+
})
|
|
392
|
+
}
|
|
393
|
+
)
|
|
394
|
+
] });
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// kind-kit/KindPanelGrid.tsx
|
|
398
|
+
import "react";
|
|
399
|
+
import { cn as cn2 } from "@ai-matrx/design-system";
|
|
400
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
401
|
+
var GAP_PX = { sm: 8, md: 12, lg: 16 };
|
|
402
|
+
var GAP_CLASS = { sm: "gap-2", md: "gap-3", lg: "gap-4" };
|
|
403
|
+
function KindPanelGrid({
|
|
404
|
+
children,
|
|
405
|
+
minColumnWidth = 280,
|
|
406
|
+
maxColumns,
|
|
407
|
+
gap = "md",
|
|
408
|
+
fill = "auto-fit",
|
|
409
|
+
className
|
|
410
|
+
}) {
|
|
411
|
+
const min = `min(100%, ${minColumnWidth}px)`;
|
|
412
|
+
const track = maxColumns && maxColumns > 0 ? `max(${min}, calc((100% - ${GAP_PX[gap] * (maxColumns - 1)}px) / ${maxColumns}))` : min;
|
|
413
|
+
return /* @__PURE__ */ jsx4(
|
|
414
|
+
"div",
|
|
415
|
+
{
|
|
416
|
+
className: cn2("grid items-stretch", GAP_CLASS[gap], className),
|
|
417
|
+
style: { gridTemplateColumns: `repeat(${fill}, minmax(${track}, 1fr))` },
|
|
418
|
+
children
|
|
419
|
+
}
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// kind-kit/KindPanel.tsx
|
|
424
|
+
import * as React6 from "react";
|
|
425
|
+
import {
|
|
426
|
+
Button,
|
|
427
|
+
cn as cn4,
|
|
428
|
+
DropdownMenu,
|
|
429
|
+
DropdownMenuContent,
|
|
430
|
+
DropdownMenuItem,
|
|
431
|
+
DropdownMenuSeparator,
|
|
432
|
+
DropdownMenuTrigger
|
|
433
|
+
} from "@ai-matrx/design-system";
|
|
434
|
+
|
|
435
|
+
// kind-kit/icon-slot.tsx
|
|
436
|
+
import * as React5 from "react";
|
|
437
|
+
import { cn as cn3 } from "@ai-matrx/design-system";
|
|
438
|
+
function resolveIconType(icon) {
|
|
439
|
+
if (typeof icon === "function") return icon;
|
|
440
|
+
if (typeof icon !== "object" || icon === null) return null;
|
|
441
|
+
const candidate = icon;
|
|
442
|
+
if (typeof candidate.$$typeof === "symbol") {
|
|
443
|
+
return icon;
|
|
444
|
+
}
|
|
445
|
+
if ("default" in candidate && candidate.default !== icon) {
|
|
446
|
+
return resolveIconType(candidate.default);
|
|
447
|
+
}
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
function renderKindKitIcon(icon, className) {
|
|
451
|
+
if (!icon) return null;
|
|
452
|
+
if (React5.isValidElement(icon)) {
|
|
453
|
+
return React5.cloneElement(icon, {
|
|
454
|
+
className: cn3(className, icon.props.className)
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
const Icon = resolveIconType(icon);
|
|
458
|
+
return Icon ? React5.createElement(Icon, { className }) : null;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// kind-kit/KindPanel.tsx
|
|
462
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
463
|
+
function KindPanel({
|
|
464
|
+
title,
|
|
465
|
+
icon,
|
|
466
|
+
count,
|
|
467
|
+
badge,
|
|
468
|
+
streaming = false,
|
|
469
|
+
actions,
|
|
470
|
+
menuItems,
|
|
471
|
+
subline,
|
|
472
|
+
children,
|
|
473
|
+
footer,
|
|
474
|
+
variant = "card",
|
|
475
|
+
dense = false,
|
|
476
|
+
className,
|
|
477
|
+
bodyClassName
|
|
478
|
+
}) {
|
|
479
|
+
const px = dense ? "px-2.5" : "px-3";
|
|
480
|
+
const menu = menuItems && menuItems.length > 0 ? menuItems : null;
|
|
481
|
+
return /* @__PURE__ */ jsxs4(
|
|
482
|
+
"section",
|
|
483
|
+
{
|
|
484
|
+
className: cn4(
|
|
485
|
+
"flex h-full min-h-0 min-w-0 flex-col",
|
|
486
|
+
variant === "card" && "rounded-lg border border-border bg-card",
|
|
487
|
+
className
|
|
488
|
+
),
|
|
489
|
+
children: [
|
|
490
|
+
/* @__PURE__ */ jsxs4(
|
|
491
|
+
"header",
|
|
492
|
+
{
|
|
493
|
+
className: cn4(
|
|
494
|
+
"flex items-start gap-2",
|
|
495
|
+
px,
|
|
496
|
+
dense ? "pt-2" : "pt-3",
|
|
497
|
+
variant === "bare" && "px-0"
|
|
498
|
+
),
|
|
499
|
+
children: [
|
|
500
|
+
renderKindKitIcon(icon, "mt-0.5 h-3.5 w-3.5 shrink-0 text-primary"),
|
|
501
|
+
/* @__PURE__ */ jsx5("h3", { className: "min-w-0 flex-1 text-xs font-semibold uppercase leading-5 tracking-wide text-foreground break-words", children: title }),
|
|
502
|
+
count !== void 0 && /* @__PURE__ */ jsx5("span", { className: "mt-0.5 shrink-0 rounded-full bg-muted px-1.5 py-0.5 text-[10px] tabular-nums text-muted-foreground", children: count }),
|
|
503
|
+
badge !== void 0 && /* @__PURE__ */ jsx5("span", { className: "mt-0.5 shrink-0", children: badge }),
|
|
504
|
+
streaming && /* @__PURE__ */ jsx5(
|
|
505
|
+
Loader2,
|
|
506
|
+
{
|
|
507
|
+
"aria-label": "Still arriving",
|
|
508
|
+
className: "mt-1 h-3 w-3 shrink-0 animate-spin text-muted-foreground"
|
|
509
|
+
}
|
|
510
|
+
),
|
|
511
|
+
actions && /* @__PURE__ */ jsx5("div", { className: "flex shrink-0 items-center gap-1", children: actions }),
|
|
512
|
+
menu && /* @__PURE__ */ jsxs4(DropdownMenu, { children: [
|
|
513
|
+
/* @__PURE__ */ jsx5(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx5(
|
|
514
|
+
Button,
|
|
515
|
+
{
|
|
516
|
+
type: "button",
|
|
517
|
+
variant: "ghost",
|
|
518
|
+
size: "icon",
|
|
519
|
+
"aria-label": "More actions",
|
|
520
|
+
className: "-mr-1 -mt-1 h-7 w-7 shrink-0 text-muted-foreground",
|
|
521
|
+
children: /* @__PURE__ */ jsx5(MoreHorizontal, { className: "h-4 w-4" })
|
|
522
|
+
}
|
|
523
|
+
) }),
|
|
524
|
+
/* @__PURE__ */ jsx5(DropdownMenuContent, { align: "end", className: "min-w-44", children: menu.map((item, i) => /* @__PURE__ */ jsxs4(React6.Fragment, { children: [
|
|
525
|
+
item.separatorBefore && i > 0 && /* @__PURE__ */ jsx5(DropdownMenuSeparator, {}),
|
|
526
|
+
/* @__PURE__ */ jsxs4(
|
|
527
|
+
DropdownMenuItem,
|
|
528
|
+
{
|
|
529
|
+
disabled: item.disabled ?? false,
|
|
530
|
+
onSelect: () => item.onSelect(),
|
|
531
|
+
className: cn4(
|
|
532
|
+
"text-xs",
|
|
533
|
+
item.destructive && "text-destructive focus:text-destructive"
|
|
534
|
+
),
|
|
535
|
+
children: [
|
|
536
|
+
item.icon && /* @__PURE__ */ jsx5(item.icon, { className: "mr-2 h-3.5 w-3.5" }),
|
|
537
|
+
item.label
|
|
538
|
+
]
|
|
539
|
+
}
|
|
540
|
+
)
|
|
541
|
+
] }, `${i}-${item.label}`)) })
|
|
542
|
+
] })
|
|
543
|
+
]
|
|
544
|
+
}
|
|
545
|
+
),
|
|
546
|
+
subline !== void 0 && subline !== null && subline !== "" && /* @__PURE__ */ jsx5(
|
|
547
|
+
"div",
|
|
548
|
+
{
|
|
549
|
+
className: cn4(
|
|
550
|
+
"pt-1 text-xs leading-snug text-muted-foreground break-words",
|
|
551
|
+
px,
|
|
552
|
+
variant === "bare" && "px-0"
|
|
553
|
+
),
|
|
554
|
+
children: subline
|
|
555
|
+
}
|
|
556
|
+
),
|
|
557
|
+
/* @__PURE__ */ jsx5(
|
|
558
|
+
"div",
|
|
559
|
+
{
|
|
560
|
+
className: cn4(
|
|
561
|
+
"min-w-0 flex-1",
|
|
562
|
+
px,
|
|
563
|
+
dense ? "py-1.5" : "py-2",
|
|
564
|
+
variant === "bare" && "px-0",
|
|
565
|
+
bodyClassName
|
|
566
|
+
),
|
|
567
|
+
children
|
|
568
|
+
}
|
|
569
|
+
),
|
|
570
|
+
footer !== void 0 && footer !== null && /* @__PURE__ */ jsx5(
|
|
571
|
+
"div",
|
|
572
|
+
{
|
|
573
|
+
className: cn4(
|
|
574
|
+
"mt-auto border-t border-border",
|
|
575
|
+
px,
|
|
576
|
+
dense ? "py-1.5" : "py-2",
|
|
577
|
+
variant === "bare" && "px-0"
|
|
578
|
+
),
|
|
579
|
+
children: footer
|
|
580
|
+
}
|
|
581
|
+
)
|
|
582
|
+
]
|
|
583
|
+
}
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// kind-kit/KindHeaderBar.tsx
|
|
588
|
+
import "react";
|
|
589
|
+
import { cn as cn5 } from "@ai-matrx/design-system";
|
|
590
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
591
|
+
function KindHeaderBar({
|
|
592
|
+
title,
|
|
593
|
+
icon,
|
|
594
|
+
subtitle,
|
|
595
|
+
stats,
|
|
596
|
+
streaming = false,
|
|
597
|
+
streamingLabel = "Streaming",
|
|
598
|
+
copy,
|
|
599
|
+
actions,
|
|
600
|
+
size = "sm",
|
|
601
|
+
className
|
|
602
|
+
}) {
|
|
603
|
+
const { CopyButtons } = getKindKitHost();
|
|
604
|
+
const titleCls = size === "md" ? "text-base" : "text-sm";
|
|
605
|
+
const iconCls = size === "md" ? "h-5 w-5" : "h-4 w-4";
|
|
606
|
+
const iconNode = renderKindKitIcon(
|
|
607
|
+
icon,
|
|
608
|
+
cn5("mt-0.5 shrink-0 text-primary", iconCls)
|
|
609
|
+
);
|
|
610
|
+
return /* @__PURE__ */ jsxs5(
|
|
611
|
+
"div",
|
|
612
|
+
{
|
|
613
|
+
className: cn5("flex flex-wrap items-center gap-x-3 gap-y-1.5", className),
|
|
614
|
+
children: [
|
|
615
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 flex-1 basis-48 items-start gap-2", children: [
|
|
616
|
+
iconNode,
|
|
617
|
+
/* @__PURE__ */ jsxs5("div", { className: "min-w-0 flex-1", children: [
|
|
618
|
+
/* @__PURE__ */ jsx6(
|
|
619
|
+
"div",
|
|
620
|
+
{
|
|
621
|
+
className: cn5(
|
|
622
|
+
"font-semibold leading-tight text-foreground break-words",
|
|
623
|
+
titleCls
|
|
624
|
+
),
|
|
625
|
+
children: title
|
|
626
|
+
}
|
|
627
|
+
),
|
|
628
|
+
subtitle !== void 0 && subtitle !== null && subtitle !== "" && /* @__PURE__ */ jsx6("div", { className: "mt-0.5 text-xs leading-snug text-muted-foreground break-words", children: subtitle })
|
|
629
|
+
] })
|
|
630
|
+
] }),
|
|
631
|
+
stats && stats.length > 0 && /* @__PURE__ */ jsx6("dl", { className: "flex flex-wrap items-center gap-x-3 gap-y-1", children: stats.map((s, i) => /* @__PURE__ */ jsxs5(
|
|
632
|
+
"div",
|
|
633
|
+
{
|
|
634
|
+
title: s.title,
|
|
635
|
+
className: "flex items-baseline gap-1 text-xs",
|
|
636
|
+
children: [
|
|
637
|
+
renderKindKitIcon(
|
|
638
|
+
s.icon,
|
|
639
|
+
"h-3 w-3 self-center text-muted-foreground"
|
|
640
|
+
),
|
|
641
|
+
/* @__PURE__ */ jsx6("dd", { className: "font-semibold tabular-nums text-foreground", children: s.value }),
|
|
642
|
+
/* @__PURE__ */ jsx6("dt", { className: "text-muted-foreground", children: s.label })
|
|
643
|
+
]
|
|
644
|
+
},
|
|
645
|
+
`${i}-${s.label}`
|
|
646
|
+
)) }),
|
|
647
|
+
streaming && /* @__PURE__ */ jsxs5("span", { className: "inline-flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
648
|
+
/* @__PURE__ */ jsx6(Loader2, { className: "h-3 w-3 animate-spin" }),
|
|
649
|
+
streamingLabel
|
|
650
|
+
] }),
|
|
651
|
+
(actions || copy) && /* @__PURE__ */ jsxs5("div", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: [
|
|
652
|
+
actions,
|
|
653
|
+
copy && /* @__PURE__ */ jsx6(CopyButtons, { ...copy, size: size === "md" ? "sm" : "icon" })
|
|
654
|
+
] })
|
|
655
|
+
]
|
|
656
|
+
}
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// kind-kit/StreamingSkeleton.tsx
|
|
661
|
+
import * as React8 from "react";
|
|
662
|
+
import { cn as cn6, Skeleton } from "@ai-matrx/design-system";
|
|
663
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
664
|
+
function StreamingSkeleton({
|
|
665
|
+
layout = "list",
|
|
666
|
+
rows = 3,
|
|
667
|
+
columns,
|
|
668
|
+
header = true,
|
|
669
|
+
label = "Loading",
|
|
670
|
+
className
|
|
671
|
+
}) {
|
|
672
|
+
const n = Math.max(1, rows);
|
|
673
|
+
const cols = Math.max(1, columns ?? (layout === "cards" ? 2 : 3));
|
|
674
|
+
return /* @__PURE__ */ jsxs6(
|
|
675
|
+
"div",
|
|
676
|
+
{
|
|
677
|
+
role: "status",
|
|
678
|
+
"aria-busy": "true",
|
|
679
|
+
"aria-label": label,
|
|
680
|
+
className: cn6("space-y-2", className),
|
|
681
|
+
children: [
|
|
682
|
+
header && /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
|
|
683
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-4 w-4 rounded" }),
|
|
684
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-4 w-40" }),
|
|
685
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "ml-auto h-6 w-16" })
|
|
686
|
+
] }),
|
|
687
|
+
layout === "list" && Array.from({ length: n }).map((_, i) => /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 rounded-md border border-border px-2 py-2", children: [
|
|
688
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-4 w-4 rounded" }),
|
|
689
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: cn6("h-3.5", i % 3 === 0 ? "w-2/3" : i % 3 === 1 ? "w-1/2" : "w-3/4") })
|
|
690
|
+
] }, i)),
|
|
691
|
+
layout === "cards" && /* @__PURE__ */ jsx7(
|
|
692
|
+
"div",
|
|
693
|
+
{
|
|
694
|
+
className: "grid gap-3",
|
|
695
|
+
style: { gridTemplateColumns: `repeat(auto-fit, minmax(min(100%, 240px), 1fr))` },
|
|
696
|
+
children: Array.from({ length: Math.max(n, cols) }).map((_, i) => /* @__PURE__ */ jsxs6("div", { className: "space-y-2 rounded-lg border border-border p-3", children: [
|
|
697
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-3.5 w-1/2" }),
|
|
698
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-3 w-full" }),
|
|
699
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex flex-wrap gap-1.5 pt-1", children: [
|
|
700
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-5 w-16 rounded-full" }),
|
|
701
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-5 w-24 rounded-full" }),
|
|
702
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-5 w-12 rounded-full" })
|
|
703
|
+
] })
|
|
704
|
+
] }, i))
|
|
705
|
+
}
|
|
706
|
+
),
|
|
707
|
+
layout === "table" && /* @__PURE__ */ jsxs6("div", { className: "overflow-hidden rounded-md border border-border", children: [
|
|
708
|
+
/* @__PURE__ */ jsx7(
|
|
709
|
+
"div",
|
|
710
|
+
{
|
|
711
|
+
className: "grid gap-2 border-b border-border bg-muted/40 px-2 py-1.5",
|
|
712
|
+
style: { gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))` },
|
|
713
|
+
children: Array.from({ length: cols }).map((_, c) => /* @__PURE__ */ jsx7(Skeleton, { className: "h-3 w-2/3" }, c))
|
|
714
|
+
}
|
|
715
|
+
),
|
|
716
|
+
Array.from({ length: n }).map((_, r) => /* @__PURE__ */ jsx7(
|
|
717
|
+
"div",
|
|
718
|
+
{
|
|
719
|
+
className: "grid gap-2 px-2 py-2",
|
|
720
|
+
style: { gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))` },
|
|
721
|
+
children: Array.from({ length: cols }).map((_2, c) => /* @__PURE__ */ jsx7(Skeleton, { className: cn6("h-3", c === 0 ? "w-3/4" : "w-1/2") }, c))
|
|
722
|
+
},
|
|
723
|
+
r
|
|
724
|
+
))
|
|
725
|
+
] }),
|
|
726
|
+
layout === "text" && Array.from({ length: n }).map((_, i) => /* @__PURE__ */ jsx7(
|
|
727
|
+
Skeleton,
|
|
728
|
+
{
|
|
729
|
+
className: cn6("h-3", i === n - 1 ? "w-2/5" : i % 2 === 0 ? "w-full" : "w-11/12")
|
|
730
|
+
},
|
|
731
|
+
i
|
|
732
|
+
)),
|
|
733
|
+
/* @__PURE__ */ jsx7("span", { className: "sr-only", children: label })
|
|
734
|
+
]
|
|
735
|
+
}
|
|
736
|
+
);
|
|
737
|
+
}
|
|
738
|
+
function useStreamingValue(value, fallback) {
|
|
739
|
+
const [last, setLast] = React8.useState({
|
|
740
|
+
value: fallback,
|
|
741
|
+
arrived: false
|
|
742
|
+
});
|
|
743
|
+
const defined = value !== null && value !== void 0;
|
|
744
|
+
if (defined && (!last.arrived || !Object.is(value, last.value))) {
|
|
745
|
+
const next = { value, arrived: true };
|
|
746
|
+
setLast(next);
|
|
747
|
+
return next;
|
|
748
|
+
}
|
|
749
|
+
return last;
|
|
750
|
+
}
|
|
751
|
+
function streamList(value) {
|
|
752
|
+
return Array.isArray(value) ? value : [];
|
|
753
|
+
}
|
|
754
|
+
function streamText(value, fallback = "") {
|
|
755
|
+
return typeof value === "string" && value.length > 0 ? value : fallback;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
// kind-kit/TagList.tsx
|
|
759
|
+
import * as React9 from "react";
|
|
760
|
+
import { cn as cn7 } from "@ai-matrx/design-system";
|
|
761
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
762
|
+
var TONE = {
|
|
763
|
+
default: "border-border bg-background text-foreground",
|
|
764
|
+
primary: "border-primary/40 bg-primary/5 text-foreground",
|
|
765
|
+
muted: "border-border bg-muted text-muted-foreground"
|
|
766
|
+
};
|
|
767
|
+
function KeywordChip({
|
|
768
|
+
label,
|
|
769
|
+
meta,
|
|
770
|
+
icon,
|
|
771
|
+
selected = false,
|
|
772
|
+
onSelect,
|
|
773
|
+
onRemove,
|
|
774
|
+
onEdit,
|
|
775
|
+
disabled = false,
|
|
776
|
+
tone = "default",
|
|
777
|
+
size = "sm",
|
|
778
|
+
className
|
|
779
|
+
}) {
|
|
780
|
+
const [editing, setEditing] = React9.useState(false);
|
|
781
|
+
const [draft, setDraft] = React9.useState(label);
|
|
782
|
+
const inputRef = React9.useRef(null);
|
|
783
|
+
const selectable = !!onSelect && !disabled;
|
|
784
|
+
const editable = !!onEdit && !disabled;
|
|
785
|
+
const startEdit = () => {
|
|
786
|
+
if (!editable) return;
|
|
787
|
+
setDraft(label);
|
|
788
|
+
setEditing(true);
|
|
789
|
+
requestAnimationFrame(() => inputRef.current?.select());
|
|
790
|
+
};
|
|
791
|
+
const commit = () => {
|
|
792
|
+
setEditing(false);
|
|
793
|
+
const next = draft.trim();
|
|
794
|
+
if (next && next !== label) onEdit?.(next);
|
|
795
|
+
};
|
|
796
|
+
const cancel = () => {
|
|
797
|
+
setEditing(false);
|
|
798
|
+
setDraft(label);
|
|
799
|
+
};
|
|
800
|
+
const pad = size === "md" ? "px-2.5 py-1 text-sm" : "px-2 py-0.5 text-xs";
|
|
801
|
+
const inputText = size === "md" ? "text-[16px] sm:text-sm" : "text-[16px] sm:text-xs";
|
|
802
|
+
const ctl = size === "md" ? "h-4 w-4" : "h-3.5 w-3.5";
|
|
803
|
+
return /* @__PURE__ */ jsxs7(
|
|
804
|
+
"span",
|
|
805
|
+
{
|
|
806
|
+
className: cn7(
|
|
807
|
+
// max-w-full + min-w-0 + break-words: the text wraps INSIDE the chip.
|
|
808
|
+
"inline-flex max-w-full min-w-0 items-center gap-1 rounded-full border leading-snug",
|
|
809
|
+
pad,
|
|
810
|
+
selected ? "border-primary bg-primary/10 text-foreground" : TONE[tone],
|
|
811
|
+
disabled && "opacity-60",
|
|
812
|
+
className
|
|
813
|
+
),
|
|
814
|
+
children: [
|
|
815
|
+
selectable && /* @__PURE__ */ jsx8(
|
|
816
|
+
"button",
|
|
817
|
+
{
|
|
818
|
+
type: "button",
|
|
819
|
+
role: "checkbox",
|
|
820
|
+
"aria-checked": selected,
|
|
821
|
+
"aria-label": `${selected ? "Deselect" : "Select"} ${label}`,
|
|
822
|
+
onClick: () => onSelect?.(!selected),
|
|
823
|
+
className: cn7(
|
|
824
|
+
"flex shrink-0 items-center justify-center rounded-sm border",
|
|
825
|
+
size === "md" ? "h-4 w-4" : "h-3.5 w-3.5",
|
|
826
|
+
selected ? "border-primary bg-primary text-primary-foreground" : "border-muted-foreground/50 bg-background"
|
|
827
|
+
),
|
|
828
|
+
children: selected && /* @__PURE__ */ jsx8(Check, { className: "h-2.5 w-2.5" })
|
|
829
|
+
}
|
|
830
|
+
),
|
|
831
|
+
renderKindKitIcon(
|
|
832
|
+
icon,
|
|
833
|
+
cn7("shrink-0 text-muted-foreground", ctl)
|
|
834
|
+
),
|
|
835
|
+
editing ? /* @__PURE__ */ jsx8(
|
|
836
|
+
"input",
|
|
837
|
+
{
|
|
838
|
+
ref: inputRef,
|
|
839
|
+
value: draft,
|
|
840
|
+
onChange: (e) => setDraft(e.target.value),
|
|
841
|
+
onBlur: commit,
|
|
842
|
+
onKeyDown: (e) => {
|
|
843
|
+
if (e.key === "Enter") {
|
|
844
|
+
e.preventDefault();
|
|
845
|
+
commit();
|
|
846
|
+
} else if (e.key === "Escape") {
|
|
847
|
+
e.preventDefault();
|
|
848
|
+
cancel();
|
|
849
|
+
}
|
|
850
|
+
},
|
|
851
|
+
"aria-label": `Edit ${label}`,
|
|
852
|
+
size: Math.max(4, draft.length + 1),
|
|
853
|
+
className: cn7("min-w-0 bg-transparent outline-none", inputText)
|
|
854
|
+
}
|
|
855
|
+
) : /* @__PURE__ */ jsx8(
|
|
856
|
+
"span",
|
|
857
|
+
{
|
|
858
|
+
className: "min-w-0 whitespace-normal break-words text-left",
|
|
859
|
+
onDoubleClick: startEdit,
|
|
860
|
+
children: label
|
|
861
|
+
}
|
|
862
|
+
),
|
|
863
|
+
meta !== void 0 && meta !== null && /* @__PURE__ */ jsx8("span", { className: "shrink-0 tabular-nums text-muted-foreground", children: meta }),
|
|
864
|
+
editable && !editing && /* @__PURE__ */ jsx8(
|
|
865
|
+
"button",
|
|
866
|
+
{
|
|
867
|
+
type: "button",
|
|
868
|
+
"aria-label": `Edit ${label}`,
|
|
869
|
+
onClick: startEdit,
|
|
870
|
+
className: "shrink-0 rounded-full text-muted-foreground hover:text-foreground",
|
|
871
|
+
children: /* @__PURE__ */ jsx8(Pencil, { className: cn7("h-3 w-3", size === "md" && "h-3.5 w-3.5") })
|
|
872
|
+
}
|
|
873
|
+
),
|
|
874
|
+
onRemove && /* @__PURE__ */ jsx8(
|
|
875
|
+
"button",
|
|
876
|
+
{
|
|
877
|
+
type: "button",
|
|
878
|
+
"aria-label": `Remove ${label}`,
|
|
879
|
+
disabled,
|
|
880
|
+
onClick: onRemove,
|
|
881
|
+
className: "-mr-0.5 shrink-0 rounded-full text-muted-foreground hover:text-destructive disabled:pointer-events-none",
|
|
882
|
+
children: /* @__PURE__ */ jsx8(X, { className: ctl })
|
|
883
|
+
}
|
|
884
|
+
)
|
|
885
|
+
]
|
|
886
|
+
}
|
|
887
|
+
);
|
|
888
|
+
}
|
|
889
|
+
function normalize(item) {
|
|
890
|
+
return typeof item === "string" ? { label: item } : item;
|
|
891
|
+
}
|
|
892
|
+
function TagList({
|
|
893
|
+
items,
|
|
894
|
+
selected,
|
|
895
|
+
onToggle,
|
|
896
|
+
onRemove,
|
|
897
|
+
onEdit,
|
|
898
|
+
onAdd,
|
|
899
|
+
addPlaceholder = "Add\u2026",
|
|
900
|
+
emptyState,
|
|
901
|
+
read,
|
|
902
|
+
tone,
|
|
903
|
+
size = "sm",
|
|
904
|
+
disabled = false,
|
|
905
|
+
className
|
|
906
|
+
}) {
|
|
907
|
+
const { ReadEmpty, ReadStaleNotice } = getKindKitHost();
|
|
908
|
+
const [adding, setAdding] = React9.useState(false);
|
|
909
|
+
const [draft, setDraft] = React9.useState("");
|
|
910
|
+
const inputText = size === "md" ? "text-[16px] sm:text-sm" : "text-[16px] sm:text-xs";
|
|
911
|
+
const selectedSet = new Set(selected ?? []);
|
|
912
|
+
const commitAdd = () => {
|
|
913
|
+
const next = draft.trim();
|
|
914
|
+
if (next) onAdd?.(next);
|
|
915
|
+
setDraft("");
|
|
916
|
+
setAdding(false);
|
|
917
|
+
};
|
|
918
|
+
if (items.length === 0 && read && read.status !== "ready") return /* @__PURE__ */ jsx8(ReadEmpty, { read });
|
|
919
|
+
if (items.length === 0 && !onAdd) {
|
|
920
|
+
return emptyState !== void 0 ? /* @__PURE__ */ jsx8("div", { className: cn7("text-xs text-muted-foreground", className), children: emptyState }) : null;
|
|
921
|
+
}
|
|
922
|
+
return /* @__PURE__ */ jsxs7("div", { className: cn7("flex flex-wrap items-center gap-1.5", className), children: [
|
|
923
|
+
/* @__PURE__ */ jsx8(ReadStaleNotice, { read, className: "w-full" }),
|
|
924
|
+
items.map((raw, index) => {
|
|
925
|
+
const item = normalize(raw);
|
|
926
|
+
const key = item.key ?? item.label;
|
|
927
|
+
return /* @__PURE__ */ jsx8(
|
|
928
|
+
KeywordChip,
|
|
929
|
+
{
|
|
930
|
+
label: item.label,
|
|
931
|
+
meta: item.meta,
|
|
932
|
+
tone,
|
|
933
|
+
size,
|
|
934
|
+
disabled: disabled || item.disabled,
|
|
935
|
+
selected: selectedSet.has(key),
|
|
936
|
+
onSelect: onToggle ? (next) => onToggle(key, next) : void 0,
|
|
937
|
+
onRemove: onRemove ? () => onRemove(key, index) : void 0,
|
|
938
|
+
onEdit: onEdit ? (next) => onEdit(key, index, next) : void 0
|
|
939
|
+
},
|
|
940
|
+
`${key}-${index}`
|
|
941
|
+
);
|
|
942
|
+
}),
|
|
943
|
+
items.length === 0 && emptyState !== void 0 && /* @__PURE__ */ jsx8("span", { className: "text-xs text-muted-foreground", children: emptyState }),
|
|
944
|
+
onAdd && !disabled && (adding ? /* @__PURE__ */ jsx8(
|
|
945
|
+
"span",
|
|
946
|
+
{
|
|
947
|
+
className: cn7(
|
|
948
|
+
"inline-flex items-center gap-1 rounded-full border border-dashed border-primary/60 bg-background",
|
|
949
|
+
size === "md" ? "px-2.5 py-1 text-sm" : "px-2 py-0.5 text-xs"
|
|
950
|
+
),
|
|
951
|
+
children: /* @__PURE__ */ jsx8(
|
|
952
|
+
"input",
|
|
953
|
+
{
|
|
954
|
+
autoFocus: true,
|
|
955
|
+
value: draft,
|
|
956
|
+
placeholder: addPlaceholder,
|
|
957
|
+
onChange: (e) => setDraft(e.target.value),
|
|
958
|
+
onBlur: commitAdd,
|
|
959
|
+
onKeyDown: (e) => {
|
|
960
|
+
if (e.key === "Enter") {
|
|
961
|
+
e.preventDefault();
|
|
962
|
+
commitAdd();
|
|
963
|
+
} else if (e.key === "Escape") {
|
|
964
|
+
e.preventDefault();
|
|
965
|
+
setDraft("");
|
|
966
|
+
setAdding(false);
|
|
967
|
+
}
|
|
968
|
+
},
|
|
969
|
+
"aria-label": addPlaceholder,
|
|
970
|
+
size: Math.max(6, draft.length + 1),
|
|
971
|
+
className: cn7("min-w-0 bg-transparent outline-none placeholder:text-muted-foreground", inputText)
|
|
972
|
+
}
|
|
973
|
+
)
|
|
974
|
+
}
|
|
975
|
+
) : /* @__PURE__ */ jsxs7(
|
|
976
|
+
"button",
|
|
977
|
+
{
|
|
978
|
+
type: "button",
|
|
979
|
+
onClick: () => setAdding(true),
|
|
980
|
+
className: cn7(
|
|
981
|
+
"inline-flex items-center gap-1 rounded-full border border-dashed border-border text-muted-foreground hover:border-primary/60 hover:text-foreground",
|
|
982
|
+
size === "md" ? "px-2.5 py-1 text-sm" : "px-2 py-0.5 text-xs"
|
|
983
|
+
),
|
|
984
|
+
children: [
|
|
985
|
+
/* @__PURE__ */ jsx8(Plus, { className: "h-3 w-3" }),
|
|
986
|
+
addPlaceholder.replace(/…$/, "")
|
|
987
|
+
]
|
|
988
|
+
}
|
|
989
|
+
))
|
|
990
|
+
] });
|
|
991
|
+
}
|
|
992
|
+
export {
|
|
993
|
+
DefaultCopyButtons,
|
|
994
|
+
DefaultReadEmpty,
|
|
995
|
+
DefaultReadStaleNotice,
|
|
996
|
+
KeywordChip,
|
|
997
|
+
KindHeaderBar,
|
|
998
|
+
KindPanel,
|
|
999
|
+
KindPanelGrid,
|
|
1000
|
+
SortableList,
|
|
1001
|
+
StreamingSkeleton,
|
|
1002
|
+
TagList,
|
|
1003
|
+
getKindKitHost,
|
|
1004
|
+
renderKindKitIcon,
|
|
1005
|
+
resetKindKitHost,
|
|
1006
|
+
setKindKitHost,
|
|
1007
|
+
streamList,
|
|
1008
|
+
streamText,
|
|
1009
|
+
useStreamingValue
|
|
1010
|
+
};
|
|
1011
|
+
//# sourceMappingURL=kind-kit.js.map
|