@particle-academy/react-fancy 5.37.0 → 5.39.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 (64) hide show
  1. package/CHANGELOG.md +133 -0
  2. package/dist/{index-C8PKWA_5.d.cts → Composer.types-CuSPnaOt.d.cts} +103 -7
  3. package/dist/{index-C8PKWA_5.d.ts → Composer.types-CuSPnaOt.d.ts} +103 -7
  4. package/dist/autocomplete.cjs +3 -3
  5. package/dist/autocomplete.js +2 -2
  6. package/dist/chunk-2JOWGYAJ.js +609 -0
  7. package/dist/chunk-2JOWGYAJ.js.map +1 -0
  8. package/dist/chunk-6TZPM43Q.cjs +616 -0
  9. package/dist/chunk-6TZPM43Q.cjs.map +1 -0
  10. package/dist/{chunk-FXP4JLGU.cjs → chunk-AR3JOPGT.cjs} +3 -3
  11. package/dist/{chunk-FXP4JLGU.cjs.map → chunk-AR3JOPGT.cjs.map} +1 -1
  12. package/dist/{chunk-23FTDEGR.cjs → chunk-BZOU7VJQ.cjs} +97 -84
  13. package/dist/chunk-BZOU7VJQ.cjs.map +1 -0
  14. package/dist/{chunk-35EN5AYE.js → chunk-CF5KRDN4.js} +6 -3
  15. package/dist/chunk-CF5KRDN4.js.map +1 -0
  16. package/dist/{chunk-DNV7MUEE.cjs → chunk-FJ2GMQLC.cjs} +117 -27
  17. package/dist/chunk-FJ2GMQLC.cjs.map +1 -0
  18. package/dist/{chunk-6ASZUE4T.js → chunk-FQLL2JI7.js} +3 -3
  19. package/dist/{chunk-6ASZUE4T.js.map → chunk-FQLL2JI7.js.map} +1 -1
  20. package/dist/{chunk-ZH3SPBVB.js → chunk-IECPLOSZ.js} +3 -3
  21. package/dist/{chunk-ZH3SPBVB.js.map → chunk-IECPLOSZ.js.map} +1 -1
  22. package/dist/{chunk-E2SZBIAV.cjs → chunk-IWQ3ZFLZ.cjs} +5 -5
  23. package/dist/{chunk-E2SZBIAV.cjs.map → chunk-IWQ3ZFLZ.cjs.map} +1 -1
  24. package/dist/{chunk-QBNR5IVM.cjs → chunk-MFBUK4RV.cjs} +3 -3
  25. package/dist/{chunk-QBNR5IVM.cjs.map → chunk-MFBUK4RV.cjs.map} +1 -1
  26. package/dist/{chunk-2XAVAPDA.js → chunk-MXAVGOHW.js} +99 -85
  27. package/dist/chunk-MXAVGOHW.js.map +1 -0
  28. package/dist/{chunk-ISPCXIJZ.cjs → chunk-X7H75WVP.cjs} +6 -3
  29. package/dist/chunk-X7H75WVP.cjs.map +1 -0
  30. package/dist/{chunk-O3WEV562.js → chunk-YLPVTEUH.js} +118 -28
  31. package/dist/chunk-YLPVTEUH.js.map +1 -0
  32. package/dist/{chunk-O2ZHORSC.js → chunk-Z6RVBZQ4.js} +3 -3
  33. package/dist/{chunk-O2ZHORSC.js.map → chunk-Z6RVBZQ4.js.map} +1 -1
  34. package/dist/composer.cjs +10 -2
  35. package/dist/composer.d.cts +7 -2
  36. package/dist/composer.d.ts +7 -2
  37. package/dist/composer.js +5 -1
  38. package/dist/editor.cjs +1 -1
  39. package/dist/editor.js +1 -1
  40. package/dist/{index-DXUAAZzE.d.ts → index-BsIBOwaK.d.cts} +46 -1
  41. package/dist/{index-DXUAAZzE.d.cts → index-S4FC1yFK.d.ts} +46 -1
  42. package/dist/index.cjs +40 -35
  43. package/dist/index.d.cts +3 -2
  44. package/dist/index.d.ts +3 -2
  45. package/dist/index.js +8 -7
  46. package/dist/inputs.cjs +3 -3
  47. package/dist/inputs.js +2 -2
  48. package/dist/json-editor.cjs +14 -14
  49. package/dist/json-editor.js +3 -3
  50. package/dist/prompt-input.cjs +5 -3
  51. package/dist/prompt-input.d.cts +2 -1
  52. package/dist/prompt-input.d.ts +2 -1
  53. package/dist/prompt-input.js +4 -2
  54. package/dist/select.cjs +3 -3
  55. package/dist/select.js +2 -2
  56. package/dist/tooltip.cjs +2 -2
  57. package/dist/tooltip.js +1 -1
  58. package/package.json +1 -1
  59. package/dist/chunk-23FTDEGR.cjs.map +0 -1
  60. package/dist/chunk-2XAVAPDA.js.map +0 -1
  61. package/dist/chunk-35EN5AYE.js.map +0 -1
  62. package/dist/chunk-DNV7MUEE.cjs.map +0 -1
  63. package/dist/chunk-ISPCXIJZ.cjs.map +0 -1
  64. package/dist/chunk-O3WEV562.js.map +0 -1
@@ -1,58 +1,12 @@
1
1
  'use strict';
2
2
 
3
+ var chunk6TZPM43Q_cjs = require('./chunk-6TZPM43Q.cjs');
3
4
  var chunkSNHU2AI4_cjs = require('./chunk-SNHU2AI4.cjs');
4
5
  var chunkZU5Q77OT_cjs = require('./chunk-ZU5Q77OT.cjs');
5
6
  var react = require('react');
6
7
  var jsxRuntime = require('react/jsx-runtime');
7
8
 
8
- function usePastePills({
9
- threshold,
10
- heldPastes: controlledHeldPastes,
11
- onHeldPastesChange
12
- } = {}) {
13
- const [heldPastes, setHeldPastes] = chunkSNHU2AI4_cjs.useControllableState(
14
- controlledHeldPastes,
15
- [],
16
- onHeldPastesChange
17
- );
18
- const nextId = react.useRef(0);
19
- const handlePaste = react.useCallback(
20
- (event) => {
21
- if (!threshold || threshold <= 0) return false;
22
- const text = event.clipboardData?.getData("text/plain") ?? "";
23
- if (text.length < threshold) return false;
24
- event.preventDefault();
25
- nextId.current += 1;
26
- const id = `paste-${nextId.current}`;
27
- setHeldPastes((current) => [...current, { id, text }]);
28
- return true;
29
- },
30
- [threshold, setHeldPastes]
31
- );
32
- const expand = react.useCallback(
33
- (id) => {
34
- const found = heldPastes.find((p) => p.id === id);
35
- if (found === void 0) return void 0;
36
- setHeldPastes((current) => current.filter((p) => p.id !== id));
37
- return found.text;
38
- },
39
- [heldPastes, setHeldPastes]
40
- );
41
- const remove = react.useCallback(
42
- (id) => setHeldPastes((current) => current.filter((p) => p.id !== id)),
43
- [setHeldPastes]
44
- );
45
- const clear = react.useCallback(() => setHeldPastes([]), [setHeldPastes]);
46
- return { heldPastes, handlePaste, expand, remove, clear };
47
- }
48
9
  var PREVIEW_CHARS = 20;
49
- function withSeparators(n) {
50
- return String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
51
- }
52
- function endsOf(text) {
53
- if (text.length <= PREVIEW_CHARS * 2) return text;
54
- return `${text.slice(0, PREVIEW_CHARS)} \u2026 ${text.slice(-PREVIEW_CHARS)}`;
55
- }
56
10
  var Composer = react.forwardRef(
57
11
  function Composer2({
58
12
  value: controlledValue,
@@ -64,39 +18,69 @@ var Composer = react.forwardRef(
64
18
  disabled = false,
65
19
  className,
66
20
  pasteThreshold,
21
+ pastePlacement = "above",
22
+ pasteImages = false,
23
+ previewChars = PREVIEW_CHARS,
24
+ renderPastePreview,
25
+ classNames,
67
26
  heldPastes: controlledHeldPastes,
68
- onHeldPastesChange
27
+ onHeldPastesChange,
28
+ heldImages: controlledHeldImages,
29
+ onHeldImagesChange
69
30
  }, ref) {
31
+ const inline = pastePlacement === "inline";
70
32
  const [value, setValue] = chunkSNHU2AI4_cjs.useControllableState(
71
33
  controlledValue,
72
34
  defaultValue,
73
35
  onChange
74
36
  );
75
- const pills = usePastePills({
76
- threshold: pasteThreshold,
37
+ const textareaRef = react.useRef(null);
38
+ const editorRef = react.useRef(null);
39
+ const paste = chunk6TZPM43Q_cjs.useInlinePaste({
40
+ pasteThreshold,
41
+ pasteImages,
42
+ previewChars,
43
+ renderPastePreview,
44
+ classNames,
45
+ disabled,
77
46
  heldPastes: controlledHeldPastes,
78
- onHeldPastesChange
47
+ onHeldPastesChange,
48
+ heldImages: controlledHeldImages,
49
+ onHeldImagesChange,
50
+ editorRef
79
51
  });
80
- const heldPastes = pills.heldPastes;
81
- const textareaRef = react.useRef(null);
52
+ const pills = paste.pills;
53
+ const heldPastes = paste.heldPastes;
82
54
  const handlePaste = react.useCallback(
83
55
  (e) => {
84
56
  pills.handlePaste(e);
85
57
  },
86
58
  [pills]
87
59
  );
88
- const composeOutgoing = react.useCallback(
89
- () => [value, ...heldPastes.map((p) => p.text)].filter(Boolean).join("\n\n"),
90
- [value, heldPastes]
60
+ const handleInlineChange = react.useCallback(
61
+ (next) => {
62
+ setValue(next);
63
+ paste.prune(next);
64
+ },
65
+ [setValue, paste]
91
66
  );
92
- const hasContent = value.trim().length > 0 || heldPastes.length > 0;
67
+ const composeOutgoing = react.useCallback(() => {
68
+ if (inline) return paste.expand(value);
69
+ return [value, ...heldPastes.map((p) => p.text)].filter(Boolean).join("\n\n");
70
+ }, [inline, value, heldPastes, paste]);
71
+ const hasContent = value.trim().length > 0 || !inline && heldPastes.length > 0;
72
+ const focusInput = react.useCallback(() => {
73
+ if (inline) editorRef.current?.focus();
74
+ else textareaRef.current?.focus();
75
+ }, [inline]);
93
76
  const handleSubmit = react.useCallback(() => {
94
77
  if (!hasContent || disabled) return;
95
- onSubmit?.(composeOutgoing());
78
+ const images = inline ? paste.imagesIn(value) : [];
79
+ onSubmit?.(composeOutgoing(), { images });
96
80
  setValue("");
97
- pills.clear();
98
- textareaRef.current?.focus();
99
- }, [hasContent, disabled, onSubmit, composeOutgoing, setValue, pills]);
81
+ paste.clear();
82
+ focusInput();
83
+ }, [hasContent, disabled, value, inline, paste, onSubmit, composeOutgoing, setValue, focusInput]);
100
84
  const handleKeyDown = (e) => {
101
85
  if (e.key === "Enter" && !e.shiftKey) {
102
86
  e.preventDefault();
@@ -104,8 +88,8 @@ var Composer = react.forwardRef(
104
88
  }
105
89
  };
106
90
  const insertPaste = react.useCallback(
107
- (paste) => {
108
- const text = pills.expand(paste.id);
91
+ (held) => {
92
+ const text = pills.expand(held.id);
109
93
  if (text === void 0) return;
110
94
  setValue((current) => current ? `${current}
111
95
 
@@ -125,12 +109,12 @@ ${text}` : text);
125
109
  className
126
110
  ),
127
111
  children: [
128
- heldPastes.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
112
+ !inline && heldPastes.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
129
113
  "div",
130
114
  {
131
115
  "data-react-fancy-composer-paste-pills": "",
132
116
  className: "flex flex-wrap gap-1.5 px-3 pt-3",
133
- children: heldPastes.map((paste) => (
117
+ children: heldPastes.map((paste2) => (
134
118
  // `group` + `group-hover` rather than hover state: the preview is
135
119
  // presentation, and a useState for it would be one more thing an
136
120
  // agent could desynchronise.
@@ -139,15 +123,19 @@ ${text}` : text);
139
123
  "button",
140
124
  {
141
125
  type: "button",
142
- "data-react-fancy-composer-paste-pill": paste.id,
143
- onClick: () => insertPaste(paste),
126
+ "data-react-fancy-composer-paste-pill": paste2.id,
127
+ onClick: () => insertPaste(paste2),
144
128
  disabled,
145
- "aria-label": `Insert this pasted text, ${withSeparators(paste.text.length)} characters`,
146
- "aria-describedby": `${paste.id}-preview`,
147
- className: "inline-flex items-center gap-1.5 rounded-full border border-zinc-200 bg-zinc-50 py-1 pl-2.5 pr-7 text-xs text-zinc-700 transition-colors hover:bg-zinc-100 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-200 dark:hover:bg-zinc-700",
129
+ "aria-label": `Insert this pasted text, ${chunk6TZPM43Q_cjs.withSeparators(paste2.text.length)} characters`,
130
+ "aria-describedby": `${paste2.id}-preview`,
131
+ className: chunkZU5Q77OT_cjs.cn(
132
+ "inline-flex items-center gap-1.5 rounded-full border border-zinc-200 bg-zinc-50 py-1 pl-2.5 pr-7 text-xs text-zinc-700 transition-colors hover:bg-zinc-100 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-200 dark:hover:bg-zinc-700",
133
+ classNames?.pill,
134
+ classNames?.textPill
135
+ ),
148
136
  children: /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
149
137
  "Pasted text \xB7 ",
150
- withSeparators(paste.text.length),
138
+ chunk6TZPM43Q_cjs.withSeparators(paste2.text.length),
151
139
  " characters"
152
140
  ] })
153
141
  }
@@ -156,29 +144,52 @@ ${text}` : text);
156
144
  "button",
157
145
  {
158
146
  type: "button",
159
- "data-react-fancy-composer-paste-pill-remove": paste.id,
160
- onClick: () => pills.remove(paste.id),
147
+ "data-react-fancy-composer-paste-pill-remove": paste2.id,
148
+ onClick: () => pills.remove(paste2.id),
161
149
  disabled,
162
150
  "aria-label": "Discard this pasted text",
163
- className: "absolute right-1 top-1/2 -translate-y-1/2 rounded-full px-1 text-xs text-zinc-400 transition-colors hover:text-zinc-700 dark:hover:text-zinc-100",
151
+ className: chunkZU5Q77OT_cjs.cn(
152
+ "absolute right-1 top-1/2 -translate-y-1/2 rounded-full px-1 text-xs text-zinc-400 transition-colors hover:text-zinc-700 dark:hover:text-zinc-100",
153
+ classNames?.remove
154
+ ),
164
155
  children: "\xD7"
165
156
  }
166
157
  ),
167
158
  /* @__PURE__ */ jsxRuntime.jsx(
168
159
  "span",
169
160
  {
170
- id: `${paste.id}-preview`,
171
- "data-react-fancy-composer-paste-pill-preview": paste.id,
161
+ id: `${paste2.id}-preview`,
162
+ "data-react-fancy-composer-paste-pill-preview": paste2.id,
172
163
  role: "tooltip",
173
- className: "pointer-events-none absolute bottom-full left-0 z-10 mb-1 hidden max-w-xs whitespace-pre-wrap break-all rounded-md bg-zinc-900 px-2 py-1 text-xs text-white group-hover:block dark:bg-zinc-100 dark:text-zinc-900",
174
- children: endsOf(paste.text)
164
+ className: chunkZU5Q77OT_cjs.cn(
165
+ "pointer-events-none absolute bottom-full left-0 z-10 mb-1 hidden max-w-xs whitespace-pre-wrap break-all rounded-md bg-zinc-900 px-2 py-1 text-xs text-white group-hover:block dark:bg-zinc-100 dark:text-zinc-900",
166
+ classNames?.preview
167
+ ),
168
+ children: renderPastePreview?.({ kind: "text", paste: paste2 }) ?? chunk6TZPM43Q_cjs.endsOf(paste2.text, previewChars)
175
169
  }
176
170
  )
177
- ] }, paste.id)
171
+ ] }, paste2.id)
178
172
  ))
179
173
  }
180
174
  ),
181
- /* @__PURE__ */ jsxRuntime.jsx(
175
+ inline ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
176
+ /* @__PURE__ */ jsxRuntime.jsx(
177
+ chunk6TZPM43Q_cjs.InlinePasteEditor,
178
+ {
179
+ ref: editorRef,
180
+ value,
181
+ known: paste.known,
182
+ onChange: handleInlineChange,
183
+ onSubmit: handleSubmit,
184
+ onPaste: paste.decidePaste,
185
+ onHostsChange: paste.onHostsChange,
186
+ placeholder,
187
+ disabled,
188
+ className: classNames?.input
189
+ }
190
+ ),
191
+ paste.portals
192
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
182
193
  "textarea",
183
194
  {
184
195
  ref: textareaRef,
@@ -189,7 +200,10 @@ ${text}` : text);
189
200
  placeholder,
190
201
  disabled,
191
202
  rows: 3,
192
- className: "w-full resize-none bg-transparent px-4 pt-3 text-sm outline-none placeholder:text-zinc-400"
203
+ className: chunkZU5Q77OT_cjs.cn(
204
+ "w-full resize-none bg-transparent px-4 pt-3 text-sm outline-none placeholder:text-zinc-400",
205
+ classNames?.input
206
+ )
193
207
  }
194
208
  ),
195
209
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between border-t border-zinc-100 px-3 py-2 dark:border-zinc-800", children: [
@@ -213,6 +227,5 @@ ${text}` : text);
213
227
  Composer.displayName = "Composer";
214
228
 
215
229
  exports.Composer = Composer;
216
- exports.usePastePills = usePastePills;
217
- //# sourceMappingURL=chunk-23FTDEGR.cjs.map
218
- //# sourceMappingURL=chunk-23FTDEGR.cjs.map
230
+ //# sourceMappingURL=chunk-BZOU7VJQ.cjs.map
231
+ //# sourceMappingURL=chunk-BZOU7VJQ.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/Composer/Composer.tsx"],"names":["forwardRef","Composer","useControllableState","useRef","useInlinePaste","useCallback","jsxs","cn","jsx","paste","withSeparators","endsOf","Fragment","InlinePasteEditor"],"mappings":"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","file":"chunk-BZOU7VJQ.cjs","sourcesContent":["import { forwardRef, useCallback, useRef } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useControllableState } from \"../../hooks/use-controllable-state\";\nimport type { HeldPaste } from \"../../hooks/use-paste-pills\";\nimport { endsOf, withSeparators } from \"./InlinePill\";\nimport { InlinePasteEditor, type InlinePasteEditorHandle } from \"./InlinePasteEditor\";\nimport { useInlinePaste } from \"./use-inline-paste\";\nimport type { ComposerProps } from \"./Composer.types\";\n\n/** Characters of a held paste shown at each end of the hover preview, unless `previewChars` says otherwise. */\nconst PREVIEW_CHARS = 20;\n\nexport const Composer = forwardRef<HTMLDivElement, ComposerProps>(\n function Composer(\n {\n value: controlledValue,\n defaultValue = \"\",\n onChange,\n onSubmit,\n placeholder = \"Type a message...\",\n actions,\n disabled = false,\n className,\n pasteThreshold,\n pastePlacement = \"above\",\n pasteImages = false,\n previewChars = PREVIEW_CHARS,\n renderPastePreview,\n classNames,\n heldPastes: controlledHeldPastes,\n onHeldPastesChange,\n heldImages: controlledHeldImages,\n onHeldImagesChange,\n },\n ref,\n ) {\n const inline = pastePlacement === \"inline\";\n const [value, setValue] = useControllableState(\n controlledValue,\n defaultValue,\n onChange,\n );\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const editorRef = useRef<InlinePasteEditorHandle>(null);\n /*\n * The holding logic lives in `usePastePills`, wrapped by `useInlinePaste` for\n * the inline placement — which `PromptInput` shares, so the two components\n * cannot disagree about what a pill means. The rule that must not drift is\n * the one below: a send with pills still closed carries the text.\n */\n const paste = useInlinePaste({\n pasteThreshold,\n pasteImages,\n previewChars,\n renderPastePreview,\n classNames,\n disabled,\n heldPastes: controlledHeldPastes,\n onHeldPastesChange,\n heldImages: controlledHeldImages,\n onHeldImagesChange,\n editorRef,\n });\n const pills = paste.pills;\n const heldPastes = paste.heldPastes;\n\n const handlePaste = useCallback(\n (e: React.ClipboardEvent<HTMLTextAreaElement>) => {\n // Composable by design, so this reads as a question rather than a handover.\n // Nothing else here wants the paste, so the answer is simply ignored.\n pills.handlePaste(e);\n },\n [pills],\n );\n\n const handleInlineChange = useCallback(\n (next: string) => {\n setValue(next);\n paste.prune(next);\n },\n [setValue, paste],\n );\n\n /** Everything the person believes they are sending, in the order they built it. */\n const composeOutgoing = useCallback(() => {\n if (inline) return paste.expand(value);\n\n return [value, ...heldPastes.map((p) => p.text)].filter(Boolean).join(\"\\n\\n\");\n }, [inline, value, heldPastes, paste]);\n\n const hasContent = value.trim().length > 0 || (!inline && heldPastes.length > 0);\n\n const focusInput = useCallback(() => {\n if (inline) editorRef.current?.focus();\n else textareaRef.current?.focus();\n }, [inline]);\n\n const handleSubmit = useCallback(() => {\n if (!hasContent || disabled) return;\n\n /*\n * THE DANGEROUS STATE, and the reason this feature needed a spec rather than\n * a guess. A pill reads as \"your paste is attached\" — so a send that drops it\n * means asking a question about a document without the document, and nobody\n * can tell: the sender believes it went, the receiver sees a question about\n * nothing.\n *\n * Above the input, held pastes go out in arrival order after what was typed,\n * because people type the question BEFORE pasting the thing it is about.\n * Inline, every pill goes out exactly where it sits.\n */\n const images = inline ? paste.imagesIn(value) : [];\n\n onSubmit?.(composeOutgoing(), { images });\n setValue(\"\");\n paste.clear();\n focusInput();\n }, [hasContent, disabled, value, inline, paste, onSubmit, composeOutgoing, setValue, focusInput]);\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSubmit();\n }\n };\n\n /** Above the input: click a pill to dump it in, APPENDED to what is already typed. */\n const insertPaste = useCallback(\n (held: HeldPaste) => {\n // `expand` removes it and hands back the text; inserting is this\n // component's job because the hook owns no DOM.\n const text = pills.expand(held.id);\n\n if (text === undefined) return;\n\n setValue((current) => (current ? `${current}\\n\\n${text}` : text));\n textareaRef.current?.focus();\n },\n [pills, setValue],\n );\n\n return (\n <div\n data-react-fancy-composer=\"\"\n ref={ref}\n className={cn(\n \"rounded-xl border border-zinc-200 bg-white dark:border-zinc-700 dark:bg-zinc-900\",\n disabled && \"opacity-50\",\n className,\n )}\n >\n {!inline && heldPastes.length > 0 && (\n <div\n data-react-fancy-composer-paste-pills=\"\"\n className=\"flex flex-wrap gap-1.5 px-3 pt-3\"\n >\n {heldPastes.map((paste) => (\n // `group` + `group-hover` rather than hover state: the preview is\n // presentation, and a useState for it would be one more thing an\n // agent could desynchronise.\n <span key={paste.id} className=\"group relative inline-flex\">\n <button\n type=\"button\"\n data-react-fancy-composer-paste-pill={paste.id}\n onClick={() => insertPaste(paste)}\n disabled={disabled}\n // No `title`. A native tooltip plus the hover preview below\n // renders TWO tooltips on the same hover, at different delays.\n // The label says what clicking does; the preview says what the\n // text is, and it is linked rather than merely adjacent so a\n // screen reader reaches it too.\n aria-label={`Insert this pasted text, ${withSeparators(paste.text.length)} characters`}\n aria-describedby={`${paste.id}-preview`}\n // `pr-7` leaves room for the absolutely-positioned × that sits\n // over this button's right edge. With a smaller right padding the\n // × lands on top of the label.\n className={cn(\n \"inline-flex items-center gap-1.5 rounded-full border border-zinc-200 bg-zinc-50 py-1 pl-2.5 pr-7 text-xs text-zinc-700 transition-colors hover:bg-zinc-100 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-200 dark:hover:bg-zinc-700\",\n classNames?.pill,\n classNames?.textPill,\n )}\n >\n <span>\n Pasted text · {withSeparators(paste.text.length)} characters\n </span>\n </button>\n\n <button\n type=\"button\"\n data-react-fancy-composer-paste-pill-remove={paste.id}\n onClick={() => pills.remove(paste.id)}\n disabled={disabled}\n aria-label=\"Discard this pasted text\"\n className={cn(\n \"absolute right-1 top-1/2 -translate-y-1/2 rounded-full px-1 text-xs text-zinc-400 transition-colors hover:text-zinc-700 dark:hover:text-zinc-100\",\n classNames?.remove,\n )}\n >\n ×\n </button>\n\n <span\n id={`${paste.id}-preview`}\n data-react-fancy-composer-paste-pill-preview={paste.id}\n role=\"tooltip\"\n className={cn(\n \"pointer-events-none absolute bottom-full left-0 z-10 mb-1 hidden max-w-xs whitespace-pre-wrap break-all rounded-md bg-zinc-900 px-2 py-1 text-xs text-white group-hover:block dark:bg-zinc-100 dark:text-zinc-900\",\n classNames?.preview,\n )}\n >\n {renderPastePreview?.({ kind: \"text\", paste }) ??\n endsOf(paste.text, previewChars)}\n </span>\n </span>\n ))}\n </div>\n )}\n\n {inline ? (\n <>\n <InlinePasteEditor\n ref={editorRef}\n value={value}\n known={paste.known}\n onChange={handleInlineChange}\n onSubmit={handleSubmit}\n onPaste={paste.decidePaste}\n onHostsChange={paste.onHostsChange}\n placeholder={placeholder}\n disabled={disabled}\n className={classNames?.input}\n />\n {paste.portals}\n </>\n ) : (\n <textarea\n ref={textareaRef}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={handleKeyDown}\n onPaste={handlePaste}\n placeholder={placeholder}\n disabled={disabled}\n rows={3}\n className={cn(\n \"w-full resize-none bg-transparent px-4 pt-3 text-sm outline-none placeholder:text-zinc-400\",\n classNames?.input,\n )}\n />\n )}\n <div className=\"flex items-center justify-between border-t border-zinc-100 px-3 py-2 dark:border-zinc-800\">\n <div className=\"flex items-center gap-1\">{actions}</div>\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={disabled || !hasContent}\n className=\"rounded-lg bg-zinc-900 px-3 py-1.5 text-sm font-medium text-white transition-colors hover:bg-zinc-800 disabled:opacity-50 dark:bg-white dark:text-zinc-900 dark:hover:bg-zinc-100\"\n >\n Send\n </button>\n </div>\n </div>\n );\n },\n);\n\nComposer.displayName = \"Composer\";\n"]}
@@ -48,7 +48,10 @@ var Tooltip = forwardRef(
48
48
  "div",
49
49
  {
50
50
  className: cn(
51
- "absolute h-2 w-2 rotate-45 bg-zinc-900 dark:bg-zinc-700",
51
+ // `bg-inherit`, not a colour of its own: a `className` that
52
+ // restyles the bubble would otherwise leave a dark arrow
53
+ // pointing out of a light one.
54
+ "absolute h-2 w-2 rotate-45 bg-inherit",
52
55
  position.placement.startsWith("top") && "bottom-[-4px] left-1/2 -translate-x-1/2",
53
56
  position.placement.startsWith("bottom") && "top-[-4px] left-1/2 -translate-x-1/2",
54
57
  position.placement.startsWith("left") && "right-[-4px] top-1/2 -translate-y-1/2",
@@ -65,5 +68,5 @@ var Tooltip = forwardRef(
65
68
  Tooltip.displayName = "Tooltip";
66
69
 
67
70
  export { Tooltip };
68
- //# sourceMappingURL=chunk-35EN5AYE.js.map
69
- //# sourceMappingURL=chunk-35EN5AYE.js.map
71
+ //# sourceMappingURL=chunk-CF5KRDN4.js.map
72
+ //# sourceMappingURL=chunk-CF5KRDN4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/Tooltip/Tooltip.tsx"],"names":["Tooltip"],"mappings":";;;;;;AAaO,IAAM,OAAA,GAAU,UAAA;AAAA,EACrB,SAASA,QAAAA,CACP,EAAE,QAAA,EAAU,OAAA,EAAS,SAAA,GAAY,KAAA,EAAO,KAAA,GAAQ,GAAA,EAAK,MAAA,GAAS,CAAA,EAAG,SAAA,IACjE,IAAA,EACA;AACA,IAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,KAAK,CAAA;AACtC,IAAA,MAAM,SAAA,GAAY,OAAoB,IAAI,CAAA;AAC1C,IAAA,MAAM,WAAA,GAAc,OAAuB,IAAI,CAAA;AAC/C,IAAA,MAAM,UAAA,GAAa,OAAsC,MAAS,CAAA;AAElE,IAAA,MAAM,QAAA,GAAW,mBAAA,CAAoB,SAAA,EAAW,WAAA,EAAa;AAAA,MAC3D,SAAA;AAAA,MACA,MAAA;AAAA,MACA,OAAA,EAAS;AAAA,KACV,CAAA;AAED,IAAA,MAAM,IAAA,GAAO,YAAY,MAAM;AAC7B,MAAA,UAAA,CAAW,UAAU,UAAA,CAAW,MAAM,OAAA,CAAQ,IAAI,GAAG,KAAK,CAAA;AAAA,IAC5D,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AAEV,IAAA,MAAM,IAAA,GAAO,YAAY,MAAM;AAC7B,MAAA,YAAA,CAAa,WAAW,OAAO,CAAA;AAC/B,MAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,IACf,CAAA,EAAG,EAAE,CAAA;AAEL,IAAA,MAAM,OAAA,GAAU,aAAa,QAAA,EAAmD;AAAA,MAC9E,GAAA,EAAK,SAAA;AAAA,MACL,YAAA,EAAc,IAAA;AAAA,MACd,YAAA,EAAc,IAAA;AAAA,MACd,OAAA,EAAS,IAAA;AAAA,MACT,MAAA,EAAQ;AAAA,KACT,CAAA;AAED,IAAA,uBACE,IAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA;AAAA,MAAA,OAAA;AAAA,MACA,IAAA,wBACE,MAAA,EAAA,EACC,QAAA,kBAAA,IAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,GAAA,EAAK,WAAA;AAAA,UACL,0BAAA,EAAyB,EAAA;AAAA,UACzB,IAAA,EAAK,SAAA;AAAA,UACL,SAAA,EAAW,EAAA;AAAA,YACT,2JAAA;AAAA,YACA;AAAA,WACF;AAAA,UACA,OAAO,EAAE,IAAA,EAAM,SAAS,CAAA,EAAG,GAAA,EAAK,SAAS,CAAA,EAAE;AAAA,UAE1C,QAAA,EAAA;AAAA,YAAA,OAAA;AAAA,4BACD,GAAA;AAAA,cAAC,KAAA;AAAA,cAAA;AAAA,gBACC,SAAA,EAAW,EAAA;AAAA;AAAA;AAAA;AAAA,kBAIT,uCAAA;AAAA,kBACA,QAAA,CAAS,SAAA,CAAU,UAAA,CAAW,KAAK,CAAA,IACjC,yCAAA;AAAA,kBACF,QAAA,CAAS,SAAA,CAAU,UAAA,CAAW,QAAQ,CAAA,IACpC,sCAAA;AAAA,kBACF,QAAA,CAAS,SAAA,CAAU,UAAA,CAAW,MAAM,CAAA,IAClC,uCAAA;AAAA,kBACF,QAAA,CAAS,SAAA,CAAU,UAAA,CAAW,OAAO,CAAA,IACnC;AAAA;AACJ;AAAA;AACF;AAAA;AAAA,OACF,EACF;AAAA,KAAA,EAEJ,CAAA;AAAA,EAEJ;AACF;AAEA,OAAA,CAAQ,WAAA,GAAc,SAAA","file":"chunk-CF5KRDN4.js","sourcesContent":["import {\n cloneElement,\n forwardRef,\n useCallback,\n useRef,\n useState,\n type ReactElement,\n} from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Portal } from \"../Portal\";\nimport { useFloatingPosition } from \"../../hooks/use-floating-position\";\nimport type { TooltipProps } from \"./Tooltip.types\";\n\nexport const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(\n function Tooltip(\n { children, content, placement = \"top\", delay = 200, offset = 8, className },\n _ref,\n ) {\n const [open, setOpen] = useState(false);\n const anchorRef = useRef<HTMLElement>(null);\n const floatingRef = useRef<HTMLDivElement>(null);\n const timeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n const position = useFloatingPosition(anchorRef, floatingRef, {\n placement,\n offset,\n enabled: open,\n });\n\n const show = useCallback(() => {\n timeoutRef.current = setTimeout(() => setOpen(true), delay);\n }, [delay]);\n\n const hide = useCallback(() => {\n clearTimeout(timeoutRef.current);\n setOpen(false);\n }, []);\n\n const trigger = cloneElement(children as ReactElement<Record<string, unknown>>, {\n ref: anchorRef,\n onMouseEnter: show,\n onMouseLeave: hide,\n onFocus: show,\n onBlur: hide,\n });\n\n return (\n <>\n {trigger}\n {open && (\n <Portal>\n <div\n ref={floatingRef}\n data-react-fancy-tooltip=\"\"\n role=\"tooltip\"\n className={cn(\n \"fancy-fade-in pointer-events-none fixed z-50 max-w-xs rounded-lg bg-zinc-900 px-3 py-1.5 text-sm text-white shadow-lg dark:bg-zinc-700 dark:text-zinc-100\",\n className,\n )}\n style={{ left: position.x, top: position.y }}\n >\n {content}\n <div\n className={cn(\n // `bg-inherit`, not a colour of its own: a `className` that\n // restyles the bubble would otherwise leave a dark arrow\n // pointing out of a light one.\n \"absolute h-2 w-2 rotate-45 bg-inherit\",\n position.placement.startsWith(\"top\") &&\n \"bottom-[-4px] left-1/2 -translate-x-1/2\",\n position.placement.startsWith(\"bottom\") &&\n \"top-[-4px] left-1/2 -translate-x-1/2\",\n position.placement.startsWith(\"left\") &&\n \"right-[-4px] top-1/2 -translate-y-1/2\",\n position.placement.startsWith(\"right\") &&\n \"left-[-4px] top-1/2 -translate-y-1/2\",\n )}\n />\n </div>\n </Portal>\n )}\n </>\n );\n },\n);\n\nTooltip.displayName = \"Tooltip\";\n"]}
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkISPCXIJZ_cjs = require('./chunk-ISPCXIJZ.cjs');
3
+ var chunk6TZPM43Q_cjs = require('./chunk-6TZPM43Q.cjs');
4
+ var chunkX7H75WVP_cjs = require('./chunk-X7H75WVP.cjs');
4
5
  var chunkRMJGF7MN_cjs = require('./chunk-RMJGF7MN.cjs');
5
6
  var chunkQKFOJKVE_cjs = require('./chunk-QKFOJKVE.cjs');
6
7
  var chunkZU5Q77OT_cjs = require('./chunk-ZU5Q77OT.cjs');
@@ -46,9 +47,31 @@ function PromptInput({
46
47
  maxHeight = 280,
47
48
  aboveInput,
48
49
  className,
50
+ pasteThreshold,
51
+ pasteImages = false,
52
+ previewChars = 20,
53
+ renderPastePreview,
54
+ pasteClassNames,
55
+ attachButton = "label",
56
+ sendButton = "label",
57
+ usedTokens,
58
+ meter = "always",
59
+ meterShowAt = 0.75,
60
+ meterWarnAt = 0.9,
49
61
  ...rest
50
62
  }) {
51
63
  const [text, setText] = react.useState("");
64
+ const inline = pasteThreshold !== void 0 || pasteImages;
65
+ const editorRef = react.useRef(null);
66
+ const paste = chunk6TZPM43Q_cjs.useInlinePaste({
67
+ pasteThreshold,
68
+ pasteImages,
69
+ previewChars,
70
+ renderPastePreview,
71
+ classNames: pasteClassNames,
72
+ disabled: false,
73
+ editorRef
74
+ });
52
75
  const [attachments, setAttachments] = react.useState([]);
53
76
  const [picker, setPicker] = react.useState(null);
54
77
  const taRef = react.useRef(null);
@@ -62,12 +85,14 @@ function PromptInput({
62
85
  }, [platform]);
63
86
  const modKey = modifierKeyLabel(platform ?? detected);
64
87
  const resolvedPlaceholder = placeholder ?? `Ask anything. Type / for commands, @ for mentions. ${modKey}+Enter to send.`;
65
- const tokens = react.useMemo(
66
- () => Math.ceil(text.length / Math.max(1, charsPerToken)),
67
- [text, charsPerToken]
88
+ const draftTokens = react.useMemo(
89
+ () => Math.ceil((inline ? paste.expand(text) : text).length / Math.max(1, charsPerToken)),
90
+ [text, inline, paste, charsPerToken]
68
91
  );
92
+ const tokens = (usedTokens ?? 0) + draftTokens;
69
93
  const ratio = Math.min(1, tokens / budgetTokens);
70
- const meterColor = ratio < 0.6 ? "#10b981" : ratio < 0.85 ? "#f59e0b" : "#ef4444";
94
+ const meterLevel = meter === "hidden" ? null : meter === "near-limit" ? ratio < meterShowAt ? null : ratio >= meterWarnAt ? "warn" : "muted" : ratio < 0.6 ? "ok" : ratio < 0.85 ? "caution" : "warn";
95
+ const meterColor = meterLevel === "ok" ? "#10b981" : meterLevel === "caution" ? "#f59e0b" : meterLevel === "warn" ? "#ef4444" : "#a1a1aa";
71
96
  const filteredCmds = react.useMemo(
72
97
  () => picker?.kind === "cmd" ? commands.filter(
73
98
  (c) => c.name.slice(1).toLowerCase().startsWith(picker.query.toLowerCase())
@@ -121,6 +146,10 @@ function PromptInput({
121
146
  const next = before + insert + after;
122
147
  setText(next);
123
148
  setPicker(null);
149
+ if (inline) {
150
+ editorRef.current?.setValue(next, before.length + insert.length);
151
+ return;
152
+ }
124
153
  requestAnimationFrame(() => {
125
154
  const ta = taRef.current;
126
155
  if (!ta) return;
@@ -131,7 +160,19 @@ function PromptInput({
131
160
  };
132
161
  const submit = () => {
133
162
  if (!text.trim() && attachments.length === 0) return;
134
- onSubmit(text, attachments);
163
+ if (inline) {
164
+ const pastedImages = paste.imagesIn(text).map((image) => ({
165
+ id: image.id,
166
+ name: image.file.name,
167
+ bytes: image.file.size,
168
+ file: image.file,
169
+ type: image.file.type
170
+ }));
171
+ onSubmit(paste.expand(text), [...attachments, ...pastedImages]);
172
+ paste.clear();
173
+ } else {
174
+ onSubmit(text, attachments);
175
+ }
135
176
  setText("");
136
177
  setAttachments([]);
137
178
  setPicker(null);
@@ -233,7 +274,34 @@ function PromptInput({
233
274
  a.id
234
275
  )) }),
235
276
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
236
- /* @__PURE__ */ jsxRuntime.jsx(
277
+ inline ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
278
+ /* @__PURE__ */ jsxRuntime.jsx(
279
+ chunk6TZPM43Q_cjs.InlinePasteEditor,
280
+ {
281
+ ref: editorRef,
282
+ value: text,
283
+ known: paste.known,
284
+ onChange: (next, caret) => {
285
+ updateText(next, caret);
286
+ paste.prune(next);
287
+ },
288
+ onSubmit: submit,
289
+ submitKey: "mod-enter",
290
+ onKeyDown,
291
+ onPaste: paste.decidePaste,
292
+ onHostsChange: paste.onHostsChange,
293
+ placeholder: resolvedPlaceholder,
294
+ disabled: false,
295
+ maxHeight,
296
+ placeholderClassName: "left-3 top-2.5 text-[14px] leading-relaxed",
297
+ className: chunkZU5Q77OT_cjs.cn(
298
+ "block min-h-[5.5rem] px-3 py-2.5 text-[14px] leading-relaxed",
299
+ pasteClassNames?.input
300
+ )
301
+ }
302
+ ),
303
+ paste.portals
304
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
237
305
  "textarea",
238
306
  {
239
307
  ref: taRef,
@@ -302,15 +370,17 @@ function PromptInput({
302
370
  ] })
303
371
  ] }),
304
372
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 border-t border-zinc-200 bg-zinc-50/60 px-3 py-2 dark:border-zinc-800 dark:bg-zinc-900/40", children: [
305
- /* @__PURE__ */ jsxRuntime.jsx(chunkISPCXIJZ_cjs.Tooltip, { content: "Drop files here, or click", children: /* @__PURE__ */ jsxRuntime.jsx(
373
+ /* @__PURE__ */ jsxRuntime.jsx(chunkX7H75WVP_cjs.Tooltip, { content: attachButton === "icon" ? "Attach files \u2014 or drop them here" : "Drop files here, or click", children: /* @__PURE__ */ jsxRuntime.jsx(
306
374
  chunkRMJGF7MN_cjs.Button,
307
375
  {
308
376
  variant: "ghost",
309
377
  size: "sm",
310
378
  icon: "paperclip",
311
379
  className: "shrink-0",
380
+ "data-react-fancy-prompt-input-attach": "",
381
+ "aria-label": attachButton === "icon" ? "Attach files" : void 0,
312
382
  onClick: () => fileRef.current?.click(),
313
- children: "attach"
383
+ children: attachButton === "icon" ? null : "attach"
314
384
  }
315
385
  ) }),
316
386
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -326,22 +396,30 @@ function PromptInput({
326
396
  }
327
397
  }
328
398
  ),
329
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-2 flex min-w-0 items-center gap-1.5 overflow-hidden", children: [
330
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1.5 w-24 shrink overflow-hidden rounded-full bg-zinc-200 dark:bg-zinc-700", children: /* @__PURE__ */ jsxRuntime.jsx(
331
- "div",
332
- {
333
- className: "h-full rounded-full transition-all",
334
- style: { width: `${ratio * 100}%`, backgroundColor: meterColor }
335
- }
336
- ) }),
337
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono text-[11px]", style: { color: meterColor }, children: [
338
- fmtTokens(tokens),
339
- " / ",
340
- fmtTokens(budgetTokens)
341
- ] })
342
- ] }),
399
+ meterLevel !== null && /* @__PURE__ */ jsxRuntime.jsxs(
400
+ "div",
401
+ {
402
+ "data-react-fancy-prompt-input-meter": "",
403
+ "data-level": meterLevel,
404
+ className: "ml-2 flex min-w-0 items-center gap-1.5 overflow-hidden",
405
+ children: [
406
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1.5 w-24 shrink overflow-hidden rounded-full bg-zinc-200 dark:bg-zinc-700", children: /* @__PURE__ */ jsxRuntime.jsx(
407
+ "div",
408
+ {
409
+ className: "h-full rounded-full transition-all",
410
+ style: { width: `${ratio * 100}%`, backgroundColor: meterColor }
411
+ }
412
+ ) }),
413
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono text-[11px]", style: { color: meterColor }, children: [
414
+ fmtTokens(tokens),
415
+ " / ",
416
+ fmtTokens(budgetTokens)
417
+ ] })
418
+ ]
419
+ }
420
+ ),
343
421
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-auto flex shrink-0 items-center gap-2", children: [
344
- showHint && /* @__PURE__ */ jsxRuntime.jsxs(
422
+ showHint && sendButton !== "icon" && /* @__PURE__ */ jsxRuntime.jsxs(
345
423
  "span",
346
424
  {
347
425
  className: "hidden text-[10px] text-zinc-500 sm:inline",
@@ -357,13 +435,25 @@ function PromptInput({
357
435
  ]
358
436
  }
359
437
  ),
360
- /* @__PURE__ */ jsxRuntime.jsx(
438
+ sendButton === "icon" ? /* @__PURE__ */ jsxRuntime.jsx(chunkX7H75WVP_cjs.Tooltip, { content: `Send \xB7 ${modKey}+Enter`, children: /* @__PURE__ */ jsxRuntime.jsx(
439
+ chunkRMJGF7MN_cjs.Button,
440
+ {
441
+ color: "violet",
442
+ size: "sm",
443
+ icon: "arrow-up",
444
+ className: "shrink-0",
445
+ "data-react-fancy-prompt-input-send": "",
446
+ "aria-label": "Send",
447
+ onClick: submit
448
+ }
449
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx(
361
450
  chunkRMJGF7MN_cjs.Button,
362
451
  {
363
452
  color: "violet",
364
453
  size: "sm",
365
454
  iconTrailing: "arrow-right",
366
455
  className: "shrink-0",
456
+ "data-react-fancy-prompt-input-send": "",
367
457
  onClick: submit,
368
458
  children: "send"
369
459
  }
@@ -388,5 +478,5 @@ exports.PromptInput = PromptInput;
388
478
  exports.browserPlatformHints = browserPlatformHints;
389
479
  exports.detectPlatform = detectPlatform;
390
480
  exports.modifierKeyLabel = modifierKeyLabel;
391
- //# sourceMappingURL=chunk-DNV7MUEE.cjs.map
392
- //# sourceMappingURL=chunk-DNV7MUEE.cjs.map
481
+ //# sourceMappingURL=chunk-FJ2GMQLC.cjs.map
482
+ //# sourceMappingURL=chunk-FJ2GMQLC.cjs.map