@copilotkit/react-textarea 0.17.0 → 0.19.0-alpha.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 (242) hide show
  1. package/.turbo/turbo-build.log +304 -190
  2. package/CHANGELOG.md +17 -0
  3. package/dist/chunk-2NURR2DX.mjs +47 -0
  4. package/dist/chunk-2NURR2DX.mjs.map +1 -0
  5. package/dist/chunk-3YJ63D5D.mjs +106 -0
  6. package/dist/chunk-3YJ63D5D.mjs.map +1 -0
  7. package/dist/chunk-4S5ZJH3I.mjs +18 -0
  8. package/dist/chunk-4S5ZJH3I.mjs.map +1 -0
  9. package/dist/chunk-4T72ROFJ.mjs +469 -0
  10. package/dist/chunk-4T72ROFJ.mjs.map +1 -0
  11. package/dist/chunk-55EGOC5T.mjs +87 -0
  12. package/dist/chunk-55EGOC5T.mjs.map +1 -0
  13. package/dist/{chunk-3A2CNIG5.mjs → chunk-5ARCOTW3.mjs} +8 -5
  14. package/dist/chunk-5ARCOTW3.mjs.map +1 -0
  15. package/dist/chunk-5EJ5XOGP.mjs +22 -0
  16. package/dist/chunk-5EJ5XOGP.mjs.map +1 -0
  17. package/dist/chunk-5FO6ISW4.mjs +3 -0
  18. package/dist/{chunk-JWN2VEE3.mjs → chunk-A2RRLD23.mjs} +13 -12
  19. package/dist/chunk-A2RRLD23.mjs.map +1 -0
  20. package/dist/chunk-ASPOPGV7.mjs +47 -0
  21. package/dist/chunk-ASPOPGV7.mjs.map +1 -0
  22. package/dist/chunk-CDB7HFCY.mjs +65 -0
  23. package/dist/chunk-CDB7HFCY.mjs.map +1 -0
  24. package/dist/chunk-CIFH63LP.mjs +107 -0
  25. package/dist/chunk-CIFH63LP.mjs.map +1 -0
  26. package/dist/{chunk-MFJNLKRC.mjs → chunk-D7SEV5PR.mjs} +4 -3
  27. package/dist/chunk-D7SEV5PR.mjs.map +1 -0
  28. package/dist/chunk-HAFHLU4N.mjs +55 -0
  29. package/dist/chunk-HAFHLU4N.mjs.map +1 -0
  30. package/dist/{chunk-3UQM3NLM.mjs → chunk-IXJ2HCOA.mjs} +42 -7
  31. package/dist/chunk-IXJ2HCOA.mjs.map +1 -0
  32. package/dist/{chunk-UW3ITU2Y.mjs → chunk-JAFCXEPU.mjs} +1 -1
  33. package/dist/chunk-JAFCXEPU.mjs.map +1 -0
  34. package/dist/chunk-L7VVZH4Q.mjs +3 -0
  35. package/dist/{chunk-V54GX4SO.mjs → chunk-MA4NHL3H.mjs} +69 -31
  36. package/dist/chunk-MA4NHL3H.mjs.map +1 -0
  37. package/dist/chunk-ND5PXTAW.mjs +17 -0
  38. package/dist/chunk-ND5PXTAW.mjs.map +1 -0
  39. package/dist/chunk-O5OWT5GE.mjs +114 -0
  40. package/dist/chunk-O5OWT5GE.mjs.map +1 -0
  41. package/dist/chunk-OD7ZMOVE.mjs +45 -0
  42. package/dist/chunk-OD7ZMOVE.mjs.map +1 -0
  43. package/dist/chunk-QL2GYGG5.mjs +19 -0
  44. package/dist/chunk-QL2GYGG5.mjs.map +1 -0
  45. package/dist/chunk-RQHOUUXQ.mjs +29 -0
  46. package/dist/chunk-RQHOUUXQ.mjs.map +1 -0
  47. package/dist/{chunk-HZGSG7ST.mjs → chunk-UHD44NC5.mjs} +10 -5
  48. package/dist/chunk-UHD44NC5.mjs.map +1 -0
  49. package/dist/chunk-VBIJPE3H.mjs +108 -0
  50. package/dist/chunk-VBIJPE3H.mjs.map +1 -0
  51. package/dist/chunk-VHIS7RTM.mjs +44 -0
  52. package/dist/chunk-VHIS7RTM.mjs.map +1 -0
  53. package/dist/chunk-XDT7BF3V.mjs +81 -0
  54. package/dist/chunk-XDT7BF3V.mjs.map +1 -0
  55. package/dist/chunk-XHUMROEY.mjs +91 -0
  56. package/dist/chunk-XHUMROEY.mjs.map +1 -0
  57. package/dist/{chunk-RKZRCIPE.mjs → chunk-YQU7WG7T.mjs} +3 -3
  58. package/dist/chunk-YTOPHPSG.mjs +45 -0
  59. package/dist/chunk-YTOPHPSG.mjs.map +1 -0
  60. package/dist/chunk-YW3REYX6.mjs +23 -0
  61. package/dist/chunk-YW3REYX6.mjs.map +1 -0
  62. package/dist/components/base-copilot-textarea/base-copilot-textarea.d.ts +3 -5
  63. package/dist/components/base-copilot-textarea/base-copilot-textarea.mjs +23 -9
  64. package/dist/components/base-copilot-textarea/track-cursor-moved-since-last-text-change.d.ts +6 -0
  65. package/dist/components/base-copilot-textarea/track-cursor-moved-since-last-text-change.mjs +5 -0
  66. package/dist/components/copilot-textarea/copilot-textarea.d.ts +13 -10
  67. package/dist/components/copilot-textarea/copilot-textarea.mjs +33 -14
  68. package/dist/components/hovering-toolbar/hovering-editor-provider.d.ts +13 -0
  69. package/dist/components/hovering-toolbar/hovering-editor-provider.mjs +4 -0
  70. package/dist/components/hovering-toolbar/hovering-toolbar-components.d.ts +18 -0
  71. package/dist/components/hovering-toolbar/hovering-toolbar-components.mjs +4 -0
  72. package/dist/components/hovering-toolbar/hovering-toolbar.d.ts +8 -0
  73. package/dist/components/hovering-toolbar/hovering-toolbar.mjs +17 -0
  74. package/dist/components/hovering-toolbar/hovering-toolbar.mjs.map +1 -0
  75. package/dist/components/hovering-toolbar/text-insertion-prompt-box/hovering-insertion-prompt-box.d.ts +12 -0
  76. package/dist/components/hovering-toolbar/text-insertion-prompt-box/hovering-insertion-prompt-box.mjs +12 -0
  77. package/dist/components/hovering-toolbar/text-insertion-prompt-box/hovering-insertion-prompt-box.mjs.map +1 -0
  78. package/dist/components/hovering-toolbar/text-insertion-prompt-box/index.d.ts +3 -0
  79. package/dist/components/hovering-toolbar/text-insertion-prompt-box/index.mjs +13 -0
  80. package/dist/components/hovering-toolbar/text-insertion-prompt-box/index.mjs.map +1 -0
  81. package/dist/components/hovering-toolbar/text-insertion-prompt-box/mode-pre-suggestion.d.ts +16 -0
  82. package/dist/components/hovering-toolbar/text-insertion-prompt-box/mode-pre-suggestion.mjs +5 -0
  83. package/dist/components/hovering-toolbar/text-insertion-prompt-box/mode-pre-suggestion.mjs.map +1 -0
  84. package/dist/components/hovering-toolbar/text-insertion-prompt-box/mode-suggestion-appearing.d.ts +37 -0
  85. package/dist/components/hovering-toolbar/text-insertion-prompt-box/mode-suggestion-appearing.mjs +10 -0
  86. package/dist/components/hovering-toolbar/text-insertion-prompt-box/mode-suggestion-appearing.mjs.map +1 -0
  87. package/dist/components/index.d.ts +9 -4
  88. package/dist/components/index.mjs +33 -14
  89. package/dist/components/manual-ui/chip-with-icon.d.ts +10 -0
  90. package/dist/components/manual-ui/chip-with-icon.mjs +25 -0
  91. package/dist/components/manual-ui/chip-with-icon.mjs.map +1 -0
  92. package/dist/components/source-search-box/source-search-box.d.ts +17 -0
  93. package/dist/components/source-search-box/source-search-box.mjs +10 -0
  94. package/dist/components/source-search-box/source-search-box.mjs.map +1 -0
  95. package/dist/components/ui/button.d.ts +14 -0
  96. package/dist/components/ui/button.mjs +5 -0
  97. package/dist/components/ui/button.mjs.map +1 -0
  98. package/dist/components/ui/card.d.ts +10 -0
  99. package/dist/components/ui/card.mjs +63 -0
  100. package/dist/components/ui/card.mjs.map +1 -0
  101. package/dist/components/ui/command.d.ts +48 -0
  102. package/dist/components/ui/command.mjs +6 -0
  103. package/dist/components/ui/command.mjs.map +1 -0
  104. package/dist/components/ui/dialog.d.ts +18 -0
  105. package/dist/components/ui/dialog.mjs +5 -0
  106. package/dist/components/ui/dialog.mjs.map +1 -0
  107. package/dist/components/ui/label.d.ts +8 -0
  108. package/dist/components/ui/label.mjs +5 -0
  109. package/dist/components/ui/label.mjs.map +1 -0
  110. package/dist/components/ui/separator.d.ts +6 -0
  111. package/dist/components/ui/separator.mjs +26 -0
  112. package/dist/components/ui/separator.mjs.map +1 -0
  113. package/dist/components/ui/textarea.d.ts +7 -0
  114. package/dist/components/ui/textarea.mjs +22 -0
  115. package/dist/components/ui/textarea.mjs.map +1 -0
  116. package/dist/hooks/base-copilot-textarea-implementation/use-autosuggestions.mjs +2 -2
  117. package/dist/hooks/base-copilot-textarea-implementation/use-populate-copilot-textarea-ref.d.ts +2 -2
  118. package/dist/hooks/base-copilot-textarea-implementation/use-populate-copilot-textarea-ref.mjs +3 -3
  119. package/dist/hooks/make-autosuggestions-function/use-make-standard-autosuggestions-function.d.ts +5 -7
  120. package/dist/hooks/make-autosuggestions-function/use-make-standard-autosuggestions-function.mjs +2 -1
  121. package/dist/hooks/make-autosuggestions-function/use-make-standard-insertion-function.d.ts +23 -0
  122. package/dist/hooks/make-autosuggestions-function/use-make-standard-insertion-function.mjs +5 -0
  123. package/dist/hooks/make-autosuggestions-function/use-make-standard-insertion-function.mjs.map +1 -0
  124. package/dist/hooks/misc/use-autosize-textarea.d.ts +5 -0
  125. package/dist/hooks/misc/use-autosize-textarea.mjs +4 -0
  126. package/dist/hooks/misc/use-autosize-textarea.mjs.map +1 -0
  127. package/dist/index.css +674 -0
  128. package/dist/index.css.map +1 -1
  129. package/dist/index.d.ts +8 -3
  130. package/dist/index.mjs +34 -15
  131. package/dist/lib/editor-to-text.mjs +1 -42
  132. package/dist/lib/editor-to-text.mjs.map +1 -1
  133. package/dist/lib/get-text-around-cursor.d.ts +10 -3
  134. package/dist/lib/get-text-around-cursor.mjs +1 -1
  135. package/dist/lib/retry.d.ts +3 -0
  136. package/dist/lib/retry.mjs +4 -0
  137. package/dist/lib/retry.mjs.map +1 -0
  138. package/dist/lib/slatejs-edits/replace-text.mjs +1 -1
  139. package/dist/types/autosuggestions-config/autosuggestions-config-user-specified.d.ts +25 -0
  140. package/dist/types/autosuggestions-config/autosuggestions-config-user-specified.mjs +3 -0
  141. package/dist/types/autosuggestions-config/autosuggestions-config-user-specified.mjs.map +1 -0
  142. package/dist/types/autosuggestions-config/autosuggestions-config.d.ts +20 -0
  143. package/dist/types/autosuggestions-config/autosuggestions-config.mjs +10 -0
  144. package/dist/types/autosuggestions-config/autosuggestions-config.mjs.map +1 -0
  145. package/dist/types/autosuggestions-config/editing-api-config.d.ts +17 -0
  146. package/dist/types/autosuggestions-config/editing-api-config.mjs +5 -0
  147. package/dist/types/autosuggestions-config/editing-api-config.mjs.map +1 -0
  148. package/dist/types/autosuggestions-config/index.d.ts +10 -0
  149. package/dist/types/autosuggestions-config/index.mjs +11 -0
  150. package/dist/types/autosuggestions-config/index.mjs.map +1 -0
  151. package/dist/types/autosuggestions-config/insertions-api-config.d.ts +17 -0
  152. package/dist/types/autosuggestions-config/insertions-api-config.mjs +5 -0
  153. package/dist/types/autosuggestions-config/insertions-api-config.mjs.map +1 -0
  154. package/dist/types/{standard-autosuggestions → autosuggestions-config/subtypes}/chatlike-api-endpoint.d.ts +7 -4
  155. package/dist/types/autosuggestions-config/subtypes/chatlike-api-endpoint.mjs +4 -0
  156. package/dist/types/autosuggestions-config/subtypes/chatlike-api-endpoint.mjs.map +1 -0
  157. package/dist/types/autosuggestions-config/subtypes/make-system-prompt.d.ts +3 -0
  158. package/dist/types/autosuggestions-config/subtypes/make-system-prompt.mjs +3 -0
  159. package/dist/types/autosuggestions-config/subtypes/make-system-prompt.mjs.map +1 -0
  160. package/dist/types/autosuggestions-config/subtypes/minimal-chat-gpt-message.mjs.map +1 -0
  161. package/dist/types/autosuggestions-config/suggestions-api-config.d.ts +17 -0
  162. package/dist/types/autosuggestions-config/suggestions-api-config.mjs +5 -0
  163. package/dist/types/autosuggestions-config/suggestions-api-config.mjs.map +1 -0
  164. package/dist/types/base/autosuggestions-bare-function.d.ts +16 -2
  165. package/dist/types/base/base-autosuggestions-config.d.ts +5 -1
  166. package/dist/types/base/base-autosuggestions-config.mjs +1 -1
  167. package/dist/types/base/base-copilot-textarea-props.d.ts +3 -1
  168. package/dist/types/base/editor-autocomplete-state.mjs +1 -1
  169. package/dist/types/base/index.mjs +1 -1
  170. package/dist/types/index.d.ts +8 -3
  171. package/dist/types/index.mjs +7 -4
  172. package/package.json +19 -5
  173. package/src/components/base-copilot-textarea/base-copilot-textarea.tsx +64 -13
  174. package/src/components/base-copilot-textarea/track-cursor-moved-since-last-text-change.tsx +61 -0
  175. package/src/components/copilot-textarea/copilot-textarea.tsx +29 -17
  176. package/src/components/hovering-toolbar/hovering-editor-provider.tsx +29 -0
  177. package/src/components/hovering-toolbar/hovering-toolbar-components.tsx +115 -0
  178. package/src/components/hovering-toolbar/hovering-toolbar.tsx +156 -0
  179. package/src/components/hovering-toolbar/text-insertion-prompt-box/hovering-insertion-prompt-box.tsx +70 -0
  180. package/src/components/hovering-toolbar/text-insertion-prompt-box/index.ts +2 -0
  181. package/src/components/hovering-toolbar/text-insertion-prompt-box/mode-pre-suggestion.tsx +83 -0
  182. package/src/components/hovering-toolbar/text-insertion-prompt-box/mode-suggestion-appearing.tsx +399 -0
  183. package/src/components/manual-ui/chip-with-icon.tsx +29 -0
  184. package/src/components/source-search-box/source-search-box.tsx +127 -0
  185. package/src/components/ui/button.tsx +56 -0
  186. package/src/components/ui/card.tsx +86 -0
  187. package/src/components/ui/command.tsx +155 -0
  188. package/src/components/ui/dialog.tsx +123 -0
  189. package/src/components/ui/label.tsx +26 -0
  190. package/src/components/ui/separator.tsx +31 -0
  191. package/src/components/ui/textarea.tsx +24 -0
  192. package/src/hooks/base-copilot-textarea-implementation/use-autosuggestions.ts +10 -3
  193. package/src/hooks/make-autosuggestions-function/use-make-standard-autosuggestions-function.tsx +29 -44
  194. package/src/hooks/make-autosuggestions-function/use-make-standard-insertion-function.tsx +150 -0
  195. package/src/hooks/misc/use-autosize-textarea.tsx +21 -0
  196. package/src/lib/get-text-around-cursor.ts +71 -6
  197. package/src/lib/retry.tsx +23 -0
  198. package/src/lib/slatejs-edits/replace-text.ts +15 -31
  199. package/src/styles.css +2 -0
  200. package/src/types/autosuggestions-config/autosuggestions-config-user-specified.tsx +27 -0
  201. package/src/types/autosuggestions-config/autosuggestions-config.tsx +43 -0
  202. package/src/types/autosuggestions-config/editing-api-config.tsx +102 -0
  203. package/src/types/autosuggestions-config/index.ts +11 -0
  204. package/src/types/autosuggestions-config/insertions-api-config.tsx +95 -0
  205. package/src/types/{standard-autosuggestions → autosuggestions-config/subtypes}/chatlike-api-endpoint.tsx +19 -7
  206. package/src/types/autosuggestions-config/subtypes/make-system-prompt.ts +4 -0
  207. package/src/types/{standard-autosuggestions/autosuggestions-config.tsx → autosuggestions-config/suggestions-api-config.tsx} +12 -23
  208. package/src/types/base/autosuggestions-bare-function.ts +24 -2
  209. package/src/types/base/base-autosuggestions-config.tsx +7 -2
  210. package/src/types/base/base-copilot-textarea-props.tsx +3 -1
  211. package/src/types/base/editor-autocomplete-state.ts +1 -0
  212. package/src/types/index.ts +1 -1
  213. package/tailwind.config.js +2 -0
  214. package/dist/chunk-3A2CNIG5.mjs.map +0 -1
  215. package/dist/chunk-3UQM3NLM.mjs.map +0 -1
  216. package/dist/chunk-BTAUKCBN.mjs +0 -60
  217. package/dist/chunk-BTAUKCBN.mjs.map +0 -1
  218. package/dist/chunk-HZGSG7ST.mjs.map +0 -1
  219. package/dist/chunk-JWN2VEE3.mjs.map +0 -1
  220. package/dist/chunk-KW6VCM7T.mjs +0 -40
  221. package/dist/chunk-KW6VCM7T.mjs.map +0 -1
  222. package/dist/chunk-MFJNLKRC.mjs.map +0 -1
  223. package/dist/chunk-O5VWVXYD.mjs +0 -32
  224. package/dist/chunk-O5VWVXYD.mjs.map +0 -1
  225. package/dist/chunk-SL4J5HMW.mjs +0 -3
  226. package/dist/chunk-UW3ITU2Y.mjs.map +0 -1
  227. package/dist/chunk-V54GX4SO.mjs.map +0 -1
  228. package/dist/types/standard-autosuggestions/autosuggestions-config.d.ts +0 -19
  229. package/dist/types/standard-autosuggestions/autosuggestions-config.mjs +0 -6
  230. package/dist/types/standard-autosuggestions/chatlike-api-endpoint.mjs +0 -4
  231. package/dist/types/standard-autosuggestions/index.d.ts +0 -4
  232. package/dist/types/standard-autosuggestions/index.mjs +0 -8
  233. package/src/types/standard-autosuggestions/index.ts +0 -14
  234. /package/dist/{chunk-SL4J5HMW.mjs.map → chunk-5FO6ISW4.mjs.map} +0 -0
  235. /package/dist/{types/standard-autosuggestions/autosuggestions-config.mjs.map → chunk-L7VVZH4Q.mjs.map} +0 -0
  236. /package/dist/{chunk-RKZRCIPE.mjs.map → chunk-YQU7WG7T.mjs.map} +0 -0
  237. /package/dist/{types/standard-autosuggestions/chatlike-api-endpoint.mjs.map → components/base-copilot-textarea/track-cursor-moved-since-last-text-change.mjs.map} +0 -0
  238. /package/dist/{types/standard-autosuggestions/index.mjs.map → components/hovering-toolbar/hovering-editor-provider.mjs.map} +0 -0
  239. /package/dist/{types/standard-autosuggestions/minimal-chat-gpt-message.mjs.map → components/hovering-toolbar/hovering-toolbar-components.mjs.map} +0 -0
  240. /package/dist/types/{standard-autosuggestions → autosuggestions-config/subtypes}/minimal-chat-gpt-message.d.ts +0 -0
  241. /package/dist/types/{standard-autosuggestions → autosuggestions-config/subtypes}/minimal-chat-gpt-message.mjs +0 -0
  242. /package/src/types/{standard-autosuggestions → autosuggestions-config/subtypes}/minimal-chat-gpt-message.tsx +0 -0
@@ -0,0 +1,156 @@
1
+ import { css } from "@emotion/css";
2
+ import { useEffect, useMemo, useRef, useState } from "react";
3
+ import { BaseSelection, Editor, Range, Location, Transforms } from "slate";
4
+ import { useSlate, useSlateSelection } from "slate-react";
5
+ import { HoveringInsertionPromptBox } from "./text-insertion-prompt-box";
6
+ import { Button, Icon, Menu, Portal } from "./hovering-toolbar-components";
7
+ import { useHoveringEditorContext } from "./hovering-editor-provider";
8
+ import {
9
+ getFullEditorTextWithNewlines,
10
+ getTextAroundSelection,
11
+ } from "../../lib/get-text-around-cursor";
12
+ import {
13
+ EditingEditorState,
14
+ InsertionEditorApiConfig,
15
+ } from "../../types/base/autosuggestions-bare-function";
16
+
17
+ export interface HoveringToolbarProps {
18
+ apiConfig: InsertionEditorApiConfig;
19
+ }
20
+
21
+ export const HoveringToolbar: (
22
+ props: HoveringToolbarProps
23
+ ) => JSX.Element | null = (props) => {
24
+ const ref = useRef<HTMLDivElement>(null);
25
+ const editor = useSlate();
26
+ const selection = useSlateSelection();
27
+ const { isDisplayed, setIsDisplayed } = useHoveringEditorContext();
28
+
29
+ // only render on client
30
+ const [isClient, setIsClient] = useState(false);
31
+ useEffect(() => {
32
+ setIsClient(true);
33
+ }, []);
34
+
35
+ useEffect(() => {
36
+ const el = ref.current;
37
+ const { selection } = editor;
38
+
39
+ if (!el) {
40
+ return;
41
+ }
42
+
43
+ if (!selection) {
44
+ el.removeAttribute("style");
45
+ return;
46
+ }
47
+
48
+ const domSelection = window.getSelection();
49
+ if (!domSelection) {
50
+ return;
51
+ }
52
+
53
+ const domRange = domSelection.getRangeAt(0);
54
+ const rect = domRange.getBoundingClientRect();
55
+
56
+ // We use window = (0,0,0,0) as a signal that the selection is not in the original copilot-textarea,
57
+ // but inside the hovering window.
58
+ //
59
+ // in such case, we simply do nothing.
60
+ if (
61
+ rect.top === 0 &&
62
+ rect.left === 0 &&
63
+ rect.width === 0 &&
64
+ rect.height === 0
65
+ ) {
66
+ return;
67
+ }
68
+
69
+ const minGapFromEdge = 60;
70
+ const verticalOffsetFromCorner = 35;
71
+ const horizontalOffsetFromCorner = 15;
72
+ let top =
73
+ rect.top + window.scrollY - el.offsetHeight + verticalOffsetFromCorner;
74
+ // make sure top is in the viewport and not too close to the edge
75
+ if (top < minGapFromEdge) {
76
+ top = rect.bottom + window.scrollY + minGapFromEdge;
77
+ } else if (top + el.offsetHeight > window.innerHeight - minGapFromEdge) {
78
+ top = rect.top + window.scrollY - el.offsetHeight - minGapFromEdge;
79
+ }
80
+
81
+ let left =
82
+ rect.left +
83
+ window.scrollX -
84
+ el.offsetWidth / 2 +
85
+ rect.width / 2 +
86
+ horizontalOffsetFromCorner;
87
+ // make sure left is in the viewport and not too close to the edge
88
+ if (left < minGapFromEdge) {
89
+ left = minGapFromEdge;
90
+ } else if (left + el.offsetWidth > window.innerWidth - minGapFromEdge) {
91
+ left = window.innerWidth - el.offsetWidth - minGapFromEdge;
92
+ }
93
+
94
+ el.style.opacity = "1";
95
+ el.style.top = `${top}px`;
96
+ el.style.left = `${left}px`;
97
+ });
98
+
99
+ useEffect(() => {
100
+ const handleClickOutside = (event: MouseEvent) => {
101
+ if (ref.current && !ref.current.contains(event.target as Node)) {
102
+ setIsDisplayed(false);
103
+ }
104
+ };
105
+
106
+ document.addEventListener("mousedown", handleClickOutside);
107
+ return () => {
108
+ document.removeEventListener("mousedown", handleClickOutside);
109
+ };
110
+ }, [ref, setIsDisplayed]);
111
+
112
+ if (!isClient) {
113
+ return null;
114
+ }
115
+
116
+ return (
117
+ <Portal>
118
+ <Menu
119
+ ref={ref}
120
+ className="p-2 absolute z-10 top-[-10000px] left-[-10000px] mt-[-6px] opacity-0 transition-opacity duration-700"
121
+ >
122
+ {isDisplayed && selection && (
123
+ <HoveringInsertionPromptBox
124
+ editorState={editorState(editor, selection)}
125
+ apiConfig={props.apiConfig}
126
+ closeWindow={() => {
127
+ setIsDisplayed(false);
128
+ }}
129
+ performInsertion={(insertedText) => {
130
+ console.log("inserted text", insertedText);
131
+ // replace the selection with the inserted text
132
+ Transforms.delete(editor, { at: selection });
133
+ Transforms.insertText(editor, insertedText, {
134
+ at: selection,
135
+ });
136
+ setIsDisplayed(false);
137
+ }}
138
+ />
139
+ )}
140
+ </Menu>
141
+ </Portal>
142
+ );
143
+ };
144
+
145
+ function editorState(editor: Editor, selection: Location): EditingEditorState {
146
+ const textAroundCursor = getTextAroundSelection(editor);
147
+ if (textAroundCursor) {
148
+ return textAroundCursor;
149
+ }
150
+
151
+ return {
152
+ textBeforeCursor: getFullEditorTextWithNewlines(editor),
153
+ textAfterCursor: "",
154
+ selectedText: "",
155
+ };
156
+ }
@@ -0,0 +1,70 @@
1
+ import React, { useCallback, useState } from "react";
2
+ import {
3
+ State_SuggestionAppearing,
4
+ SuggestionAppearing,
5
+ } from "./mode-suggestion-appearing";
6
+ import { PreSuggestion, State_PreSuggestion } from "./mode-pre-suggestion";
7
+ import {
8
+ EditingEditorState,
9
+ InsertionEditorApiConfig,
10
+ } from "../../../types/base/autosuggestions-bare-function";
11
+
12
+ type InsertionPromptState = State_PreSuggestion | State_SuggestionAppearing;
13
+
14
+ export interface Props {
15
+ editorState: EditingEditorState;
16
+ apiConfig: InsertionEditorApiConfig;
17
+ performInsertion: (insertedText: string) => void;
18
+ closeWindow: () => void;
19
+ }
20
+
21
+ export const HoveringInsertionPromptBox: React.FC<Props> = (props) => {
22
+ const [insertionPrompt, setInsertionPrompt] = useState<string>("");
23
+ const [mode, setMode] = useState<InsertionPromptState>({
24
+ type: "pre-suggestion",
25
+ });
26
+
27
+ const handleGeneratedText = useCallback(
28
+ (generatingText: ReadableStream<string>) => {
29
+ setMode({
30
+ type: "suggestion-appearing",
31
+ initialSuggestion: {
32
+ editorState: props.editorState,
33
+ adjustmentPrompt: insertionPrompt,
34
+ generatingSuggestion: generatingText,
35
+ },
36
+ });
37
+ },
38
+ [setMode, insertionPrompt]
39
+ );
40
+
41
+ const goBack = () => {
42
+ setMode({ type: "pre-suggestion" });
43
+ };
44
+
45
+ return (
46
+ <div className="flex flex-col justify-center items-center space-y-4 rounded-md border shadow-lg p-4 border-gray- bg-white" style={{width: "30rem"}}>
47
+ {mode.type === "pre-suggestion" ? (
48
+ <PreSuggestion
49
+ {...props}
50
+ insertionOrEditingFunction={
51
+ props.apiConfig.insertionOrEditingFunction
52
+ }
53
+ insertionOrEditingPrompt={insertionPrompt}
54
+ setInsertionOrEditingPrompt={setInsertionPrompt}
55
+ onGeneratedText={handleGeneratedText}
56
+ />
57
+ ) : (
58
+ <SuggestionAppearing
59
+ {...props}
60
+ state={mode}
61
+ goBack={goBack}
62
+ insertionOrEditingFunction={
63
+ props.apiConfig.insertionOrEditingFunction
64
+ }
65
+ onGeneratedText={handleGeneratedText}
66
+ />
67
+ )}
68
+ </div>
69
+ );
70
+ };
@@ -0,0 +1,2 @@
1
+ export { HoveringInsertionPromptBox } from "./hovering-insertion-prompt-box";
2
+ export type { Props } from "./hovering-insertion-prompt-box";
@@ -0,0 +1,83 @@
1
+ import useAutosizeTextArea from "../../../hooks/misc/use-autosize-textarea";
2
+ import React, { useEffect, useRef, useState } from "react";
3
+ import {
4
+ EditingEditorState,
5
+ Generator_InsertionOrEditingSuggestion,
6
+ } from "../../../types/base/autosuggestions-bare-function";
7
+
8
+ export type State_PreSuggestion = {
9
+ type: "pre-suggestion";
10
+ };
11
+
12
+ export interface PreSuggestionProps {
13
+ editorState: EditingEditorState;
14
+ insertionOrEditingFunction: Generator_InsertionOrEditingSuggestion;
15
+ onGeneratedText: (generatedText: ReadableStream<string>) => void;
16
+
17
+ insertionOrEditingPrompt: string;
18
+ setInsertionOrEditingPrompt: (value: string) => void;
19
+ }
20
+
21
+ export const PreSuggestion: React.FC<PreSuggestionProps> = ({
22
+ editorState,
23
+ insertionOrEditingFunction: insertionSuggestion,
24
+ onGeneratedText,
25
+ insertionOrEditingPrompt: insertionPrompt,
26
+ setInsertionOrEditingPrompt: setInsertionPrompt,
27
+ }) => {
28
+ const [loading, setLoading] = useState(false);
29
+
30
+ const promptTextAreaRef = useRef<HTMLTextAreaElement>(null);
31
+ useAutosizeTextArea(promptTextAreaRef, insertionPrompt);
32
+
33
+ // initially focus on the prompt text area
34
+ useEffect(() => {
35
+ promptTextAreaRef.current?.focus();
36
+ }, []);
37
+
38
+ const generateText = async (abortSignal?: AbortSignal) => {
39
+ // don't generate text if the prompt is empty
40
+ if (!insertionPrompt.trim()) {
41
+ return;
42
+ }
43
+
44
+ setLoading(true);
45
+ const insertionSuggestionTextStream = await insertionSuggestion(
46
+ editorState,
47
+ insertionPrompt,
48
+ abortSignal || new AbortController().signal
49
+ );
50
+ onGeneratedText(insertionSuggestionTextStream);
51
+
52
+ setLoading(false);
53
+ };
54
+
55
+ return (
56
+ <div className="flex flex-col justify-center items-start gap-2">
57
+ <textarea
58
+ ref={promptTextAreaRef}
59
+ value={insertionPrompt}
60
+ onChange={(e) => setInsertionPrompt(e.target.value)}
61
+ onKeyDown={(e) => {
62
+ if (e.key === "Enter" && e.shiftKey) {
63
+ e.preventDefault();
64
+ setInsertionPrompt(insertionPrompt + "\n");
65
+ } else if (e.key === "Enter") {
66
+ e.preventDefault();
67
+ generateText();
68
+ }
69
+ }}
70
+ placeholder="Describe the text you'd like to insert..."
71
+ className="w-full bg-slate-100 h-auto text-sm p-2 rounded-md resize-none overflow-visible focus:outline-none focus:ring-0 focus:border-none"
72
+ rows={1}
73
+ />
74
+ <button
75
+ disabled={loading || !insertionPrompt.trim()}
76
+ onClick={() => generateText()}
77
+ className="w-full py-2 px-4 rounded-md text-white bg-blue-500 hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed"
78
+ >
79
+ {loading ? "Loading..." : "Generate Text"}
80
+ </button>
81
+ </div>
82
+ );
83
+ };