@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.
Files changed (59) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/dist/{PastePills.types-CDyotkUb.d.cts → PastePills.types-CpXzsuwJ.d.cts} +2 -0
  3. package/dist/{PastePills.types-CDyotkUb.d.ts → PastePills.types-CpXzsuwJ.d.ts} +2 -0
  4. package/dist/{PastedFilesInput-CrgNoEBd.d.ts → PastedFilesInput-Bt3KSTVN.d.ts} +1 -1
  5. package/dist/{PastedFilesInput-DQ1eZaHk.d.cts → PastedFilesInput-CUQeOeOA.d.cts} +1 -1
  6. package/dist/{chunk-SZH7TFME.js → chunk-4EUDW2WU.js} +3 -3
  7. package/dist/{chunk-SZH7TFME.js.map → chunk-4EUDW2WU.js.map} +1 -1
  8. package/dist/{chunk-CMC2TOEQ.cjs → chunk-6CAXLP7D.cjs} +6 -6
  9. package/dist/{chunk-CMC2TOEQ.cjs.map → chunk-6CAXLP7D.cjs.map} +1 -1
  10. package/dist/{chunk-TQGRXJ74.cjs → chunk-7FYRFNPX.cjs} +9 -9
  11. package/dist/{chunk-TQGRXJ74.cjs.map → chunk-7FYRFNPX.cjs.map} +1 -1
  12. package/dist/{chunk-4XHG6Q42.cjs → chunk-7HXFEYOV.cjs} +8 -8
  13. package/dist/{chunk-4XHG6Q42.cjs.map → chunk-7HXFEYOV.cjs.map} +1 -1
  14. package/dist/{chunk-MVVHUTXA.js → chunk-B4LVQ4QI.js} +3 -3
  15. package/dist/{chunk-MVVHUTXA.js.map → chunk-B4LVQ4QI.js.map} +1 -1
  16. package/dist/{chunk-QNQNGARW.cjs → chunk-HFK5SBNM.cjs} +27 -9
  17. package/dist/chunk-HFK5SBNM.cjs.map +1 -0
  18. package/dist/{chunk-BTNF3QBR.js → chunk-J44EV6SP.js} +366 -32
  19. package/dist/chunk-J44EV6SP.js.map +1 -0
  20. package/dist/{chunk-Z6LYBL5L.cjs → chunk-MCQWTOTV.cjs} +369 -33
  21. package/dist/chunk-MCQWTOTV.cjs.map +1 -0
  22. package/dist/{chunk-ELFTEJBT.js → chunk-QSGAFKK2.js} +3 -3
  23. package/dist/{chunk-ELFTEJBT.js.map → chunk-QSGAFKK2.js.map} +1 -1
  24. package/dist/{chunk-NILA2LZY.js → chunk-YIKXJWO4.js} +27 -9
  25. package/dist/chunk-YIKXJWO4.js.map +1 -0
  26. package/dist/composer.cjs +4 -4
  27. package/dist/composer.d.cts +2 -2
  28. package/dist/composer.d.ts +2 -2
  29. package/dist/composer.js +2 -2
  30. package/dist/{index-BZON-gXr.d.ts → index-DWtSViJ3.d.cts} +147 -4
  31. package/dist/{index-BF5qsQur.d.cts → index-XR5t8bTq.d.ts} +147 -4
  32. package/dist/index.cjs +36 -28
  33. package/dist/index.d.cts +3 -3
  34. package/dist/index.d.ts +3 -3
  35. package/dist/index.js +5 -5
  36. package/dist/input.cjs +3 -3
  37. package/dist/input.d.cts +1 -1
  38. package/dist/input.d.ts +1 -1
  39. package/dist/input.js +2 -2
  40. package/dist/inputs.cjs +3 -3
  41. package/dist/inputs.d.cts +1 -1
  42. package/dist/inputs.d.ts +1 -1
  43. package/dist/inputs.js +2 -2
  44. package/dist/json-editor.cjs +14 -14
  45. package/dist/json-editor.js +3 -3
  46. package/dist/paste-pills.cjs +14 -14
  47. package/dist/paste-pills.d.cts +3 -3
  48. package/dist/paste-pills.d.ts +3 -3
  49. package/dist/paste-pills.js +1 -1
  50. package/dist/prompt-input.cjs +11 -3
  51. package/dist/prompt-input.d.cts +2 -2
  52. package/dist/prompt-input.d.ts +2 -2
  53. package/dist/prompt-input.js +2 -2
  54. package/docs/PromptInput.md +101 -1
  55. package/package.json +1 -1
  56. package/dist/chunk-BTNF3QBR.js.map +0 -1
  57. package/dist/chunk-NILA2LZY.js.map +0 -1
  58. package/dist/chunk-QNQNGARW.cjs.map +0 -1
  59. 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 chunkQNQNGARW_cjs = require('./chunk-QNQNGARW.cjs');
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
- function PromptInput({
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 = chunkQNQNGARW_cjs.useInlinePaste({
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 [attachments, setAttachments] = react.useState([]);
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: image.id,
167
- name: image.file.name,
168
- bytes: image.file.size,
169
- file: image.file,
170
- type: image.file.type
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
- setText("");
178
- setAttachments([]);
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
- setAttachments((cur) => [
215
- ...cur,
216
- ...files.map((f) => ({
217
- id: crypto.randomUUID(),
218
- name: f.name,
219
- bytes: f.size,
220
- file: f,
221
- type: f.type
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: () => setAttachments((cur) => cur.filter((x) => x.id !== a.id)),
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
- chunkQNQNGARW_cjs.InlinePasteEditor,
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
- chunkQNQNGARW_cjs.PastedFilesInput,
640
+ chunkHFK5SBNM_cjs.PastedFilesInput,
307
641
  {
308
642
  name: pasteFilesName,
309
- files: paste.imagesIn(text).map((i) => i.file)
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
- //# sourceMappingURL=chunk-Z6LYBL5L.cjs.map
490
- //# sourceMappingURL=chunk-Z6LYBL5L.cjs.map
823
+ exports.promptDataUrlToFile = promptDataUrlToFile;
824
+ exports.promptFileToDataUrl = promptFileToDataUrl;
825
+ //# sourceMappingURL=chunk-MCQWTOTV.cjs.map
826
+ //# sourceMappingURL=chunk-MCQWTOTV.cjs.map