@particle-academy/react-fancy 5.64.1 → 5.66.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 +67 -0
- package/dist/{PastePills.types-CDyotkUb.d.cts → PastePills.types-CpXzsuwJ.d.cts} +2 -0
- package/dist/{PastePills.types-CDyotkUb.d.ts → PastePills.types-CpXzsuwJ.d.ts} +2 -0
- package/dist/{PastedFilesInput-CrgNoEBd.d.ts → PastedFilesInput-Bt3KSTVN.d.ts} +1 -1
- package/dist/{PastedFilesInput-DQ1eZaHk.d.cts → PastedFilesInput-CUQeOeOA.d.cts} +1 -1
- package/dist/{chunk-SZH7TFME.js → chunk-4EUDW2WU.js} +3 -3
- package/dist/{chunk-SZH7TFME.js.map → chunk-4EUDW2WU.js.map} +1 -1
- package/dist/{chunk-CMC2TOEQ.cjs → chunk-6CAXLP7D.cjs} +6 -6
- package/dist/{chunk-CMC2TOEQ.cjs.map → chunk-6CAXLP7D.cjs.map} +1 -1
- package/dist/{chunk-TQGRXJ74.cjs → chunk-7FYRFNPX.cjs} +9 -9
- package/dist/{chunk-TQGRXJ74.cjs.map → chunk-7FYRFNPX.cjs.map} +1 -1
- package/dist/{chunk-4XHG6Q42.cjs → chunk-7HXFEYOV.cjs} +8 -8
- package/dist/{chunk-4XHG6Q42.cjs.map → chunk-7HXFEYOV.cjs.map} +1 -1
- package/dist/{chunk-MVVHUTXA.js → chunk-B4LVQ4QI.js} +3 -3
- package/dist/{chunk-MVVHUTXA.js.map → chunk-B4LVQ4QI.js.map} +1 -1
- package/dist/{chunk-QNQNGARW.cjs → chunk-HFK5SBNM.cjs} +27 -9
- package/dist/chunk-HFK5SBNM.cjs.map +1 -0
- package/dist/{chunk-BTNF3QBR.js → chunk-J44EV6SP.js} +366 -32
- package/dist/chunk-J44EV6SP.js.map +1 -0
- package/dist/{chunk-Z6LYBL5L.cjs → chunk-MCQWTOTV.cjs} +369 -33
- package/dist/chunk-MCQWTOTV.cjs.map +1 -0
- package/dist/{chunk-ELFTEJBT.js → chunk-QSGAFKK2.js} +3 -3
- package/dist/{chunk-ELFTEJBT.js.map → chunk-QSGAFKK2.js.map} +1 -1
- package/dist/{chunk-NILA2LZY.js → chunk-YIKXJWO4.js} +27 -9
- package/dist/chunk-YIKXJWO4.js.map +1 -0
- package/dist/composer.cjs +4 -4
- package/dist/composer.d.cts +2 -2
- package/dist/composer.d.ts +2 -2
- package/dist/composer.js +2 -2
- package/dist/{index-BZON-gXr.d.ts → index-DWtSViJ3.d.cts} +147 -4
- package/dist/{index-BF5qsQur.d.cts → index-XR5t8bTq.d.ts} +147 -4
- package/dist/index.cjs +36 -28
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +5 -5
- package/dist/input.cjs +3 -3
- package/dist/input.d.cts +1 -1
- package/dist/input.d.ts +1 -1
- package/dist/input.js +2 -2
- package/dist/inputs.cjs +3 -3
- package/dist/inputs.d.cts +1 -1
- package/dist/inputs.d.ts +1 -1
- package/dist/inputs.js +2 -2
- package/dist/json-editor.cjs +14 -14
- package/dist/json-editor.js +3 -3
- package/dist/paste-pills.cjs +14 -14
- package/dist/paste-pills.d.cts +3 -3
- package/dist/paste-pills.d.ts +3 -3
- package/dist/paste-pills.js +1 -1
- package/dist/prompt-input.cjs +11 -3
- package/dist/prompt-input.d.cts +2 -2
- package/dist/prompt-input.d.ts +2 -2
- package/dist/prompt-input.js +2 -2
- package/docs/PromptInput.md +101 -1
- package/package.json +1 -1
- package/dist/chunk-BTNF3QBR.js.map +0 -1
- package/dist/chunk-NILA2LZY.js.map +0 -1
- package/dist/chunk-QNQNGARW.cjs.map +0 -1
- package/dist/chunk-Z6LYBL5L.cjs.map +0 -1
|
@@ -1,13 +1,102 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkOASSZI6M_cjs = require('./chunk-OASSZI6M.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunkHFK5SBNM_cjs = require('./chunk-HFK5SBNM.cjs');
|
|
5
5
|
var chunkC5YX5XVL_cjs = require('./chunk-C5YX5XVL.cjs');
|
|
6
6
|
var chunkMXWR3T3N_cjs = require('./chunk-MXWR3T3N.cjs');
|
|
7
7
|
var chunkZU5Q77OT_cjs = require('./chunk-ZU5Q77OT.cjs');
|
|
8
8
|
var react = require('react');
|
|
9
9
|
var jsxRuntime = require('react/jsx-runtime');
|
|
10
10
|
|
|
11
|
+
// src/components/PromptInput/prompt-draft.ts
|
|
12
|
+
var EMPTY_DRAFT = { v: 1, text: "", pills: [], attachments: [] };
|
|
13
|
+
function readFile(raw, id) {
|
|
14
|
+
if (!raw || typeof raw !== "object") return null;
|
|
15
|
+
const f = raw;
|
|
16
|
+
const fileId = id ?? f.id;
|
|
17
|
+
if (typeof fileId !== "string" || typeof f.name !== "string") return null;
|
|
18
|
+
const out = {
|
|
19
|
+
id: fileId,
|
|
20
|
+
name: f.name,
|
|
21
|
+
type: typeof f.type === "string" ? f.type : "",
|
|
22
|
+
bytes: typeof f.bytes === "number" && Number.isFinite(f.bytes) ? f.bytes : 0
|
|
23
|
+
};
|
|
24
|
+
if (typeof f.ref === "string") out.ref = f.ref;
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
function readPill(raw) {
|
|
28
|
+
if (!raw || typeof raw !== "object") return null;
|
|
29
|
+
const p = raw;
|
|
30
|
+
if (typeof p.id !== "string") return null;
|
|
31
|
+
if (p.kind === "text" && typeof p.text === "string") {
|
|
32
|
+
return typeof p.label === "string" ? { kind: "text", id: p.id, text: p.text, label: p.label } : { kind: "text", id: p.id, text: p.text };
|
|
33
|
+
}
|
|
34
|
+
if (p.kind === "image" && typeof p.label === "string") {
|
|
35
|
+
const file = readFile(p.file, p.id);
|
|
36
|
+
return file ? { kind: "image", id: p.id, label: p.label, file } : null;
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
function readPromptDraft(raw, inline) {
|
|
41
|
+
if (!raw || typeof raw !== "object" || raw.v !== 1) return null;
|
|
42
|
+
const d = raw;
|
|
43
|
+
let text = typeof d.text === "string" ? d.text : "";
|
|
44
|
+
let pills = (Array.isArray(d.pills) ? d.pills : []).map(readPill).filter((p) => p !== null);
|
|
45
|
+
let attachments = (Array.isArray(d.attachments) ? d.attachments : []).map((a) => readFile(a)).filter((a) => a !== null);
|
|
46
|
+
const marked = new Set(chunkHFK5SBNM_cjs.markedIds(text));
|
|
47
|
+
pills = pills.filter((p) => marked.has(p.id));
|
|
48
|
+
if (!inline && pills.length > 0) {
|
|
49
|
+
const texts = pills.flatMap((p) => p.kind === "text" ? [{ id: p.id, text: p.text }] : []);
|
|
50
|
+
const images = pills.flatMap((p) => p.kind === "image" ? [p] : []);
|
|
51
|
+
text = chunkHFK5SBNM_cjs.expandMarkers(
|
|
52
|
+
text,
|
|
53
|
+
texts,
|
|
54
|
+
images.map((p) => ({ id: p.id, label: p.label }))
|
|
55
|
+
);
|
|
56
|
+
attachments = [...attachments, ...images.map((p) => p.file)];
|
|
57
|
+
pills = [];
|
|
58
|
+
}
|
|
59
|
+
return { v: 1, text, pills, attachments };
|
|
60
|
+
}
|
|
61
|
+
function clonePromptDraft(draft) {
|
|
62
|
+
return JSON.parse(JSON.stringify(draft));
|
|
63
|
+
}
|
|
64
|
+
function promptDraftFiles(draft) {
|
|
65
|
+
return [
|
|
66
|
+
...draft.attachments,
|
|
67
|
+
...draft.pills.flatMap((p) => p.kind === "image" ? [p.file] : [])
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
function promptFileToDataUrl(file) {
|
|
71
|
+
return new Promise((resolve, reject) => {
|
|
72
|
+
const reader = new FileReader();
|
|
73
|
+
reader.onload = () => resolve(String(reader.result));
|
|
74
|
+
reader.onerror = () => reject(reader.error);
|
|
75
|
+
reader.readAsDataURL(file);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function promptDataUrlToFile(dataUrl, name, type) {
|
|
79
|
+
if (!dataUrl.startsWith("data:")) return void 0;
|
|
80
|
+
const comma = dataUrl.indexOf(",");
|
|
81
|
+
if (comma < 0) return void 0;
|
|
82
|
+
const meta = dataUrl.slice(5, comma);
|
|
83
|
+
const body = dataUrl.slice(comma + 1);
|
|
84
|
+
const mime = type || meta.split(";")[0] || "application/octet-stream";
|
|
85
|
+
try {
|
|
86
|
+
let bytes;
|
|
87
|
+
if (meta.endsWith(";base64")) {
|
|
88
|
+
const bin = atob(body);
|
|
89
|
+
bytes = new Uint8Array(bin.length);
|
|
90
|
+
for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
|
|
91
|
+
} else {
|
|
92
|
+
bytes = new TextEncoder().encode(decodeURIComponent(body));
|
|
93
|
+
}
|
|
94
|
+
return new File([bytes], name, { type: mime });
|
|
95
|
+
} catch {
|
|
96
|
+
return void 0;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
11
100
|
// src/utils/platform.ts
|
|
12
101
|
var APPLE_UA_DATA_PLATFORMS = /* @__PURE__ */ new Set(["macos", "ios", "ipados"]);
|
|
13
102
|
var APPLE_FREE_TEXT = /\b(mac|macintosh|iphone|ipad|ipod|darwin)/i;
|
|
@@ -34,7 +123,15 @@ var DEFAULT_MENTION_COLOR = {
|
|
|
34
123
|
file: "#10b981",
|
|
35
124
|
person: "#3b82f6"
|
|
36
125
|
};
|
|
37
|
-
|
|
126
|
+
var PromptInput = react.forwardRef(function PromptInput2({
|
|
127
|
+
value: controlledValue,
|
|
128
|
+
defaultValue,
|
|
129
|
+
onChange,
|
|
130
|
+
draft: controlledDraft,
|
|
131
|
+
defaultDraft,
|
|
132
|
+
onDraftChange,
|
|
133
|
+
persistAttachment,
|
|
134
|
+
restoreAttachment,
|
|
38
135
|
budgetTokens,
|
|
39
136
|
commands = [],
|
|
40
137
|
mentions = [],
|
|
@@ -60,20 +157,209 @@ function PromptInput({
|
|
|
60
157
|
meterShowAt = 0.75,
|
|
61
158
|
meterWarnAt = 0.9,
|
|
62
159
|
...rest
|
|
63
|
-
}) {
|
|
64
|
-
const [text, setText] = react.useState("");
|
|
160
|
+
}, ref) {
|
|
65
161
|
const inline = pasteThreshold !== void 0 || pasteImages;
|
|
162
|
+
const draftControlled = controlledDraft !== void 0;
|
|
163
|
+
const [innerDraft, setInnerDraft] = react.useState(
|
|
164
|
+
() => defaultDraft && readPromptDraft(defaultDraft, inline) || {
|
|
165
|
+
...EMPTY_DRAFT,
|
|
166
|
+
text: defaultValue ?? ""
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
const baseDraft = draftControlled ? controlledDraft : innerDraft;
|
|
170
|
+
const model = !draftControlled && controlledValue !== void 0 && controlledValue !== baseDraft.text ? { ...baseDraft, text: controlledValue } : baseDraft;
|
|
171
|
+
const modelRef = react.useRef(model);
|
|
172
|
+
modelRef.current = model;
|
|
173
|
+
const text = model.text;
|
|
174
|
+
const onChangeRef = react.useRef(onChange);
|
|
175
|
+
onChangeRef.current = onChange;
|
|
176
|
+
const onDraftChangeRef = react.useRef(onDraftChange);
|
|
177
|
+
onDraftChangeRef.current = onDraftChange;
|
|
178
|
+
const persistRef = react.useRef(persistAttachment);
|
|
179
|
+
persistRef.current = persistAttachment;
|
|
180
|
+
const commit = react.useCallback(
|
|
181
|
+
(update, notify = true) => {
|
|
182
|
+
const prev = modelRef.current;
|
|
183
|
+
const next = update(prev);
|
|
184
|
+
if (next === prev) return;
|
|
185
|
+
modelRef.current = next;
|
|
186
|
+
setInnerDraft(next);
|
|
187
|
+
if (!notify) return;
|
|
188
|
+
if (next.text !== prev.text) onChangeRef.current?.(next.text);
|
|
189
|
+
onDraftChangeRef.current?.(next);
|
|
190
|
+
},
|
|
191
|
+
[]
|
|
192
|
+
);
|
|
193
|
+
const filesRef = react.useRef(/* @__PURE__ */ new Map());
|
|
194
|
+
const placeholdersRef = react.useRef(/* @__PURE__ */ new Map());
|
|
195
|
+
const requestedRef = react.useRef(/* @__PURE__ */ new Set());
|
|
196
|
+
const [filesVersion, bumpFiles] = react.useReducer((n) => n + 1, 0);
|
|
197
|
+
const setFileRef = react.useCallback(
|
|
198
|
+
(id, fileRef2) => commit((m) => {
|
|
199
|
+
const withRef = (f) => f.id === id ? { ...f, ref: fileRef2 } : f;
|
|
200
|
+
if (!promptDraftFiles(m).some((f) => f.id === id)) return m;
|
|
201
|
+
return {
|
|
202
|
+
...m,
|
|
203
|
+
attachments: m.attachments.map(withRef),
|
|
204
|
+
pills: m.pills.map((p) => p.kind === "image" ? { ...p, file: withRef(p.file) } : p)
|
|
205
|
+
};
|
|
206
|
+
}),
|
|
207
|
+
[commit]
|
|
208
|
+
);
|
|
209
|
+
const persist = react.useCallback(
|
|
210
|
+
(file, entry) => {
|
|
211
|
+
const store = persistRef.current;
|
|
212
|
+
if (!store) return void 0;
|
|
213
|
+
let out;
|
|
214
|
+
try {
|
|
215
|
+
out = store(file, entry);
|
|
216
|
+
} catch (error) {
|
|
217
|
+
console.error("PromptInput: persistAttachment threw", error);
|
|
218
|
+
return void 0;
|
|
219
|
+
}
|
|
220
|
+
if (typeof out === "string") return out;
|
|
221
|
+
if (out && typeof out.then === "function") {
|
|
222
|
+
out.then(
|
|
223
|
+
(fileRef2) => {
|
|
224
|
+
if (typeof fileRef2 === "string") setFileRef(entry.id, fileRef2);
|
|
225
|
+
},
|
|
226
|
+
(error) => console.error("PromptInput: persistAttachment rejected", error)
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
return void 0;
|
|
230
|
+
},
|
|
231
|
+
[setFileRef]
|
|
232
|
+
);
|
|
233
|
+
const fileMeta = (id, file) => ({
|
|
234
|
+
id,
|
|
235
|
+
name: file.name,
|
|
236
|
+
type: file.type,
|
|
237
|
+
bytes: file.size
|
|
238
|
+
});
|
|
239
|
+
const fileFor = react.useCallback((entry) => {
|
|
240
|
+
const real = filesRef.current.get(entry.id);
|
|
241
|
+
if (real) return real;
|
|
242
|
+
let stand = placeholdersRef.current.get(entry.id);
|
|
243
|
+
if (!stand) {
|
|
244
|
+
stand = new File([], entry.name, { type: entry.type });
|
|
245
|
+
placeholdersRef.current.set(entry.id, stand);
|
|
246
|
+
}
|
|
247
|
+
return stand;
|
|
248
|
+
}, []);
|
|
249
|
+
const heldPastes = react.useMemo(
|
|
250
|
+
() => model.pills.flatMap(
|
|
251
|
+
(p) => p.kind === "text" ? [p.label !== void 0 ? { id: p.id, text: p.text, label: p.label } : { id: p.id, text: p.text }] : []
|
|
252
|
+
),
|
|
253
|
+
[model.pills]
|
|
254
|
+
);
|
|
255
|
+
const heldImages = react.useMemo(
|
|
256
|
+
() => model.pills.flatMap(
|
|
257
|
+
(p) => p.kind === "image" ? [{ id: p.id, label: p.label, file: fileFor(p.file) }] : []
|
|
258
|
+
),
|
|
259
|
+
// filesVersion: a restored File arrived, so the stand-in can be swapped out.
|
|
260
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
261
|
+
[model.pills, fileFor, filesVersion]
|
|
262
|
+
);
|
|
263
|
+
const onHeldPastesChange = react.useCallback(
|
|
264
|
+
(next) => commit((m) => {
|
|
265
|
+
const current = m.pills.filter((p) => p.kind === "text");
|
|
266
|
+
if (current.length === next.length && current.every(
|
|
267
|
+
(p, i) => p.id === next[i].id && p.kind === "text" && p.text === next[i].text && p.label === next[i].label
|
|
268
|
+
)) {
|
|
269
|
+
return m;
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
...m,
|
|
273
|
+
pills: [
|
|
274
|
+
...next.map(
|
|
275
|
+
(p) => p.label !== void 0 ? { kind: "text", id: p.id, text: p.text, label: p.label } : { kind: "text", id: p.id, text: p.text }
|
|
276
|
+
),
|
|
277
|
+
...m.pills.filter((p) => p.kind === "image")
|
|
278
|
+
]
|
|
279
|
+
};
|
|
280
|
+
}),
|
|
281
|
+
[commit]
|
|
282
|
+
);
|
|
283
|
+
const onHeldImagesChange = react.useCallback(
|
|
284
|
+
(next) => commit((m) => {
|
|
285
|
+
const before = new Map(
|
|
286
|
+
m.pills.flatMap((p) => p.kind === "image" ? [[p.id, p]] : [])
|
|
287
|
+
);
|
|
288
|
+
if (before.size === next.length && next.every((i) => before.has(i.id))) return m;
|
|
289
|
+
const images = next.map((image) => {
|
|
290
|
+
const known = before.get(image.id);
|
|
291
|
+
if (known && known.kind === "image") return known;
|
|
292
|
+
filesRef.current.set(image.id, image.file);
|
|
293
|
+
const entry = fileMeta(image.id, image.file);
|
|
294
|
+
const fileRef2 = persist(image.file, entry);
|
|
295
|
+
return {
|
|
296
|
+
kind: "image",
|
|
297
|
+
id: image.id,
|
|
298
|
+
label: image.label,
|
|
299
|
+
file: fileRef2 === void 0 ? entry : { ...entry, ref: fileRef2 }
|
|
300
|
+
};
|
|
301
|
+
});
|
|
302
|
+
return { ...m, pills: [...m.pills.filter((p) => p.kind === "text"), ...images] };
|
|
303
|
+
}),
|
|
304
|
+
[commit, persist]
|
|
305
|
+
);
|
|
66
306
|
const editorRef = react.useRef(null);
|
|
67
|
-
const paste =
|
|
307
|
+
const paste = chunkHFK5SBNM_cjs.useInlinePaste({
|
|
68
308
|
pasteThreshold,
|
|
69
309
|
pasteImages,
|
|
70
310
|
previewChars,
|
|
71
311
|
renderPastePreview,
|
|
72
312
|
classNames: pasteClassNames,
|
|
73
313
|
disabled: false,
|
|
314
|
+
heldPastes,
|
|
315
|
+
onHeldPastesChange,
|
|
316
|
+
heldImages,
|
|
317
|
+
onHeldImagesChange,
|
|
74
318
|
editorRef
|
|
75
319
|
});
|
|
76
|
-
const
|
|
320
|
+
const attachments = react.useMemo(
|
|
321
|
+
() => model.attachments.map((a) => ({
|
|
322
|
+
id: a.id,
|
|
323
|
+
name: a.name,
|
|
324
|
+
bytes: a.bytes,
|
|
325
|
+
file: filesRef.current.get(a.id),
|
|
326
|
+
type: a.type,
|
|
327
|
+
...a.ref !== void 0 ? { ref: a.ref } : {}
|
|
328
|
+
})),
|
|
329
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
330
|
+
[model.attachments, filesVersion]
|
|
331
|
+
);
|
|
332
|
+
const restoreRef = react.useRef(restoreAttachment);
|
|
333
|
+
restoreRef.current = restoreAttachment;
|
|
334
|
+
react.useEffect(() => {
|
|
335
|
+
const restore = restoreRef.current;
|
|
336
|
+
if (!restore) return;
|
|
337
|
+
for (const entry of promptDraftFiles(model)) {
|
|
338
|
+
if (filesRef.current.has(entry.id) || requestedRef.current.has(entry.id)) continue;
|
|
339
|
+
requestedRef.current.add(entry.id);
|
|
340
|
+
const accept = (file) => {
|
|
341
|
+
if (!(file instanceof Blob)) return;
|
|
342
|
+
filesRef.current.set(entry.id, file);
|
|
343
|
+
bumpFiles();
|
|
344
|
+
};
|
|
345
|
+
let out;
|
|
346
|
+
try {
|
|
347
|
+
out = restore(entry);
|
|
348
|
+
} catch (error) {
|
|
349
|
+
console.error("PromptInput: restoreAttachment threw", error);
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
if (out && typeof out.then === "function") {
|
|
353
|
+
out.then(
|
|
354
|
+
accept,
|
|
355
|
+
(error) => console.error("PromptInput: restoreAttachment rejected", error)
|
|
356
|
+
);
|
|
357
|
+
} else {
|
|
358
|
+
accept(out);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}, [model]);
|
|
362
|
+
const setText = (next) => commit((m) => m.text === next ? m : { ...m, text: next });
|
|
77
363
|
const [picker, setPicker] = react.useState(null);
|
|
78
364
|
const taRef = react.useRef(null);
|
|
79
365
|
const fileRef = react.useRef(null);
|
|
@@ -162,22 +448,68 @@ function PromptInput({
|
|
|
162
448
|
const submit = () => {
|
|
163
449
|
if (!text.trim() && attachments.length === 0) return;
|
|
164
450
|
if (inline) {
|
|
165
|
-
const pastedImages = paste.imagesIn(text).map((image) =>
|
|
166
|
-
id
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
451
|
+
const pastedImages = paste.imagesIn(text).map((image) => {
|
|
452
|
+
const entry = model.pills.find((p) => p.id === image.id);
|
|
453
|
+
const meta = entry?.kind === "image" ? entry.file : fileMeta(image.id, image.file);
|
|
454
|
+
return {
|
|
455
|
+
id: image.id,
|
|
456
|
+
name: meta.name,
|
|
457
|
+
bytes: meta.bytes,
|
|
458
|
+
file: filesRef.current.get(image.id),
|
|
459
|
+
type: meta.type,
|
|
460
|
+
...meta.ref !== void 0 ? { ref: meta.ref } : {}
|
|
461
|
+
};
|
|
462
|
+
});
|
|
172
463
|
onSubmit(paste.expand(text), [...attachments, ...pastedImages]);
|
|
173
|
-
paste.clear();
|
|
174
464
|
} else {
|
|
175
465
|
onSubmit(text, attachments);
|
|
176
466
|
}
|
|
177
|
-
|
|
178
|
-
|
|
467
|
+
commit(() => EMPTY_DRAFT);
|
|
468
|
+
filesRef.current.clear();
|
|
469
|
+
placeholdersRef.current.clear();
|
|
470
|
+
requestedRef.current.clear();
|
|
179
471
|
setPicker(null);
|
|
180
472
|
};
|
|
473
|
+
const pendingFocus = react.useRef(false);
|
|
474
|
+
const focusInput = react.useCallback(() => {
|
|
475
|
+
if (inline) {
|
|
476
|
+
editorRef.current?.focus();
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
const ta = taRef.current;
|
|
480
|
+
if (!ta) return;
|
|
481
|
+
ta.focus();
|
|
482
|
+
ta.setSelectionRange(ta.value.length, ta.value.length);
|
|
483
|
+
}, [inline]);
|
|
484
|
+
react.useLayoutEffect(() => {
|
|
485
|
+
if (!pendingFocus.current) return;
|
|
486
|
+
pendingFocus.current = false;
|
|
487
|
+
focusInput();
|
|
488
|
+
});
|
|
489
|
+
react.useImperativeHandle(
|
|
490
|
+
ref,
|
|
491
|
+
() => ({
|
|
492
|
+
getDraft: () => clonePromptDraft(modelRef.current),
|
|
493
|
+
setDraft(next, options) {
|
|
494
|
+
const read = readPromptDraft(next, inline);
|
|
495
|
+
if (!read) {
|
|
496
|
+
console.warn(
|
|
497
|
+
"PromptInput: setDraft ignored a draft it does not recognise (expected { v: 1, ... }).",
|
|
498
|
+
next
|
|
499
|
+
);
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
for (const entry of promptDraftFiles(read)) {
|
|
503
|
+
if (!filesRef.current.has(entry.id)) requestedRef.current.delete(entry.id);
|
|
504
|
+
}
|
|
505
|
+
setPicker(null);
|
|
506
|
+
commit(() => read, false);
|
|
507
|
+
if (options?.focus) pendingFocus.current = true;
|
|
508
|
+
},
|
|
509
|
+
focus: focusInput
|
|
510
|
+
}),
|
|
511
|
+
[inline, commit, focusInput]
|
|
512
|
+
);
|
|
181
513
|
const onKeyDown = (e) => {
|
|
182
514
|
if (picker) {
|
|
183
515
|
if (e.key === "ArrowDown") {
|
|
@@ -211,16 +543,14 @@ function PromptInput({
|
|
|
211
543
|
const attach = (list) => {
|
|
212
544
|
const files = Array.from(list ?? []);
|
|
213
545
|
if (files.length === 0) return;
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}))
|
|
223
|
-
]);
|
|
546
|
+
const added = files.map((f) => {
|
|
547
|
+
const id = crypto.randomUUID();
|
|
548
|
+
filesRef.current.set(id, f);
|
|
549
|
+
const entry = fileMeta(id, f);
|
|
550
|
+
const fileRef2 = persist(f, entry);
|
|
551
|
+
return fileRef2 === void 0 ? entry : { ...entry, ref: fileRef2 };
|
|
552
|
+
});
|
|
553
|
+
commit((m) => ({ ...m, attachments: [...m.attachments, ...added] }));
|
|
224
554
|
};
|
|
225
555
|
const onDrop = (e) => {
|
|
226
556
|
e.preventDefault();
|
|
@@ -256,6 +586,7 @@ function PromptInput({
|
|
|
256
586
|
attachments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1.5 border-b border-zinc-200 px-3 py-2 dark:border-zinc-800", children: attachments.map((a) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
257
587
|
"span",
|
|
258
588
|
{
|
|
589
|
+
"data-react-fancy-prompt-input-attachment": a.id,
|
|
259
590
|
className: "inline-flex items-center gap-1.5 rounded-md bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] px-2 py-0.5 text-[11px] dark:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]",
|
|
260
591
|
children: [
|
|
261
592
|
/* @__PURE__ */ jsxRuntime.jsx(chunkMXWR3T3N_cjs.Icon, { name: "paperclip", size: "xs", className: "text-zinc-400" }),
|
|
@@ -264,7 +595,10 @@ function PromptInput({
|
|
|
264
595
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
265
596
|
"button",
|
|
266
597
|
{
|
|
267
|
-
onClick: () =>
|
|
598
|
+
onClick: () => commit((m) => ({
|
|
599
|
+
...m,
|
|
600
|
+
attachments: m.attachments.filter((x) => x.id !== a.id)
|
|
601
|
+
})),
|
|
268
602
|
className: "opacity-50 hover:opacity-100",
|
|
269
603
|
"aria-label": "Remove attachment",
|
|
270
604
|
children: "\xD7"
|
|
@@ -277,7 +611,7 @@ function PromptInput({
|
|
|
277
611
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
278
612
|
inline ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
279
613
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
280
|
-
|
|
614
|
+
chunkHFK5SBNM_cjs.InlinePasteEditor,
|
|
281
615
|
{
|
|
282
616
|
ref: editorRef,
|
|
283
617
|
value: text,
|
|
@@ -303,10 +637,10 @@ function PromptInput({
|
|
|
303
637
|
),
|
|
304
638
|
paste.portals,
|
|
305
639
|
pasteImages && pasteFilesName && /* @__PURE__ */ jsxRuntime.jsx(
|
|
306
|
-
|
|
640
|
+
chunkHFK5SBNM_cjs.PastedFilesInput,
|
|
307
641
|
{
|
|
308
642
|
name: pasteFilesName,
|
|
309
|
-
files: paste.imagesIn(text).
|
|
643
|
+
files: paste.imagesIn(text).flatMap((i) => filesRef.current.has(i.id) ? [i.file] : [])
|
|
310
644
|
}
|
|
311
645
|
)
|
|
312
646
|
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -471,7 +805,7 @@ function PromptInput({
|
|
|
471
805
|
]
|
|
472
806
|
}
|
|
473
807
|
);
|
|
474
|
-
}
|
|
808
|
+
});
|
|
475
809
|
function fmtTokens(n) {
|
|
476
810
|
if (n < 1e3) return `${n}`;
|
|
477
811
|
return `${(n / 1e3).toFixed(1)}k`;
|
|
@@ -486,5 +820,7 @@ exports.PromptInput = PromptInput;
|
|
|
486
820
|
exports.browserPlatformHints = browserPlatformHints;
|
|
487
821
|
exports.detectPlatform = detectPlatform;
|
|
488
822
|
exports.modifierKeyLabel = modifierKeyLabel;
|
|
489
|
-
|
|
490
|
-
|
|
823
|
+
exports.promptDataUrlToFile = promptDataUrlToFile;
|
|
824
|
+
exports.promptFileToDataUrl = promptFileToDataUrl;
|
|
825
|
+
//# sourceMappingURL=chunk-MCQWTOTV.cjs.map
|
|
826
|
+
//# sourceMappingURL=chunk-MCQWTOTV.cjs.map
|