@ai-stack/payloadcms 3.68.0 → 3.76.0-beta.1

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 (187) hide show
  1. package/dist/ai/core/media/image/generateImage.js +2 -6
  2. package/dist/ai/core/media/image/generateImage.js.map +1 -1
  3. package/dist/ai/core/media/image/handlers/multimodal.js +13 -28
  4. package/dist/ai/core/media/image/handlers/multimodal.js.map +1 -1
  5. package/dist/ai/core/media/image/handlers/standard.js +10 -7
  6. package/dist/ai/core/media/image/handlers/standard.js.map +1 -1
  7. package/dist/ai/core/media/speech/generateSpeech.js +8 -8
  8. package/dist/ai/core/media/speech/generateSpeech.js.map +1 -1
  9. package/dist/ai/core/media/types.d.ts +1 -1
  10. package/dist/ai/core/media/types.js.map +1 -1
  11. package/dist/ai/core/streamObject.js +3 -3
  12. package/dist/ai/core/streamObject.js.map +1 -1
  13. package/dist/ai/core/types.d.ts +3 -0
  14. package/dist/ai/core/types.js.map +1 -1
  15. package/dist/ai/prompts.d.ts +1 -2
  16. package/dist/ai/prompts.js +0 -110
  17. package/dist/ai/prompts.js.map +1 -1
  18. package/dist/ai/providers/blocks/anthropic.js +2 -1
  19. package/dist/ai/providers/blocks/anthropic.js.map +1 -1
  20. package/dist/ai/providers/blocks/elevenlabs.js +3 -2
  21. package/dist/ai/providers/blocks/elevenlabs.js.map +1 -1
  22. package/dist/ai/providers/blocks/fal.js +2 -1
  23. package/dist/ai/providers/blocks/fal.js.map +1 -1
  24. package/dist/ai/providers/blocks/google.js +12 -6
  25. package/dist/ai/providers/blocks/google.js.map +1 -1
  26. package/dist/ai/providers/blocks/openai-compatible.js +2 -1
  27. package/dist/ai/providers/blocks/openai-compatible.js.map +1 -1
  28. package/dist/ai/providers/blocks/openai.js +3 -2
  29. package/dist/ai/providers/blocks/openai.js.map +1 -1
  30. package/dist/ai/providers/blocks/xai.js +2 -1
  31. package/dist/ai/providers/blocks/xai.js.map +1 -1
  32. package/dist/ai/providers/icons.d.ts +7 -0
  33. package/dist/ai/providers/icons.js +9 -0
  34. package/dist/ai/providers/icons.js.map +1 -0
  35. package/dist/ai/providers/registry.js +36 -26
  36. package/dist/ai/providers/registry.js.map +1 -1
  37. package/dist/ai/utils/filterEditorSchemaByNodes.d.ts +9 -0
  38. package/dist/ai/utils/filterEditorSchemaByNodes.js +30 -3
  39. package/dist/ai/utils/filterEditorSchemaByNodes.js.map +1 -1
  40. package/dist/ai/utils/nodeToSchemaMap.d.ts +22 -0
  41. package/dist/ai/utils/nodeToSchemaMap.js +72 -0
  42. package/dist/ai/utils/nodeToSchemaMap.js.map +1 -0
  43. package/dist/collections/AIJobs.js +1 -1
  44. package/dist/collections/AIJobs.js.map +1 -1
  45. package/dist/collections/AIProviders.d.ts +2 -0
  46. package/dist/collections/{AISettings.js → AIProviders.js} +53 -25
  47. package/dist/collections/AIProviders.js.map +1 -0
  48. package/dist/collections/Instructions.js +45 -4
  49. package/dist/collections/Instructions.js.map +1 -1
  50. package/dist/defaults.d.ts +1 -0
  51. package/dist/defaults.js +8 -0
  52. package/dist/defaults.js.map +1 -1
  53. package/dist/endpoints/chat.d.ts +4 -0
  54. package/dist/endpoints/fetchFields.js +10 -0
  55. package/dist/endpoints/fetchFields.js.map +1 -1
  56. package/dist/endpoints/fetchVoices.js +42 -25
  57. package/dist/endpoints/fetchVoices.js.map +1 -1
  58. package/dist/endpoints/index.js +248 -35
  59. package/dist/endpoints/index.js.map +1 -1
  60. package/dist/exports/client.d.ts +1 -1
  61. package/dist/exports/client.js +1 -1
  62. package/dist/exports/client.js.map +1 -1
  63. package/dist/exports/fields.d.ts +1 -0
  64. package/dist/exports/fields.js +1 -0
  65. package/dist/exports/fields.js.map +1 -1
  66. package/dist/fields/ArrayComposeField/ArrayComposeField.d.ts +15 -0
  67. package/dist/fields/ArrayComposeField/ArrayComposeField.js +87 -0
  68. package/dist/fields/ArrayComposeField/ArrayComposeField.js.map +1 -0
  69. package/dist/fields/ArrayComposeField/ArrayComposeField.jsx +73 -0
  70. package/dist/fields/PromptEditorField/PromptEditorField.js +7 -2
  71. package/dist/fields/PromptEditorField/PromptEditorField.js.map +1 -1
  72. package/dist/fields/PromptEditorField/PromptEditorField.jsx +5 -2
  73. package/dist/index.d.ts +3 -1
  74. package/dist/index.js +2 -1
  75. package/dist/index.js.map +1 -1
  76. package/dist/payload-ai.d.ts +152 -0
  77. package/dist/plugin.js +18 -34
  78. package/dist/plugin.js.map +1 -1
  79. package/dist/providers/InstructionsProvider/InstructionsProvider.js +47 -15
  80. package/dist/providers/InstructionsProvider/InstructionsProvider.js.map +1 -1
  81. package/dist/providers/InstructionsProvider/InstructionsProvider.jsx +39 -16
  82. package/dist/providers/InstructionsProvider/context.d.ts +3 -0
  83. package/dist/providers/InstructionsProvider/context.js +2 -0
  84. package/dist/providers/InstructionsProvider/context.js.map +1 -1
  85. package/dist/providers/InstructionsProvider/useInstructions.js +22 -3
  86. package/dist/providers/InstructionsProvider/useInstructions.js.map +1 -1
  87. package/dist/styles.d.ts +11 -0
  88. package/dist/types/handlebars-async-helpers.d.ts +1 -0
  89. package/dist/types/handlebars-dist-handlebars.d.ts +1 -0
  90. package/dist/types/react-mentions.d.ts +1 -0
  91. package/dist/types.d.ts +36 -7
  92. package/dist/types.js +1 -0
  93. package/dist/types.js.map +1 -1
  94. package/dist/ui/AIConfigDashboard/index.d.ts +1 -1
  95. package/dist/ui/AIConfigDashboard/index.js +201 -23
  96. package/dist/ui/AIConfigDashboard/index.js.map +1 -1
  97. package/dist/ui/AIConfigDashboard/index.jsx +166 -15
  98. package/dist/ui/Compose/Compose.d.ts +1 -0
  99. package/dist/ui/Compose/Compose.js +23 -4
  100. package/dist/ui/Compose/Compose.js.map +1 -1
  101. package/dist/ui/Compose/Compose.jsx +23 -4
  102. package/dist/ui/Compose/UndoRedoActions.d.ts +2 -2
  103. package/dist/ui/Compose/UndoRedoActions.js +8 -5
  104. package/dist/ui/Compose/UndoRedoActions.js.map +1 -1
  105. package/dist/ui/Compose/UndoRedoActions.jsx +6 -5
  106. package/dist/ui/Compose/compose.module.css +56 -16
  107. package/dist/ui/Compose/hooks/menu/TranslateMenu.d.ts +5 -0
  108. package/dist/ui/Compose/hooks/menu/TranslateMenu.js +45 -4
  109. package/dist/ui/Compose/hooks/menu/TranslateMenu.js.map +1 -1
  110. package/dist/ui/Compose/hooks/menu/TranslateMenu.jsx +41 -5
  111. package/dist/ui/Compose/hooks/menu/itemsMap.js +12 -6
  112. package/dist/ui/Compose/hooks/menu/itemsMap.js.map +1 -1
  113. package/dist/ui/Compose/hooks/menu/menu.module.scss +4 -1
  114. package/dist/ui/Compose/hooks/menu/useMenu.js +26 -15
  115. package/dist/ui/Compose/hooks/menu/useMenu.js.map +1 -1
  116. package/dist/ui/Compose/hooks/menu/useMenu.jsx +25 -12
  117. package/dist/ui/Compose/hooks/useActiveFieldTracking.js +34 -0
  118. package/dist/ui/Compose/hooks/useActiveFieldTracking.js.map +1 -1
  119. package/dist/ui/Compose/hooks/useGenerate.js +26 -174
  120. package/dist/ui/Compose/hooks/useGenerate.js.map +1 -1
  121. package/dist/ui/Compose/hooks/useGenerateUpload.d.ts +11 -0
  122. package/dist/ui/Compose/hooks/useGenerateUpload.js +156 -0
  123. package/dist/ui/Compose/hooks/useGenerateUpload.js.map +1 -0
  124. package/dist/ui/Compose/hooks/useHistory.d.ts +0 -1
  125. package/dist/ui/Compose/hooks/useHistory.js +65 -25
  126. package/dist/ui/Compose/hooks/useHistory.js.map +1 -1
  127. package/dist/ui/Compose/hooks/useStreamingUpdate.d.ts +8 -0
  128. package/dist/ui/Compose/hooks/useStreamingUpdate.js +48 -0
  129. package/dist/ui/Compose/hooks/useStreamingUpdate.js.map +1 -0
  130. package/dist/ui/ConfigDashboard/index.d.ts +2 -0
  131. package/dist/ui/ConfigDashboard/index.js +224 -0
  132. package/dist/ui/ConfigDashboard/index.js.map +1 -0
  133. package/dist/ui/ConfigDashboard/index.jsx +175 -0
  134. package/dist/ui/DynamicModelSelect/index.js +1 -1
  135. package/dist/ui/DynamicModelSelect/index.js.map +1 -1
  136. package/dist/ui/DynamicModelSelect/index.jsx +1 -1
  137. package/dist/ui/DynamicProviderSelect/index.js +1 -1
  138. package/dist/ui/DynamicProviderSelect/index.js.map +1 -1
  139. package/dist/ui/DynamicProviderSelect/index.jsx +1 -1
  140. package/dist/ui/DynamicVoiceSelect/index.js +63 -11
  141. package/dist/ui/DynamicVoiceSelect/index.js.map +1 -1
  142. package/dist/ui/DynamicVoiceSelect/index.jsx +47 -14
  143. package/dist/ui/EncryptedTextField/index.js +4 -4
  144. package/dist/ui/EncryptedTextField/index.js.map +1 -1
  145. package/dist/ui/EncryptedTextField/index.jsx +4 -4
  146. package/dist/ui/ProviderOptionsEditor/index.js +1 -1
  147. package/dist/ui/ProviderOptionsEditor/index.js.map +1 -1
  148. package/dist/ui/ProviderOptionsEditor/index.jsx +1 -1
  149. package/dist/ui/VoicesFetcher/index.js +34 -16
  150. package/dist/ui/VoicesFetcher/index.js.map +1 -1
  151. package/dist/ui/VoicesFetcher/index.jsx +32 -15
  152. package/dist/utilities/buildSmartPrompt.d.ts +22 -0
  153. package/dist/utilities/buildSmartPrompt.js +141 -0
  154. package/dist/utilities/buildSmartPrompt.js.map +1 -0
  155. package/dist/utilities/encryption.js +2 -1
  156. package/dist/utilities/encryption.js.map +1 -1
  157. package/dist/utilities/fieldToJsonSchema.js +32 -3
  158. package/dist/utilities/fieldToJsonSchema.js.map +1 -1
  159. package/dist/utilities/resolveImageReferences.d.ts +3 -1
  160. package/dist/utilities/resolveImageReferences.js +21 -2
  161. package/dist/utilities/resolveImageReferences.js.map +1 -1
  162. package/dist/utilities/seedProperties.d.ts +7 -0
  163. package/dist/utilities/seedProperties.js +100 -0
  164. package/dist/utilities/seedProperties.js.map +1 -0
  165. package/dist/utilities/setSafeLexicalState.js +79 -6
  166. package/dist/utilities/setSafeLexicalState.js.map +1 -1
  167. package/dist/utilities/updateFieldsConfig.d.ts +1 -1
  168. package/dist/utilities/updateFieldsConfig.js +9 -2
  169. package/dist/utilities/updateFieldsConfig.js.map +1 -1
  170. package/package.json +35 -33
  171. package/dist/collections/AISettings.d.ts +0 -2
  172. package/dist/collections/AISettings.js.map +0 -1
  173. package/dist/endpoints/chat.d.js +0 -3
  174. package/dist/endpoints/chat.d.js.map +0 -1
  175. package/dist/init.d.ts +0 -7
  176. package/dist/init.js +0 -135
  177. package/dist/init.js.map +0 -1
  178. package/dist/payload-ai.d.js +0 -3
  179. package/dist/payload-ai.d.js.map +0 -1
  180. package/dist/styles.d.js +0 -2
  181. package/dist/styles.d.js.map +0 -1
  182. package/dist/types/handlebars-async-helpers.d.js +0 -2
  183. package/dist/types/handlebars-async-helpers.d.js.map +0 -1
  184. package/dist/types/handlebars-dist-handlebars.d.js +0 -2
  185. package/dist/types/handlebars-dist-handlebars.d.js.map +0 -1
  186. package/dist/types/react-mentions.d.js +0 -2
  187. package/dist/types/react-mentions.d.js.map +0 -1
@@ -1,12 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import locales from 'locale-codes';
3
- import React, { memo, useState } from 'react';
3
+ import React, { memo, useEffect, useRef, useState } from 'react';
4
4
  import { useInstructions } from '../../../../providers/InstructionsProvider/useInstructions.js';
5
5
  import { Item } from './Item.js';
6
6
  import { Translate } from './items.js';
7
7
  import styles from './menu.module.scss';
8
8
  export const TranslateMenu = ({ onClick })=>{
9
9
  const [show, setShow] = useState(false);
10
+ const closeTimeoutRef = useRef(null);
10
11
  const { enabledLanguages = [] } = useInstructions();
11
12
  let filteredLocales = locales.all.filter((a)=>{
12
13
  return a.tag && a.location;
@@ -16,11 +17,48 @@ export const TranslateMenu = ({ onClick })=>{
16
17
  }
17
18
  const [languages, setLanguages] = useState(filteredLocales);
18
19
  const [inputFocus, setInputFocus] = useState(false);
20
+ useEffect(()=>{
21
+ if (!show) {
22
+ if (typeof window !== 'undefined') {
23
+ window.__AI_MENU_INTERACTIVE = false;
24
+ }
25
+ }
26
+ return ()=>{
27
+ if (closeTimeoutRef.current) {
28
+ clearTimeout(closeTimeoutRef.current);
29
+ }
30
+ if (show && typeof window !== 'undefined') {
31
+ window.__AI_MENU_INTERACTIVE = false;
32
+ }
33
+ };
34
+ }, [
35
+ show
36
+ ]);
19
37
  return /*#__PURE__*/ _jsxs("div", {
20
- className: styles.menu,
38
+ className: `${styles.menu} ai-interactive-menu`,
39
+ "data-ai-interactive": "true",
40
+ onBlur: (e)=>{
41
+ // Only clear if focus moves outside the menu container
42
+ if (!e.currentTarget.contains(e.relatedTarget)) {
43
+ if (typeof window !== 'undefined') window.__AI_MENU_INTERACTIVE = false;
44
+ }
45
+ },
46
+ onFocus: ()=>{
47
+ if (typeof window !== 'undefined') window.__AI_MENU_INTERACTIVE = true;
48
+ },
49
+ onMouseEnter: ()=>{
50
+ if (closeTimeoutRef.current) {
51
+ clearTimeout(closeTimeoutRef.current);
52
+ closeTimeoutRef.current = null;
53
+ }
54
+ if (typeof window !== 'undefined') window.__AI_MENU_INTERACTIVE = true;
55
+ },
21
56
  onMouseLeave: ()=>{
57
+ if (typeof window !== 'undefined') window.__AI_MENU_INTERACTIVE = false;
22
58
  if (!inputFocus) {
23
- setShow(false);
59
+ closeTimeoutRef.current = setTimeout(()=>{
60
+ setShow(false);
61
+ }, 400);
24
62
  }
25
63
  },
26
64
  children: [
@@ -49,7 +87,8 @@ export const TranslateMenu = ({ onClick })=>{
49
87
  top: 0
50
88
  },
51
89
  children: /*#__PURE__*/ _jsx("input", {
52
- className: styles.menuInput,
90
+ className: `${styles.menuInput} ai-interactive-menu`,
91
+ "data-ai-interactive": "true",
53
92
  onBlur: ()=>setInputFocus(false),
54
93
  onChange: (event)=>{
55
94
  const value = event.target.value;
@@ -64,6 +103,8 @@ export const TranslateMenu = ({ onClick })=>{
64
103
  }),
65
104
  languages.map((locale)=>{
66
105
  return /*#__PURE__*/ _jsx(Item, {
106
+ className: "ai-interactive-menu",
107
+ "data-ai-interactive": "true",
67
108
  onClick: ()=>{
68
109
  onClick({
69
110
  locale: locale.tag
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/ui/Compose/hooks/menu/TranslateMenu.tsx"],"sourcesContent":["import locales from 'locale-codes'\nimport React, { memo, useState } from 'react'\n\nimport { useInstructions } from '../../../../providers/InstructionsProvider/useInstructions.js'\nimport { Item } from './Item.js'\nimport { Translate } from './items.js'\nimport styles from './menu.module.scss'\n\nexport const TranslateMenu = ({ onClick }: { onClick: (data: { locale: string }) => void }) => {\n const [show, setShow] = useState(false)\n\n const { enabledLanguages = [] } = useInstructions()\n\n let filteredLocales = locales.all.filter((a) => {\n return a.tag && a.location\n })\n\n if (enabledLanguages?.length) {\n filteredLocales = filteredLocales.filter((a) => enabledLanguages?.includes(a.tag))\n }\n\n const [languages, setLanguages] = useState(filteredLocales)\n const [inputFocus, setInputFocus] = useState(false)\n\n return (\n <div\n className={styles.menu}\n onMouseLeave={() => {\n if (!inputFocus) {\n setShow(false)\n }\n }}\n >\n <Translate\n isActive={show}\n isMenu\n onClick={() => {\n setShow(!show)\n }}\n />\n <div className={styles.hoverMenu} data-show={show}>\n <div\n className={`${styles.menu} ${styles.subMenu}`}\n style={{\n background: 'var(--popup-bg)',\n // minHeight: '300px',\n }}\n >\n <Item\n onClick={() => {}}\n style={{\n background: 'transparent',\n padding: '0 0 5px 0',\n position: 'sticky',\n top: 0,\n }}\n >\n <input\n className={styles.menuInput}\n onBlur={() => setInputFocus(false)}\n onChange={(event) => {\n const value = event.target.value\n setLanguages(\n filteredLocales.filter((l) => {\n const lowerCaseValue = value.toLowerCase()\n return (\n l.name.toLowerCase().startsWith(lowerCaseValue) ||\n (l.location && l.location.toLowerCase().startsWith(lowerCaseValue)) ||\n l.tag.toLowerCase().startsWith(lowerCaseValue)\n )\n }),\n )\n }}\n onFocus={() => setInputFocus(true)}\n placeholder=\"Search...\"\n />\n </Item>\n {languages.map((locale) => {\n return (\n <Item\n key={locale.tag}\n onClick={() => {\n onClick({ locale: locale.tag })\n }}\n >\n <span className={styles.ellipsis}>{`${locale.location} (${locale.tag})`}</span>\n </Item>\n )\n })}\n </div>\n </div>\n </div>\n )\n}\n\nexport const MemoizedTranslateMenu = memo(TranslateMenu)\n"],"names":["locales","React","memo","useState","useInstructions","Item","Translate","styles","TranslateMenu","onClick","show","setShow","enabledLanguages","filteredLocales","all","filter","a","tag","location","length","includes","languages","setLanguages","inputFocus","setInputFocus","div","className","menu","onMouseLeave","isActive","isMenu","hoverMenu","data-show","subMenu","style","background","padding","position","top","input","menuInput","onBlur","onChange","event","value","target","l","lowerCaseValue","toLowerCase","name","startsWith","onFocus","placeholder","map","locale","span","ellipsis","MemoizedTranslateMenu"],"mappings":";AAAA,OAAOA,aAAa,eAAc;AAClC,OAAOC,SAASC,IAAI,EAAEC,QAAQ,QAAQ,QAAO;AAE7C,SAASC,eAAe,QAAQ,gEAA+D;AAC/F,SAASC,IAAI,QAAQ,YAAW;AAChC,SAASC,SAAS,QAAQ,aAAY;AACtC,OAAOC,YAAY,qBAAoB;AAEvC,OAAO,MAAMC,gBAAgB,CAAC,EAAEC,OAAO,EAAmD;IACxF,MAAM,CAACC,MAAMC,QAAQ,GAAGR,SAAS;IAEjC,MAAM,EAAES,mBAAmB,EAAE,EAAE,GAAGR;IAElC,IAAIS,kBAAkBb,QAAQc,GAAG,CAACC,MAAM,CAAC,CAACC;QACxC,OAAOA,EAAEC,GAAG,IAAID,EAAEE,QAAQ;IAC5B;IAEA,IAAIN,kBAAkBO,QAAQ;QAC5BN,kBAAkBA,gBAAgBE,MAAM,CAAC,CAACC,IAAMJ,kBAAkBQ,SAASJ,EAAEC,GAAG;IAClF;IAEA,MAAM,CAACI,WAAWC,aAAa,GAAGnB,SAASU;IAC3C,MAAM,CAACU,YAAYC,cAAc,GAAGrB,SAAS;IAE7C,qBACE,MAACsB;QACCC,WAAWnB,OAAOoB,IAAI;QACtBC,cAAc;YACZ,IAAI,CAACL,YAAY;gBACfZ,QAAQ;YACV;QACF;;0BAEA,KAACL;gBACCuB,UAAUnB;gBACVoB,MAAM;gBACNrB,SAAS;oBACPE,QAAQ,CAACD;gBACX;;0BAEF,KAACe;gBAAIC,WAAWnB,OAAOwB,SAAS;gBAAEC,aAAWtB;0BAC3C,cAAA,MAACe;oBACCC,WAAW,CAAC,EAAEnB,OAAOoB,IAAI,CAAC,CAAC,EAAEpB,OAAO0B,OAAO,CAAC,CAAC;oBAC7CC,OAAO;wBACLC,YAAY;oBAEd;;sCAEA,KAAC9B;4BACCI,SAAS,KAAO;4BAChByB,OAAO;gCACLC,YAAY;gCACZC,SAAS;gCACTC,UAAU;gCACVC,KAAK;4BACP;sCAEA,cAAA,KAACC;gCACCb,WAAWnB,OAAOiC,SAAS;gCAC3BC,QAAQ,IAAMjB,cAAc;gCAC5BkB,UAAU,CAACC;oCACT,MAAMC,QAAQD,MAAME,MAAM,CAACD,KAAK;oCAChCtB,aACET,gBAAgBE,MAAM,CAAC,CAAC+B;wCACtB,MAAMC,iBAAiBH,MAAMI,WAAW;wCACxC,OACEF,EAAEG,IAAI,CAACD,WAAW,GAAGE,UAAU,CAACH,mBAC/BD,EAAE5B,QAAQ,IAAI4B,EAAE5B,QAAQ,CAAC8B,WAAW,GAAGE,UAAU,CAACH,mBACnDD,EAAE7B,GAAG,CAAC+B,WAAW,GAAGE,UAAU,CAACH;oCAEnC;gCAEJ;gCACAI,SAAS,IAAM3B,cAAc;gCAC7B4B,aAAY;;;wBAGf/B,UAAUgC,GAAG,CAAC,CAACC;4BACd,qBACE,KAACjD;gCAECI,SAAS;oCACPA,QAAQ;wCAAE6C,QAAQA,OAAOrC,GAAG;oCAAC;gCAC/B;0CAEA,cAAA,KAACsC;oCAAK7B,WAAWnB,OAAOiD,QAAQ;8CAAG,CAAC,EAAEF,OAAOpC,QAAQ,CAAC,EAAE,EAAEoC,OAAOrC,GAAG,CAAC,CAAC,CAAC;;+BALlEqC,OAAOrC,GAAG;wBAQrB;;;;;;AAKV,EAAC;AAED,OAAO,MAAMwC,sCAAwBvD,KAAKM,eAAc"}
1
+ {"version":3,"sources":["../../../../../src/ui/Compose/hooks/menu/TranslateMenu.tsx"],"sourcesContent":["import locales from 'locale-codes'\nimport React, { memo, useEffect, useRef, useState } from 'react'\n\nimport { useInstructions } from '../../../../providers/InstructionsProvider/useInstructions.js'\nimport { Item } from './Item.js'\nimport { Translate } from './items.js'\nimport styles from './menu.module.scss'\n\ndeclare global {\n interface Window {\n __AI_MENU_INTERACTIVE?: boolean\n }\n}\n\nexport const TranslateMenu = ({ onClick }: { onClick: (data: { locale: string }) => void }) => {\n const [show, setShow] = useState(false)\n const closeTimeoutRef = useRef<NodeJS.Timeout | null>(null)\n\n const { enabledLanguages = [] } = useInstructions()\n\n let filteredLocales = locales.all.filter((a) => {\n return a.tag && a.location\n })\n\n if (enabledLanguages?.length) {\n filteredLocales = filteredLocales.filter((a) => enabledLanguages?.includes(a.tag))\n }\n\n const [languages, setLanguages] = useState(filteredLocales)\n const [inputFocus, setInputFocus] = useState(false)\n\n useEffect(() => {\n if (!show) {\n if (typeof window !== 'undefined') {\n window.__AI_MENU_INTERACTIVE = false\n }\n }\n return () => {\n if (closeTimeoutRef.current) {\n clearTimeout(closeTimeoutRef.current)\n }\n if (show && typeof window !== 'undefined') {\n window.__AI_MENU_INTERACTIVE = false\n }\n }\n }, [show])\n\n return (\n <div\n className={`${styles.menu} ai-interactive-menu`}\n data-ai-interactive=\"true\"\n onBlur={(e) => {\n // Only clear if focus moves outside the menu container\n if (!e.currentTarget.contains(e.relatedTarget as Node)) {\n if (typeof window !== 'undefined') window.__AI_MENU_INTERACTIVE = false\n }\n }}\n onFocus={() => {\n if (typeof window !== 'undefined') window.__AI_MENU_INTERACTIVE = true\n }}\n onMouseEnter={() => {\n if (closeTimeoutRef.current) {\n clearTimeout(closeTimeoutRef.current)\n closeTimeoutRef.current = null\n }\n if (typeof window !== 'undefined') window.__AI_MENU_INTERACTIVE = true\n }}\n onMouseLeave={() => {\n if (typeof window !== 'undefined') window.__AI_MENU_INTERACTIVE = false\n if (!inputFocus) {\n closeTimeoutRef.current = setTimeout(() => {\n setShow(false)\n }, 400)\n }\n }}\n >\n <Translate\n isActive={show}\n isMenu\n onClick={() => {\n setShow(!show)\n }}\n />\n <div className={styles.hoverMenu} data-show={show}>\n <div\n className={`${styles.menu} ${styles.subMenu}`}\n style={{\n background: 'var(--popup-bg)',\n // minHeight: '300px',\n }}\n >\n <Item\n onClick={() => {}}\n style={{\n background: 'transparent',\n padding: '0 0 5px 0',\n position: 'sticky',\n top: 0,\n }}\n >\n <input\n className={`${styles.menuInput} ai-interactive-menu`}\n data-ai-interactive=\"true\"\n onBlur={() => setInputFocus(false)}\n onChange={(event) => {\n const value = event.target.value\n setLanguages(\n filteredLocales.filter((l) => {\n const lowerCaseValue = value.toLowerCase()\n return (\n l.name.toLowerCase().startsWith(lowerCaseValue) ||\n (l.location && l.location.toLowerCase().startsWith(lowerCaseValue)) ||\n l.tag.toLowerCase().startsWith(lowerCaseValue)\n )\n }),\n )\n }}\n onFocus={() => setInputFocus(true)}\n placeholder=\"Search...\"\n />\n </Item>\n {languages.map((locale) => {\n return (\n <Item\n className=\"ai-interactive-menu\"\n data-ai-interactive=\"true\"\n key={locale.tag}\n onClick={() => {\n onClick({ locale: locale.tag })\n }}\n >\n <span className={styles.ellipsis}>{`${locale.location} (${locale.tag})`}</span>\n </Item>\n )\n })}\n </div>\n </div>\n </div>\n )\n}\n\nexport const MemoizedTranslateMenu = memo(TranslateMenu)\n"],"names":["locales","React","memo","useEffect","useRef","useState","useInstructions","Item","Translate","styles","TranslateMenu","onClick","show","setShow","closeTimeoutRef","enabledLanguages","filteredLocales","all","filter","a","tag","location","length","includes","languages","setLanguages","inputFocus","setInputFocus","window","__AI_MENU_INTERACTIVE","current","clearTimeout","div","className","menu","data-ai-interactive","onBlur","e","currentTarget","contains","relatedTarget","onFocus","onMouseEnter","onMouseLeave","setTimeout","isActive","isMenu","hoverMenu","data-show","subMenu","style","background","padding","position","top","input","menuInput","onChange","event","value","target","l","lowerCaseValue","toLowerCase","name","startsWith","placeholder","map","locale","span","ellipsis","MemoizedTranslateMenu"],"mappings":";AAAA,OAAOA,aAAa,eAAc;AAClC,OAAOC,SAASC,IAAI,EAAEC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAO;AAEhE,SAASC,eAAe,QAAQ,gEAA+D;AAC/F,SAASC,IAAI,QAAQ,YAAW;AAChC,SAASC,SAAS,QAAQ,aAAY;AACtC,OAAOC,YAAY,qBAAoB;AAQvC,OAAO,MAAMC,gBAAgB,CAAC,EAAEC,OAAO,EAAmD;IACxF,MAAM,CAACC,MAAMC,QAAQ,GAAGR,SAAS;IACjC,MAAMS,kBAAkBV,OAA8B;IAEtD,MAAM,EAAEW,mBAAmB,EAAE,EAAE,GAAGT;IAElC,IAAIU,kBAAkBhB,QAAQiB,GAAG,CAACC,MAAM,CAAC,CAACC;QACxC,OAAOA,EAAEC,GAAG,IAAID,EAAEE,QAAQ;IAC5B;IAEA,IAAIN,kBAAkBO,QAAQ;QAC5BN,kBAAkBA,gBAAgBE,MAAM,CAAC,CAACC,IAAMJ,kBAAkBQ,SAASJ,EAAEC,GAAG;IAClF;IAEA,MAAM,CAACI,WAAWC,aAAa,GAAGpB,SAASW;IAC3C,MAAM,CAACU,YAAYC,cAAc,GAAGtB,SAAS;IAE7CF,UAAU;QACR,IAAI,CAACS,MAAM;YACT,IAAI,OAAOgB,WAAW,aAAa;gBACjCA,OAAOC,qBAAqB,GAAG;YACjC;QACF;QACA,OAAO;YACL,IAAIf,gBAAgBgB,OAAO,EAAE;gBAC3BC,aAAajB,gBAAgBgB,OAAO;YACtC;YACA,IAAIlB,QAAQ,OAAOgB,WAAW,aAAa;gBACzCA,OAAOC,qBAAqB,GAAG;YACjC;QACF;IACF,GAAG;QAACjB;KAAK;IAET,qBACE,MAACoB;QACCC,WAAW,CAAC,EAAExB,OAAOyB,IAAI,CAAC,oBAAoB,CAAC;QAC/CC,uBAAoB;QACpBC,QAAQ,CAACC;YACP,uDAAuD;YACvD,IAAI,CAACA,EAAEC,aAAa,CAACC,QAAQ,CAACF,EAAEG,aAAa,GAAW;gBACtD,IAAI,OAAOZ,WAAW,aAAaA,OAAOC,qBAAqB,GAAG;YACpE;QACF;QACAY,SAAS;YACP,IAAI,OAAOb,WAAW,aAAaA,OAAOC,qBAAqB,GAAG;QACpE;QACAa,cAAc;YACZ,IAAI5B,gBAAgBgB,OAAO,EAAE;gBAC3BC,aAAajB,gBAAgBgB,OAAO;gBACpChB,gBAAgBgB,OAAO,GAAG;YAC5B;YACA,IAAI,OAAOF,WAAW,aAAaA,OAAOC,qBAAqB,GAAG;QACpE;QACAc,cAAc;YACZ,IAAI,OAAOf,WAAW,aAAaA,OAAOC,qBAAqB,GAAG;YAClE,IAAI,CAACH,YAAY;gBACfZ,gBAAgBgB,OAAO,GAAGc,WAAW;oBACnC/B,QAAQ;gBACV,GAAG;YACL;QACF;;0BAEA,KAACL;gBACCqC,UAAUjC;gBACVkC,MAAM;gBACNnC,SAAS;oBACPE,QAAQ,CAACD;gBACX;;0BAEF,KAACoB;gBAAIC,WAAWxB,OAAOsC,SAAS;gBAAEC,aAAWpC;0BAC3C,cAAA,MAACoB;oBACCC,WAAW,CAAC,EAAExB,OAAOyB,IAAI,CAAC,CAAC,EAAEzB,OAAOwC,OAAO,CAAC,CAAC;oBAC7CC,OAAO;wBACLC,YAAY;oBAEd;;sCAEA,KAAC5C;4BACCI,SAAS,KAAO;4BAChBuC,OAAO;gCACLC,YAAY;gCACZC,SAAS;gCACTC,UAAU;gCACVC,KAAK;4BACP;sCAEA,cAAA,KAACC;gCACCtB,WAAW,CAAC,EAAExB,OAAO+C,SAAS,CAAC,oBAAoB,CAAC;gCACpDrB,uBAAoB;gCACpBC,QAAQ,IAAMT,cAAc;gCAC5B8B,UAAU,CAACC;oCACT,MAAMC,QAAQD,MAAME,MAAM,CAACD,KAAK;oCAChClC,aACET,gBAAgBE,MAAM,CAAC,CAAC2C;wCACtB,MAAMC,iBAAiBH,MAAMI,WAAW;wCACxC,OACEF,EAAEG,IAAI,CAACD,WAAW,GAAGE,UAAU,CAACH,mBAC/BD,EAAExC,QAAQ,IAAIwC,EAAExC,QAAQ,CAAC0C,WAAW,GAAGE,UAAU,CAACH,mBACnDD,EAAEzC,GAAG,CAAC2C,WAAW,GAAGE,UAAU,CAACH;oCAEnC;gCAEJ;gCACArB,SAAS,IAAMd,cAAc;gCAC7BuC,aAAY;;;wBAGf1C,UAAU2C,GAAG,CAAC,CAACC;4BACd,qBACE,KAAC7D;gCACC0B,WAAU;gCACVE,uBAAoB;gCAEpBxB,SAAS;oCACPA,QAAQ;wCAAEyD,QAAQA,OAAOhD,GAAG;oCAAC;gCAC/B;0CAEA,cAAA,KAACiD;oCAAKpC,WAAWxB,OAAO6D,QAAQ;8CAAG,CAAC,EAAEF,OAAO/C,QAAQ,CAAC,EAAE,EAAE+C,OAAOhD,GAAG,CAAC,CAAC,CAAC;;+BALlEgD,OAAOhD,GAAG;wBAQrB;;;;;;AAKV,EAAC;AAED,OAAO,MAAMmD,sCAAwBrE,KAAKQ,eAAc"}
@@ -1,11 +1,12 @@
1
1
  import locales from 'locale-codes';
2
- import React, { memo, useState } from 'react';
2
+ import React, { memo, useEffect, useRef, useState } from 'react';
3
3
  import { useInstructions } from '../../../../providers/InstructionsProvider/useInstructions.js';
4
4
  import { Item } from './Item.js';
5
5
  import { Translate } from './items.js';
6
6
  import styles from './menu.module.scss';
7
7
  export const TranslateMenu = ({ onClick }) => {
8
8
  const [show, setShow] = useState(false);
9
+ const closeTimeoutRef = useRef(null);
9
10
  const { enabledLanguages = [] } = useInstructions();
10
11
  let filteredLocales = locales.all.filter((a) => {
11
12
  return a.tag && a.location;
@@ -15,9 +16,44 @@ export const TranslateMenu = ({ onClick }) => {
15
16
  }
16
17
  const [languages, setLanguages] = useState(filteredLocales);
17
18
  const [inputFocus, setInputFocus] = useState(false);
18
- return (<div className={styles.menu} onMouseLeave={() => {
19
+ useEffect(() => {
20
+ if (!show) {
21
+ if (typeof window !== 'undefined') {
22
+ window.__AI_MENU_INTERACTIVE = false;
23
+ }
24
+ }
25
+ return () => {
26
+ if (closeTimeoutRef.current) {
27
+ clearTimeout(closeTimeoutRef.current);
28
+ }
29
+ if (show && typeof window !== 'undefined') {
30
+ window.__AI_MENU_INTERACTIVE = false;
31
+ }
32
+ };
33
+ }, [show]);
34
+ return (<div className={`${styles.menu} ai-interactive-menu`} data-ai-interactive="true" onBlur={(e) => {
35
+ // Only clear if focus moves outside the menu container
36
+ if (!e.currentTarget.contains(e.relatedTarget)) {
37
+ if (typeof window !== 'undefined')
38
+ window.__AI_MENU_INTERACTIVE = false;
39
+ }
40
+ }} onFocus={() => {
41
+ if (typeof window !== 'undefined')
42
+ window.__AI_MENU_INTERACTIVE = true;
43
+ }} onMouseEnter={() => {
44
+ if (closeTimeoutRef.current) {
45
+ clearTimeout(closeTimeoutRef.current);
46
+ closeTimeoutRef.current = null;
47
+ }
48
+ if (typeof window !== 'undefined')
49
+ window.__AI_MENU_INTERACTIVE = true;
50
+ }} onMouseLeave={() => {
51
+ if (typeof window !== 'undefined')
52
+ window.__AI_MENU_INTERACTIVE = false;
19
53
  if (!inputFocus) {
20
- setShow(false);
54
+ closeTimeoutRef.current = setTimeout(() => {
55
+ setShow(false);
56
+ }, 400);
21
57
  }
22
58
  }}>
23
59
  <Translate isActive={show} isMenu onClick={() => {
@@ -34,7 +70,7 @@ export const TranslateMenu = ({ onClick }) => {
34
70
  position: 'sticky',
35
71
  top: 0,
36
72
  }}>
37
- <input className={styles.menuInput} onBlur={() => setInputFocus(false)} onChange={(event) => {
73
+ <input className={`${styles.menuInput} ai-interactive-menu`} data-ai-interactive="true" onBlur={() => setInputFocus(false)} onChange={(event) => {
38
74
  const value = event.target.value;
39
75
  setLanguages(filteredLocales.filter((l) => {
40
76
  const lowerCaseValue = value.toLowerCase();
@@ -45,7 +81,7 @@ export const TranslateMenu = ({ onClick }) => {
45
81
  }} onFocus={() => setInputFocus(true)} placeholder="Search..."/>
46
82
  </Item>
47
83
  {languages.map((locale) => {
48
- return (<Item key={locale.tag} onClick={() => {
84
+ return (<Item className="ai-interactive-menu" data-ai-interactive="true" key={locale.tag} onClick={() => {
49
85
  onClick({ locale: locale.tag });
50
86
  }}>
51
87
  <span className={styles.ellipsis}>{`${locale.location} (${locale.tag})`}</span>
@@ -5,7 +5,8 @@ export const menuItemsMap = [
5
5
  name: 'Proofread',
6
6
  component: Proofread,
7
7
  excludedFor: [
8
- 'upload'
8
+ 'upload',
9
+ 'array'
9
10
  ],
10
11
  loadingText: 'Proofreading'
11
12
  },
@@ -13,7 +14,8 @@ export const menuItemsMap = [
13
14
  name: 'Rephrase',
14
15
  component: Rephrase,
15
16
  excludedFor: [
16
- 'upload'
17
+ 'upload',
18
+ 'array'
17
19
  ],
18
20
  loadingText: 'Rephrasing'
19
21
  },
@@ -21,7 +23,8 @@ export const menuItemsMap = [
21
23
  name: 'Translate',
22
24
  component: MemoizedTranslateMenu,
23
25
  excludedFor: [
24
- 'upload'
26
+ 'upload',
27
+ 'array'
25
28
  ],
26
29
  loadingText: 'Translating'
27
30
  },
@@ -30,7 +33,8 @@ export const menuItemsMap = [
30
33
  component: Expand,
31
34
  excludedFor: [
32
35
  'upload',
33
- 'text'
36
+ 'text',
37
+ 'array'
34
38
  ],
35
39
  loadingText: 'Expanding'
36
40
  },
@@ -41,7 +45,8 @@ export const menuItemsMap = [
41
45
  excludedFor: [
42
46
  'upload',
43
47
  'text',
44
- 'richText'
48
+ 'richText',
49
+ 'array'
45
50
  ],
46
51
  loadingText: 'Summarizing'
47
52
  },
@@ -49,7 +54,8 @@ export const menuItemsMap = [
49
54
  name: 'Simplify',
50
55
  component: Simplify,
51
56
  excludedFor: [
52
- 'upload'
57
+ 'upload',
58
+ 'array'
53
59
  ],
54
60
  loadingText: 'Simplifying'
55
61
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/ui/Compose/hooks/menu/itemsMap.ts"],"sourcesContent":["import type React from 'react'\n\nimport type { ActionMenuItems, BaseItemProps } from '../../../../types.js'\n\nimport { Compose, Expand, Proofread, Rephrase, Settings, Simplify, Summarize } from './items.js'\nimport { MemoizedTranslateMenu, TranslateMenu } from './TranslateMenu.js'\n\ntype MenuItemsMapType = {\n component: React.FC<BaseItemProps>\n excludedFor?: string[]\n loadingText?: string\n name: ActionMenuItems\n}\n\nexport const menuItemsMap: MenuItemsMapType[] = [\n { name: 'Proofread', component: Proofread, excludedFor: ['upload'], loadingText: 'Proofreading' },\n { name: 'Rephrase', component: Rephrase, excludedFor: ['upload'], loadingText: 'Rephrasing' },\n {\n name: 'Translate',\n component: MemoizedTranslateMenu,\n excludedFor: ['upload'],\n loadingText: 'Translating',\n },\n { name: 'Expand', component: Expand, excludedFor: ['upload', 'text'], loadingText: 'Expanding' },\n {\n // Turned off - WIP\n name: 'Summarize',\n component: Summarize,\n excludedFor: ['upload', 'text', 'richText'],\n loadingText: 'Summarizing',\n },\n { name: 'Simplify', component: Simplify, excludedFor: ['upload'], loadingText: 'Simplifying' },\n { name: 'Compose', component: Compose, loadingText: 'Composing' },\n { name: 'Settings', component: Settings },\n]\n"],"names":["Compose","Expand","Proofread","Rephrase","Settings","Simplify","Summarize","MemoizedTranslateMenu","menuItemsMap","name","component","excludedFor","loadingText"],"mappings":"AAIA,SAASA,OAAO,EAAEC,MAAM,EAAEC,SAAS,EAAEC,QAAQ,EAAEC,QAAQ,EAAEC,QAAQ,EAAEC,SAAS,QAAQ,aAAY;AAChG,SAASC,qBAAqB,QAAuB,qBAAoB;AASzE,OAAO,MAAMC,eAAmC;IAC9C;QAAEC,MAAM;QAAaC,WAAWR;QAAWS,aAAa;YAAC;SAAS;QAAEC,aAAa;IAAe;IAChG;QAAEH,MAAM;QAAYC,WAAWP;QAAUQ,aAAa;YAAC;SAAS;QAAEC,aAAa;IAAa;IAC5F;QACEH,MAAM;QACNC,WAAWH;QACXI,aAAa;YAAC;SAAS;QACvBC,aAAa;IACf;IACA;QAAEH,MAAM;QAAUC,WAAWT;QAAQU,aAAa;YAAC;YAAU;SAAO;QAAEC,aAAa;IAAY;IAC/F;QACE,mBAAmB;QACnBH,MAAM;QACNC,WAAWJ;QACXK,aAAa;YAAC;YAAU;YAAQ;SAAW;QAC3CC,aAAa;IACf;IACA;QAAEH,MAAM;QAAYC,WAAWL;QAAUM,aAAa;YAAC;SAAS;QAAEC,aAAa;IAAc;IAC7F;QAAEH,MAAM;QAAWC,WAAWV;QAASY,aAAa;IAAY;IAChE;QAAEH,MAAM;QAAYC,WAAWN;IAAS;CACzC,CAAA"}
1
+ {"version":3,"sources":["../../../../../src/ui/Compose/hooks/menu/itemsMap.ts"],"sourcesContent":["import type React from 'react'\n\nimport type { ActionMenuItems, BaseItemProps } from '../../../../types.js'\n\nimport { Compose, Expand, Proofread, Rephrase, Settings, Simplify, Summarize } from './items.js'\nimport { MemoizedTranslateMenu, TranslateMenu } from './TranslateMenu.js'\n\ntype MenuItemsMapType = {\n component: React.FC<BaseItemProps>\n excludedFor?: string[]\n loadingText?: string\n name: ActionMenuItems\n}\n\nexport const menuItemsMap: MenuItemsMapType[] = [\n { name: 'Proofread', component: Proofread, excludedFor: ['upload', 'array'], loadingText: 'Proofreading' },\n { name: 'Rephrase', component: Rephrase, excludedFor: ['upload', 'array'], loadingText: 'Rephrasing' },\n {\n name: 'Translate',\n component: MemoizedTranslateMenu,\n excludedFor: ['upload', 'array'],\n loadingText: 'Translating',\n },\n { name: 'Expand', component: Expand, excludedFor: ['upload', 'text', 'array'], loadingText: 'Expanding' },\n {\n // Turned off - WIP\n name: 'Summarize',\n component: Summarize,\n excludedFor: ['upload', 'text', 'richText', 'array'],\n loadingText: 'Summarizing',\n },\n { name: 'Simplify', component: Simplify, excludedFor: ['upload', 'array'], loadingText: 'Simplifying' },\n { name: 'Compose', component: Compose, loadingText: 'Composing' },\n { name: 'Settings', component: Settings },\n]\n"],"names":["Compose","Expand","Proofread","Rephrase","Settings","Simplify","Summarize","MemoizedTranslateMenu","menuItemsMap","name","component","excludedFor","loadingText"],"mappings":"AAIA,SAASA,OAAO,EAAEC,MAAM,EAAEC,SAAS,EAAEC,QAAQ,EAAEC,QAAQ,EAAEC,QAAQ,EAAEC,SAAS,QAAQ,aAAY;AAChG,SAASC,qBAAqB,QAAuB,qBAAoB;AASzE,OAAO,MAAMC,eAAmC;IAC9C;QAAEC,MAAM;QAAaC,WAAWR;QAAWS,aAAa;YAAC;YAAU;SAAQ;QAAEC,aAAa;IAAe;IACzG;QAAEH,MAAM;QAAYC,WAAWP;QAAUQ,aAAa;YAAC;YAAU;SAAQ;QAAEC,aAAa;IAAa;IACrG;QACEH,MAAM;QACNC,WAAWH;QACXI,aAAa;YAAC;YAAU;SAAQ;QAChCC,aAAa;IACf;IACA;QAAEH,MAAM;QAAUC,WAAWT;QAAQU,aAAa;YAAC;YAAU;YAAQ;SAAQ;QAAEC,aAAa;IAAY;IACxG;QACE,mBAAmB;QACnBH,MAAM;QACNC,WAAWJ;QACXK,aAAa;YAAC;YAAU;YAAQ;YAAY;SAAQ;QACpDC,aAAa;IACf;IACA;QAAEH,MAAM;QAAYC,WAAWL;QAAUM,aAAa;YAAC;YAAU;SAAQ;QAAEC,aAAa;IAAc;IACtG;QAAEH,MAAM;QAAWC,WAAWV;QAASY,aAAa;IAAY;IAChE;QAAEH,MAAM;QAAYC,WAAWN;IAAS;CACzC,CAAA"}
@@ -26,6 +26,8 @@
26
26
  }
27
27
 
28
28
  .menu {
29
+ --popup-width: 150px;
30
+
29
31
  display: flex;
30
32
  gap: 1px;
31
33
  flex-direction: column;
@@ -49,7 +51,7 @@
49
51
 
50
52
  .subMenu {
51
53
  position: absolute;
52
- left: calc(var(--popup-width) + 12px);
54
+ left: calc(var(--popup-width) + 20px);
53
55
  width: calc(var(--popup-width) + 12px);
54
56
  top: 10px;
55
57
  height: calc(100% - 16px);
@@ -85,6 +87,7 @@
85
87
  color: var(--theme-elevation-800);
86
88
  border-radius: 0;
87
89
  -webkit-appearance: none;
90
+ appearance: none;
88
91
 
89
92
  font-size: inherit !important;
90
93
  height: auto !important;
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- import { useField } from '@payloadcms/ui';
3
+ import { useForm } from '@payloadcms/ui';
4
+ import { getSiblingData } from 'payload/shared';
4
5
  import React, { useEffect, useMemo, useState } from 'react';
5
6
  import { useFieldProps } from '../../../../providers/FieldProvider/useFieldProps.js';
6
7
  import { Compose, Proofread, Rephrase } from './items.js';
@@ -19,14 +20,27 @@ const getActiveComponent = (ac)=>{
19
20
  }
20
21
  };
21
22
  export const useMenu = (menuEvents, options)=>{
22
- const { field: { type: fieldType } = {}, path: pathFromContext } = useFieldProps();
23
- const field = useField({
24
- path: pathFromContext ?? ''
25
- });
23
+ const { field: { type: fieldType } = {}, path } = useFieldProps();
24
+ const { getData } = useForm();
26
25
  const [activeComponent, setActiveComponent] = useState('Rephrase');
27
- const { initialValue, value } = field;
26
+ // Check value once on mount or when path/type changes
28
27
  useEffect(()=>{
29
- if (!value) {
28
+ let hasValue = false;
29
+ try {
30
+ const data = getData();
31
+ if (path) {
32
+ const val = getSiblingData(data, path);
33
+ hasValue = val !== undefined && val !== null;
34
+ // For richTextFields, we might need a more robust check (e.g. check for root.children.length > 0)
35
+ // But for now, simple truthiness covers most cases or at least defaults safely
36
+ if (fieldType === 'richText' && val && typeof val === 'object' && 'root' in val) {
37
+ // Basic lexical check could go here if needed
38
+ }
39
+ }
40
+ } catch (e) {
41
+ // ignore
42
+ }
43
+ if (!hasValue) {
30
44
  setActiveComponent('Compose');
31
45
  return;
32
46
  }
@@ -34,15 +48,12 @@ export const useMenu = (menuEvents, options)=>{
34
48
  setActiveComponent('Compose');
35
49
  return;
36
50
  }
37
- if (typeof value === 'string' && value !== initialValue) {
38
- setActiveComponent('Proofread');
39
- } else {
40
- setActiveComponent('Rephrase');
41
- }
51
+ // Default to Rephrase if value exists
52
+ setActiveComponent('Rephrase');
42
53
  }, [
43
- initialValue,
44
- value,
45
- fieldType
54
+ fieldType,
55
+ getData,
56
+ path
46
57
  ]);
47
58
  const MemoizedActiveComponent = useMemo(()=>{
48
59
  return ({ isLoading, loadingLabel, stop })=>{
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/ui/Compose/hooks/menu/useMenu.tsx"],"sourcesContent":["'use client'\n\nimport { useField } from '@payloadcms/ui'\nimport React, { useEffect, useMemo, useState } from 'react'\n\nimport type { ActionMenuItems, UseMenuEvents, UseMenuOptions } from '../../../../types.js'\n\nimport { useFieldProps } from '../../../../providers/FieldProvider/useFieldProps.js'\nimport { Compose, Proofread, Rephrase } from './items.js'\nimport { menuItemsMap } from './itemsMap.js'\nimport styles from './menu.module.scss'\n\nconst getActiveComponent = (ac: ActionMenuItems) => {\n switch (ac) {\n case 'Compose':\n return Compose\n case 'Proofread':\n return Proofread\n case 'Rephrase':\n return Rephrase\n default:\n return Rephrase\n }\n}\n\nexport const useMenu = (menuEvents: UseMenuEvents, options: UseMenuOptions) => {\n const { field:{ type: fieldType } = {}, path: pathFromContext } = useFieldProps()\n const field = useField({ path: pathFromContext ?? '' })\n const [activeComponent, setActiveComponent] = useState<ActionMenuItems>('Rephrase')\n\n const { initialValue, value } = field\n\n useEffect(() => {\n if (!value) {\n setActiveComponent('Compose')\n return\n }\n\n if (menuItemsMap.some((i) => i.excludedFor?.includes(fieldType ?? ''))) {\n setActiveComponent('Compose')\n return\n }\n\n if (typeof value === 'string' && value !== initialValue) {\n setActiveComponent('Proofread')\n } else {\n setActiveComponent('Rephrase')\n }\n }, [initialValue, value, fieldType])\n\n const MemoizedActiveComponent = useMemo(() => {\n return ({ isLoading, loadingLabel, stop }: { isLoading: boolean; loadingLabel?: string; stop: () => void }) => {\n const ActiveComponent = getActiveComponent(activeComponent)\n const activeItem = menuItemsMap.find((i) => i.name === activeComponent)!\n return (\n <ActiveComponent\n hideIcon\n onClick={(data: unknown) => {\n if (!isLoading) {\n const trigger = menuEvents[`on${activeComponent}`]\n if (typeof trigger === 'function') {\n trigger(data)\n } else {\n console.error('No trigger found for', activeComponent)\n }\n } else {\n stop()\n }\n }}\n title={isLoading ? 'Click to stop' : activeItem.name}\n >\n {isLoading && (loadingLabel ?? activeItem.loadingText)}\n </ActiveComponent>\n )\n }\n }, [activeComponent, menuEvents])\n\n const filteredMenuItems = useMemo(\n () =>\n menuItemsMap.filter((i) => {\n if (i.name === 'Settings' && !options.isConfigAllowed) {\n return false\n } // Disable settings if a user role is not permitted\n return i.name !== activeComponent && !i.excludedFor?.includes(fieldType ?? '')\n }),\n [activeComponent, fieldType, options.isConfigAllowed],\n )\n\n const MemoizedMenu = useMemo(() => {\n return ({ isLoading, onClose }: { isLoading: boolean; onClose: () => void }) => (\n <div className={styles.menu}>\n {filteredMenuItems.map((i) => {\n const Action = i.component\n return (\n <Action\n disabled={isLoading}\n key={i.name}\n onClick={(data: unknown) => {\n if (i.name !== 'Settings') {\n setActiveComponent(i.name)\n }\n\n menuEvents[`on${i.name}`]?.(data)\n onClose()\n }}\n >\n {isLoading && i.loadingText}\n </Action>\n )\n })}\n </div>\n )\n }, [filteredMenuItems, menuEvents])\n\n return {\n ActiveComponent: MemoizedActiveComponent,\n Menu: MemoizedMenu,\n }\n}\n"],"names":["useField","React","useEffect","useMemo","useState","useFieldProps","Compose","Proofread","Rephrase","menuItemsMap","styles","getActiveComponent","ac","useMenu","menuEvents","options","field","type","fieldType","path","pathFromContext","activeComponent","setActiveComponent","initialValue","value","some","i","excludedFor","includes","MemoizedActiveComponent","isLoading","loadingLabel","stop","ActiveComponent","activeItem","find","name","hideIcon","onClick","data","trigger","console","error","title","loadingText","filteredMenuItems","filter","isConfigAllowed","MemoizedMenu","onClose","div","className","menu","map","Action","component","disabled","Menu"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../src/ui/Compose/hooks/menu/useMenu.tsx"],"sourcesContent":["'use client'\n\nimport { useForm } from '@payloadcms/ui'\nimport { getSiblingData } from 'payload/shared'\nimport React, { useEffect, useMemo, useState } from 'react'\n\nimport type { ActionMenuItems, UseMenuEvents, UseMenuOptions } from '../../../../types.js'\n\nimport { useFieldProps } from '../../../../providers/FieldProvider/useFieldProps.js'\nimport { Compose, Proofread, Rephrase } from './items.js'\nimport { menuItemsMap } from './itemsMap.js'\nimport styles from './menu.module.scss'\n\nconst getActiveComponent = (ac: ActionMenuItems) => {\n switch (ac) {\n case 'Compose':\n return Compose\n case 'Proofread':\n return Proofread\n case 'Rephrase':\n return Rephrase\n default:\n return Rephrase\n }\n}\n\nexport const useMenu = (menuEvents: UseMenuEvents, options: UseMenuOptions) => {\n const { field: { type: fieldType } = {}, path } = useFieldProps()\n const { getData } = useForm()\n const [activeComponent, setActiveComponent] = useState<ActionMenuItems>('Rephrase')\n\n // Check value once on mount or when path/type changes\n useEffect(() => {\n let hasValue = false\n\n try {\n const data = getData()\n if (path) {\n const val = getSiblingData(data, path)\n hasValue = val !== undefined && val !== null\n // For richTextFields, we might need a more robust check (e.g. check for root.children.length > 0)\n // But for now, simple truthiness covers most cases or at least defaults safely\n if (fieldType === 'richText' && val && typeof val === 'object' && 'root' in val) {\n // Basic lexical check could go here if needed\n }\n }\n } catch (e) {\n // ignore\n }\n\n if (!hasValue) {\n setActiveComponent('Compose')\n return\n }\n\n if (menuItemsMap.some((i) => i.excludedFor?.includes(fieldType ?? ''))) {\n setActiveComponent('Compose')\n return\n }\n\n // Default to Rephrase if value exists\n setActiveComponent('Rephrase')\n }, [fieldType, getData, path])\n\n const MemoizedActiveComponent = useMemo(() => {\n return ({ isLoading, loadingLabel, stop }: { isLoading: boolean; loadingLabel?: string; stop: () => void }) => {\n const ActiveComponent = getActiveComponent(activeComponent)\n const activeItem = menuItemsMap.find((i) => i.name === activeComponent)!\n return (\n <ActiveComponent\n hideIcon\n onClick={(data: unknown) => {\n if (!isLoading) {\n const trigger = menuEvents[`on${activeComponent}`]\n if (typeof trigger === 'function') {\n trigger(data)\n } else {\n console.error('No trigger found for', activeComponent)\n }\n } else {\n stop()\n }\n }}\n title={isLoading ? 'Click to stop' : activeItem.name}\n >\n {isLoading && (loadingLabel ?? activeItem.loadingText)}\n </ActiveComponent>\n )\n }\n }, [activeComponent, menuEvents])\n\n const filteredMenuItems = useMemo(\n () =>\n menuItemsMap.filter((i) => {\n if (i.name === 'Settings' && !options.isConfigAllowed) {\n return false\n } // Disable settings if a user role is not permitted\n return i.name !== activeComponent && !i.excludedFor?.includes(fieldType ?? '')\n }),\n [activeComponent, fieldType, options.isConfigAllowed],\n )\n\n const MemoizedMenu = useMemo(() => {\n return ({ isLoading, onClose }: { isLoading: boolean; onClose: () => void }) => (\n <div className={styles.menu}>\n {filteredMenuItems.map((i) => {\n const Action = i.component\n return (\n <Action\n disabled={isLoading}\n key={i.name}\n onClick={(data: unknown) => {\n if (i.name !== 'Settings') {\n setActiveComponent(i.name)\n }\n\n menuEvents[`on${i.name}`]?.(data)\n onClose()\n }}\n >\n {isLoading && i.loadingText}\n </Action>\n )\n })}\n </div>\n )\n }, [filteredMenuItems, menuEvents])\n\n return {\n ActiveComponent: MemoizedActiveComponent,\n Menu: MemoizedMenu,\n }\n}\n\n"],"names":["useForm","getSiblingData","React","useEffect","useMemo","useState","useFieldProps","Compose","Proofread","Rephrase","menuItemsMap","styles","getActiveComponent","ac","useMenu","menuEvents","options","field","type","fieldType","path","getData","activeComponent","setActiveComponent","hasValue","data","val","undefined","e","some","i","excludedFor","includes","MemoizedActiveComponent","isLoading","loadingLabel","stop","ActiveComponent","activeItem","find","name","hideIcon","onClick","trigger","console","error","title","loadingText","filteredMenuItems","filter","isConfigAllowed","MemoizedMenu","onClose","div","className","menu","map","Action","component","disabled","Menu"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  'use client';
2
- import { useField } from '@payloadcms/ui';
2
+ import { useForm } from '@payloadcms/ui';
3
+ import { getSiblingData } from 'payload/shared';
3
4
  import React, { useEffect, useMemo, useState } from 'react';
4
5
  import { useFieldProps } from '../../../../providers/FieldProvider/useFieldProps.js';
5
6
  import { Compose, Proofread, Rephrase } from './items.js';
@@ -18,12 +19,28 @@ const getActiveComponent = (ac) => {
18
19
  }
19
20
  };
20
21
  export const useMenu = (menuEvents, options) => {
21
- const { field: { type: fieldType } = {}, path: pathFromContext } = useFieldProps();
22
- const field = useField({ path: pathFromContext ?? '' });
22
+ const { field: { type: fieldType } = {}, path } = useFieldProps();
23
+ const { getData } = useForm();
23
24
  const [activeComponent, setActiveComponent] = useState('Rephrase');
24
- const { initialValue, value } = field;
25
+ // Check value once on mount or when path/type changes
25
26
  useEffect(() => {
26
- if (!value) {
27
+ let hasValue = false;
28
+ try {
29
+ const data = getData();
30
+ if (path) {
31
+ const val = getSiblingData(data, path);
32
+ hasValue = val !== undefined && val !== null;
33
+ // For richTextFields, we might need a more robust check (e.g. check for root.children.length > 0)
34
+ // But for now, simple truthiness covers most cases or at least defaults safely
35
+ if (fieldType === 'richText' && val && typeof val === 'object' && 'root' in val) {
36
+ // Basic lexical check could go here if needed
37
+ }
38
+ }
39
+ }
40
+ catch (e) {
41
+ // ignore
42
+ }
43
+ if (!hasValue) {
27
44
  setActiveComponent('Compose');
28
45
  return;
29
46
  }
@@ -31,13 +48,9 @@ export const useMenu = (menuEvents, options) => {
31
48
  setActiveComponent('Compose');
32
49
  return;
33
50
  }
34
- if (typeof value === 'string' && value !== initialValue) {
35
- setActiveComponent('Proofread');
36
- }
37
- else {
38
- setActiveComponent('Rephrase');
39
- }
40
- }, [initialValue, value, fieldType]);
51
+ // Default to Rephrase if value exists
52
+ setActiveComponent('Rephrase');
53
+ }, [fieldType, getData, path]);
41
54
  const MemoizedActiveComponent = useMemo(() => {
42
55
  return ({ isLoading, loadingLabel, stop }) => {
43
56
  const ActiveComponent = getActiveComponent(activeComponent);
@@ -15,6 +15,8 @@ const fieldTypeCache = new WeakMap();
15
15
  let pointerDownThrottleTimer = null;
16
16
  let focusDebounceTimer = null;
17
17
  let currentContainer = null;
18
+ let lastContainer = null // Track last valid container to restore if needed
19
+ ;
18
20
  let rafId = null // Track RAF to cancel if needed
19
21
  ;
20
22
  /**
@@ -106,6 +108,8 @@ let rafId = null // Track RAF to cancel if needed
106
108
  currentContainer?.classList.remove('ai-plugin-active');
107
109
  if (next) {
108
110
  next.classList.add('ai-plugin-active');
111
+ lastContainer = next // Update last known valid container
112
+ ;
109
113
  }
110
114
  currentContainer = next;
111
115
  };
@@ -113,6 +117,7 @@ const clearActiveContainer = ()=>{
113
117
  if (currentContainer) {
114
118
  currentContainer.classList.remove('ai-plugin-active');
115
119
  currentContainer = null;
120
+ // Note: We do NOT clear lastContainer here, allowing restoration
116
121
  }
117
122
  // Cancel any pending RAF
118
123
  if (rafId !== null) {
@@ -147,6 +152,23 @@ const isInteractiveElement = (element)=>{
147
152
  }
148
153
  return false;
149
154
  };
155
+ // Helper for interactive menu check
156
+ const checkInteractiveMenu = (e)=>{
157
+ // Check global flag first (most reliable for mouse/hover interactions)
158
+ if (typeof window !== 'undefined' && window.__AI_MENU_INTERACTIVE) {
159
+ return true;
160
+ }
161
+ const target = e.target;
162
+ // Check target directly
163
+ if (target && target instanceof Element && (target.classList.contains('ai-interactive-menu') || target.hasAttribute('data-ai-interactive'))) {
164
+ return true;
165
+ }
166
+ // Fallback: Check DOM path (for keyboard or specific events)
167
+ const path = e.composedPath();
168
+ return path.some((el)=>{
169
+ return el instanceof Element && (el.classList.contains('ai-interactive-menu') || el.hasAttribute('data-ai-interactive'));
170
+ });
171
+ };
150
172
  /**
151
173
  * Handle focus events - only activate if focus is on an interactive element within .field-type
152
174
  * Performance: Debounced by 10ms to handle rapid focus changes
@@ -163,6 +185,14 @@ const isInteractiveElement = (element)=>{
163
185
  if (!isInteractiveElement(target)) {
164
186
  return;
165
187
  }
188
+ // Check for interactive menu elements using composedPath for robustness
189
+ if (typeof window !== 'undefined' && window.__AI_MENU_INTERACTIVE || checkInteractiveMenu(e)) {
190
+ // If we lost the active state (e.g. due to pointerDown clearing it), restore it
191
+ if (!currentContainer && lastContainer?.isConnected) {
192
+ setActiveContainer(lastContainer);
193
+ }
194
+ return;
195
+ }
166
196
  // Clear any pending debounce
167
197
  if (focusDebounceTimer !== null) {
168
198
  clearTimeout(focusDebounceTimer);
@@ -182,6 +212,10 @@ const isInteractiveElement = (element)=>{
182
212
  if (!(target instanceof HTMLElement)) {
183
213
  return;
184
214
  }
215
+ // Check for interactive menu elements using composedPath
216
+ if (typeof window !== 'undefined' && window.__AI_MENU_INTERACTIVE || checkInteractiveMenu(e)) {
217
+ return;
218
+ }
185
219
  // Early exit if clicking within current container
186
220
  if (currentContainer?.isConnected && currentContainer.contains(target)) {
187
221
  return;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/ui/Compose/hooks/useActiveFieldTracking.ts"],"sourcesContent":["'use client'\n\nimport { useEffect } from 'react'\n\n/**\n * Allowed field type classes that should show the active state\n */\nconst ALLOWED_FIELD_TYPES = ['upload', 'text', 'textarea', 'rich-text-lexical']\n\n// Performance optimization: Cache container and field type lookups\nconst containerCache = new WeakMap<HTMLElement, HTMLElement | null>()\nconst fieldTypeCache = new WeakMap<HTMLElement, boolean>()\n\n// Performance optimization: Throttle/debounce timers\nlet pointerDownThrottleTimer: null | number = null\nlet focusDebounceTimer: null | number = null\n\nlet currentContainer: HTMLElement | null = null\nlet rafId: null | number = null // Track RAF to cancel if needed\n\n/**\n * Safely escape CSS selector values\n */\nconst cssEscape = (value: string): string => {\n if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') {\n return CSS.escape(value)\n }\n return value.replace(/([ #;?%&,.+*~':\"!^$[\\]()=>|/@])/g, '\\\\$1')\n}\n\n/**\n * Find container from React Select dropdown elements\n * Performance: Early exit if not in a listbox/option element\n */\nconst findContainerFromReactSelect = (target: HTMLElement): HTMLElement | null => {\n // Early exit if element doesn't have role indicator for React Select\n const role = target.getAttribute('role')\n if (!role || !['listbox', 'option'].includes(role)) {\n return null\n }\n\n const listbox = target.closest<HTMLElement>('[role=\"listbox\"]')\n if (!listbox?.id) {\n return null\n }\n\n const id = cssEscape(listbox.id)\n const selector = `[aria-controls=\"${id}\"], [aria-owns=\"${id}\"]`\n const control = document.querySelector<HTMLElement>(selector)\n\n return control?.closest<HTMLElement>('.field-type') ?? null\n}\n\n/**\n * Check if a container has one of the allowed field type classes\n * Performance: Uses WeakMap cache to avoid repeated class list checks\n */\nconst isAllowedFieldType = (container: HTMLElement): boolean => {\n // Check cache first\n if (fieldTypeCache.has(container)) {\n return fieldTypeCache.get(container)!\n }\n\n // Compute and cache result\n const result = ALLOWED_FIELD_TYPES.some(\n (type) =>\n container.classList.contains(type) || container.classList.contains(`field-type-${type}`),\n )\n\n fieldTypeCache.set(container, result)\n return result\n}\n\n/**\n * Resolve the .field-type container for a given event target\n * Only returns containers that match allowed field types\n * Performance: Uses WeakMap cache to avoid repeated DOM traversals\n */\nconst resolveContainerFromTarget = (target: EventTarget | null): HTMLElement | null => {\n if (!(target instanceof HTMLElement)) {\n return null\n }\n\n // Check cache first\n if (containerCache.has(target)) {\n const cached = containerCache.get(target)!\n // Validate cache entry is still in DOM\n if (!cached || cached.isConnected) {\n return cached\n }\n // Invalidate stale cache entry\n containerCache.delete(target)\n }\n\n // Perform lookup\n let container = target.closest<HTMLElement>('.field-type')\n\n // Fall back to React Select logic if needed\n if (!container) {\n container = findContainerFromReactSelect(target)\n }\n\n // Validate field type and cache result\n const result = container && isAllowedFieldType(container) ? container : null\n containerCache.set(target, result)\n\n return result\n}\n\n/**\n * Update the active container and toggle CSS class\n * - Avoids acting on disconnected nodes\n * - Avoids redundant class work\n */\nconst setActiveContainer = (next: HTMLElement | null): void => {\n // Normalize both references against disconnected nodes\n if (currentContainer && !currentContainer.isConnected) {\n currentContainer = null\n }\n if (next && !next.isConnected) {\n next = null\n }\n\n if (currentContainer === next) {\n return\n }\n\n currentContainer?.classList.remove('ai-plugin-active')\n if (next) {\n next.classList.add('ai-plugin-active')\n }\n currentContainer = next\n}\n\nconst clearActiveContainer = (): void => {\n if (currentContainer) {\n currentContainer.classList.remove('ai-plugin-active')\n currentContainer = null\n }\n\n // Cancel any pending RAF\n if (rafId !== null) {\n cancelAnimationFrame(rafId)\n rafId = null\n }\n}\n\nconst isInteractiveElement = (element: HTMLElement): boolean => {\n const tagName = element.tagName.toLowerCase()\n const interactiveTags = ['input', 'textarea', 'select', 'button']\n\n if (interactiveTags.includes(tagName)) {\n return true\n }\n\n // Check for contenteditable\n if (element.isContentEditable) {\n return true\n }\n\n // Check for elements with role=\"textbox\" or role=\"combobox\" (React Select)\n const role = element.getAttribute('role')\n if (role && ['combobox', 'listbox', 'searchbox', 'textbox'].includes(role)) {\n return true\n }\n\n return false\n}\n\n/**\n * Handle focus events - only activate if focus is on an interactive element within .field-type\n * Performance: Debounced by 10ms to handle rapid focus changes\n */\nconst onFocusIn = (e: FocusEvent): void => {\n const target = e.target\n if (!(target instanceof HTMLElement)) {\n return\n }\n\n // Early exit if we're already inside the current container\n if (currentContainer?.isConnected && currentContainer.contains(target)) {\n return\n }\n\n // Only activate if the focused element is actually interactive\n if (!isInteractiveElement(target)) {\n return\n }\n\n // Clear any pending debounce\n if (focusDebounceTimer !== null) {\n clearTimeout(focusDebounceTimer)\n }\n\n // Debounce to reduce work during rapid focus changes (e.g., fast tabbing)\n focusDebounceTimer = window.setTimeout(() => {\n focusDebounceTimer = null\n const container = resolveContainerFromTarget(target)\n setActiveContainer(container)\n }, 10)\n}\n\n/**\n * Handle pointer/mouse events - only switch when clicking a different .field-type\n * Performance: Early exit for non-field clicks + 50ms throttling\n */\nconst onPointerDown = (e: PointerEvent): void => {\n const target = e.target\n if (!(target instanceof HTMLElement)) {\n return\n }\n\n // Early exit if clicking within current container\n if (currentContainer?.isConnected && currentContainer.contains(target)) {\n return\n }\n\n // Performance: Quick check before expensive traversal\n // If click is nowhere near a field, just clear active state\n if (!target.closest('.field-type')) {\n if (currentContainer) {\n setActiveContainer(null)\n }\n return\n }\n\n // Throttle to prevent excessive work on rapid clicking\n if (pointerDownThrottleTimer !== null) {\n return\n }\n\n const container = resolveContainerFromTarget(target)\n setActiveContainer(container)\n\n // Set throttle timer for 50ms\n pointerDownThrottleTimer = window.setTimeout(() => {\n pointerDownThrottleTimer = null\n }, 50)\n}\n\n/**\n * Handle keyboard navigation (Tab key)\n */\nconst onKeyDown = (e: KeyboardEvent): void => {\n if (e.key !== 'Tab') {\n return\n }\n\n // Cancel any pending RAF to prevent queuing\n if (rafId !== null) {\n cancelAnimationFrame(rafId)\n }\n\n // Defer until after focus has shifted\n rafId = requestAnimationFrame(() => {\n rafId = null\n const container = resolveContainerFromTarget(document.activeElement)\n setActiveContainer(container)\n })\n}\n\n/**\n * Handle visibility changes to properly cleanup when page is hidden\n */\nconst onVisibilityChange = (): void => {\n if (typeof document !== 'undefined' && document.hidden) {\n // Clear active state and cancel pending operations\n clearActiveContainer()\n }\n}\n\n/**\n * Initialize document-level listeners to track the active field container.\n * When a container is active, it receives the 'ai-plugin-active' class.\n */\nexport const useActiveFieldTracking = (): void => {\n useEffect(() => {\n if (typeof window === 'undefined') {\n return\n }\n\n const pluginWindow = window as {\n __aiComposeTracking?: boolean\n __aiComposeTrackingController?: AbortController\n __aiComposeTrackingCount?: number\n } & Window\n\n // Track number of mounted users of the hook\n pluginWindow.__aiComposeTrackingCount = (pluginWindow.__aiComposeTrackingCount ?? 0) + 1\n\n // Initialize listeners only once\n if (!pluginWindow.__aiComposeTracking) {\n const controller = new AbortController()\n pluginWindow.__aiComposeTrackingController = controller\n\n // Use capture for early handling\n document.addEventListener('focusin', onFocusIn, {\n capture: true,\n signal: controller.signal,\n })\n document.addEventListener('pointerdown', onPointerDown, {\n capture: true,\n passive: true,\n signal: controller.signal,\n })\n document.addEventListener('keydown', onKeyDown, {\n capture: true,\n signal: controller.signal,\n })\n document.addEventListener('visibilitychange', onVisibilityChange, {\n signal: controller.signal,\n })\n\n pluginWindow.__aiComposeTracking = true\n }\n\n return () => {\n // Decrement and cleanup when the last user unmounts\n pluginWindow.__aiComposeTrackingCount = (pluginWindow.__aiComposeTrackingCount ?? 1) - 1\n\n if ((pluginWindow.__aiComposeTrackingCount ?? 0) <= 0) {\n // Atomically remove all listeners\n pluginWindow.__aiComposeTrackingController?.abort()\n pluginWindow.__aiComposeTrackingController = undefined\n\n // Clear active state and cancel pending operations\n clearActiveContainer()\n\n // Reset all state\n pluginWindow.__aiComposeTracking = false\n pluginWindow.__aiComposeTrackingCount = 0\n }\n }\n }, [])\n}\n"],"names":["useEffect","ALLOWED_FIELD_TYPES","containerCache","WeakMap","fieldTypeCache","pointerDownThrottleTimer","focusDebounceTimer","currentContainer","rafId","cssEscape","value","CSS","escape","replace","findContainerFromReactSelect","target","role","getAttribute","includes","listbox","closest","id","selector","control","document","querySelector","isAllowedFieldType","container","has","get","result","some","type","classList","contains","set","resolveContainerFromTarget","HTMLElement","cached","isConnected","delete","setActiveContainer","next","remove","add","clearActiveContainer","cancelAnimationFrame","isInteractiveElement","element","tagName","toLowerCase","interactiveTags","isContentEditable","onFocusIn","e","clearTimeout","window","setTimeout","onPointerDown","onKeyDown","key","requestAnimationFrame","activeElement","onVisibilityChange","hidden","useActiveFieldTracking","pluginWindow","__aiComposeTrackingCount","__aiComposeTracking","controller","AbortController","__aiComposeTrackingController","addEventListener","capture","signal","passive","abort","undefined"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/ui/Compose/hooks/useActiveFieldTracking.ts"],"sourcesContent":["'use client'\n\nimport { useEffect } from 'react'\n\n/**\n * Allowed field type classes that should show the active state\n */\nconst ALLOWED_FIELD_TYPES = ['upload', 'text', 'textarea', 'rich-text-lexical']\n\n// Performance optimization: Cache container and field type lookups\nconst containerCache = new WeakMap<HTMLElement, HTMLElement | null>()\nconst fieldTypeCache = new WeakMap<HTMLElement, boolean>()\n\n// Performance optimization: Throttle/debounce timers\nlet pointerDownThrottleTimer: null | number = null\nlet focusDebounceTimer: null | number = null\n\nlet currentContainer: HTMLElement | null = null\nlet lastContainer: HTMLElement | null = null // Track last valid container to restore if needed\nlet rafId: null | number = null // Track RAF to cancel if needed\n\n/**\n * Safely escape CSS selector values\n */\nconst cssEscape = (value: string): string => {\n if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') {\n return CSS.escape(value)\n }\n return value.replace(/([ #;?%&,.+*~':\"!^$[\\]()=>|/@])/g, '\\\\$1')\n}\n\n/**\n * Find container from React Select dropdown elements\n * Performance: Early exit if not in a listbox/option element\n */\nconst findContainerFromReactSelect = (target: HTMLElement): HTMLElement | null => {\n // Early exit if element doesn't have role indicator for React Select\n const role = target.getAttribute('role')\n if (!role || !['listbox', 'option'].includes(role)) {\n return null\n }\n\n const listbox = target.closest<HTMLElement>('[role=\"listbox\"]')\n if (!listbox?.id) {\n return null\n }\n\n const id = cssEscape(listbox.id)\n const selector = `[aria-controls=\"${id}\"], [aria-owns=\"${id}\"]`\n const control = document.querySelector<HTMLElement>(selector)\n\n return control?.closest<HTMLElement>('.field-type') ?? null\n}\n\n/**\n * Check if a container has one of the allowed field type classes\n * Performance: Uses WeakMap cache to avoid repeated class list checks\n */\nconst isAllowedFieldType = (container: HTMLElement): boolean => {\n // Check cache first\n if (fieldTypeCache.has(container)) {\n return fieldTypeCache.get(container)!\n }\n\n // Compute and cache result\n const result = ALLOWED_FIELD_TYPES.some(\n (type) =>\n container.classList.contains(type) || container.classList.contains(`field-type-${type}`),\n )\n\n fieldTypeCache.set(container, result)\n return result\n}\n\n/**\n * Resolve the .field-type container for a given event target\n * Only returns containers that match allowed field types\n * Performance: Uses WeakMap cache to avoid repeated DOM traversals\n */\nconst resolveContainerFromTarget = (target: EventTarget | null): HTMLElement | null => {\n if (!(target instanceof HTMLElement)) {\n return null\n }\n\n // Check cache first\n if (containerCache.has(target)) {\n const cached = containerCache.get(target)!\n // Validate cache entry is still in DOM\n if (!cached || cached.isConnected) {\n return cached\n }\n // Invalidate stale cache entry\n containerCache.delete(target)\n }\n\n // Perform lookup\n let container = target.closest<HTMLElement>('.field-type')\n\n // Fall back to React Select logic if needed\n if (!container) {\n container = findContainerFromReactSelect(target)\n }\n\n // Validate field type and cache result\n const result = container && isAllowedFieldType(container) ? container : null\n containerCache.set(target, result)\n\n return result\n}\n\n/**\n * Update the active container and toggle CSS class\n * - Avoids acting on disconnected nodes\n * - Avoids redundant class work\n */\nconst setActiveContainer = (next: HTMLElement | null): void => {\n // Normalize both references against disconnected nodes\n if (currentContainer && !currentContainer.isConnected) {\n currentContainer = null\n }\n if (next && !next.isConnected) {\n next = null\n }\n\n if (currentContainer === next) {\n return\n }\n\n currentContainer?.classList.remove('ai-plugin-active')\n if (next) {\n next.classList.add('ai-plugin-active')\n lastContainer = next // Update last known valid container\n }\n currentContainer = next\n}\n\nconst clearActiveContainer = (): void => {\n if (currentContainer) {\n currentContainer.classList.remove('ai-plugin-active')\n currentContainer = null\n // Note: We do NOT clear lastContainer here, allowing restoration\n }\n\n // Cancel any pending RAF\n if (rafId !== null) {\n cancelAnimationFrame(rafId)\n rafId = null\n }\n}\n\nconst isInteractiveElement = (element: HTMLElement): boolean => {\n const tagName = element.tagName.toLowerCase()\n const interactiveTags = ['input', 'textarea', 'select', 'button']\n\n if (interactiveTags.includes(tagName)) {\n return true\n }\n\n // Check for contenteditable\n if (element.isContentEditable) {\n return true\n }\n\n // Check for elements with role=\"textbox\" or role=\"combobox\" (React Select)\n const role = element.getAttribute('role')\n if (role && ['combobox', 'listbox', 'searchbox', 'textbox'].includes(role)) {\n return true\n }\n\n return false\n}\n\n// Helper for interactive menu check\nconst checkInteractiveMenu = (e: Event): boolean => {\n // Check global flag first (most reliable for mouse/hover interactions)\n if (typeof window !== 'undefined' && window.__AI_MENU_INTERACTIVE) {\n return true\n }\n\n const target = e.target as Element\n\n // Check target directly\n if (\n target &&\n target instanceof Element &&\n (target.classList.contains('ai-interactive-menu') || target.hasAttribute('data-ai-interactive'))\n ) {\n return true\n }\n\n // Fallback: Check DOM path (for keyboard or specific events)\n const path = e.composedPath()\n return path.some((el) => {\n return (\n el instanceof Element &&\n (el.classList.contains('ai-interactive-menu') || el.hasAttribute('data-ai-interactive'))\n )\n })\n}\n\n/**\n * Handle focus events - only activate if focus is on an interactive element within .field-type\n * Performance: Debounced by 10ms to handle rapid focus changes\n */\nconst onFocusIn = (e: FocusEvent): void => {\n const target = e.target\n if (!(target instanceof HTMLElement)) {\n return\n }\n\n // Early exit if we're already inside the current container\n if (currentContainer?.isConnected && currentContainer.contains(target)) {\n return\n }\n\n // Only activate if the focused element is actually interactive\n if (!isInteractiveElement(target)) {\n return\n }\n\n // Check for interactive menu elements using composedPath for robustness\n if (typeof window !== 'undefined' && window.__AI_MENU_INTERACTIVE || checkInteractiveMenu(e)) {\n // If we lost the active state (e.g. due to pointerDown clearing it), restore it\n if (!currentContainer && lastContainer?.isConnected) {\n setActiveContainer(lastContainer)\n }\n return\n }\n\n // Clear any pending debounce\n if (focusDebounceTimer !== null) {\n clearTimeout(focusDebounceTimer)\n }\n\n // Debounce to reduce work during rapid focus changes (e.g., fast tabbing)\n focusDebounceTimer = window.setTimeout(() => {\n focusDebounceTimer = null\n const container = resolveContainerFromTarget(target)\n setActiveContainer(container)\n }, 10)\n}\n\n/**\n * Handle pointer/mouse events - only switch when clicking a different .field-type\n * Performance: Early exit for non-field clicks + 50ms throttling\n */\nconst onPointerDown = (e: PointerEvent): void => {\n const target = e.target\n if (!(target instanceof HTMLElement)) {\n return\n }\n\n // Check for interactive menu elements using composedPath\n if (typeof window !== 'undefined' && window.__AI_MENU_INTERACTIVE || checkInteractiveMenu(e)) {\n return\n }\n\n // Early exit if clicking within current container\n if (currentContainer?.isConnected && currentContainer.contains(target)) {\n return\n }\n\n // Performance: Quick check before expensive traversal\n // If click is nowhere near a field, just clear active state\n if (!target.closest('.field-type')) {\n if (currentContainer) {\n setActiveContainer(null)\n }\n return\n }\n\n // Throttle to prevent excessive work on rapid clicking\n if (pointerDownThrottleTimer !== null) {\n return\n }\n\n const container = resolveContainerFromTarget(target)\n setActiveContainer(container)\n\n // Set throttle timer for 50ms\n pointerDownThrottleTimer = window.setTimeout(() => {\n pointerDownThrottleTimer = null\n }, 50)\n}\n\n/**\n * Handle keyboard navigation (Tab key)\n */\nconst onKeyDown = (e: KeyboardEvent): void => {\n if (e.key !== 'Tab') {\n return\n }\n\n // Cancel any pending RAF to prevent queuing\n if (rafId !== null) {\n cancelAnimationFrame(rafId)\n }\n\n // Defer until after focus has shifted\n rafId = requestAnimationFrame(() => {\n rafId = null\n const container = resolveContainerFromTarget(document.activeElement)\n setActiveContainer(container)\n })\n}\n\n/**\n * Handle visibility changes to properly cleanup when page is hidden\n */\nconst onVisibilityChange = (): void => {\n if (typeof document !== 'undefined' && document.hidden) {\n // Clear active state and cancel pending operations\n clearActiveContainer()\n }\n}\n\n/**\n * Initialize document-level listeners to track the active field container.\n * When a container is active, it receives the 'ai-plugin-active' class.\n */\nexport const useActiveFieldTracking = (): void => {\n useEffect(() => {\n if (typeof window === 'undefined') {\n return\n }\n\n const pluginWindow = window as {\n __aiComposeTracking?: boolean\n __aiComposeTrackingController?: AbortController\n __aiComposeTrackingCount?: number\n } & Window\n\n // Track number of mounted users of the hook\n pluginWindow.__aiComposeTrackingCount = (pluginWindow.__aiComposeTrackingCount ?? 0) + 1\n\n // Initialize listeners only once\n if (!pluginWindow.__aiComposeTracking) {\n const controller = new AbortController()\n pluginWindow.__aiComposeTrackingController = controller\n\n // Use capture for early handling\n document.addEventListener('focusin', onFocusIn, {\n capture: true,\n signal: controller.signal,\n })\n document.addEventListener('pointerdown', onPointerDown, {\n capture: true,\n passive: true,\n signal: controller.signal,\n })\n document.addEventListener('keydown', onKeyDown, {\n capture: true,\n signal: controller.signal,\n })\n document.addEventListener('visibilitychange', onVisibilityChange, {\n signal: controller.signal,\n })\n\n pluginWindow.__aiComposeTracking = true\n }\n\n return () => {\n // Decrement and cleanup when the last user unmounts\n pluginWindow.__aiComposeTrackingCount = (pluginWindow.__aiComposeTrackingCount ?? 1) - 1\n\n if ((pluginWindow.__aiComposeTrackingCount ?? 0) <= 0) {\n // Atomically remove all listeners\n pluginWindow.__aiComposeTrackingController?.abort()\n pluginWindow.__aiComposeTrackingController = undefined\n\n // Clear active state and cancel pending operations\n clearActiveContainer()\n\n // Reset all state\n pluginWindow.__aiComposeTracking = false\n pluginWindow.__aiComposeTrackingCount = 0\n }\n }\n }, [])\n}\n"],"names":["useEffect","ALLOWED_FIELD_TYPES","containerCache","WeakMap","fieldTypeCache","pointerDownThrottleTimer","focusDebounceTimer","currentContainer","lastContainer","rafId","cssEscape","value","CSS","escape","replace","findContainerFromReactSelect","target","role","getAttribute","includes","listbox","closest","id","selector","control","document","querySelector","isAllowedFieldType","container","has","get","result","some","type","classList","contains","set","resolveContainerFromTarget","HTMLElement","cached","isConnected","delete","setActiveContainer","next","remove","add","clearActiveContainer","cancelAnimationFrame","isInteractiveElement","element","tagName","toLowerCase","interactiveTags","isContentEditable","checkInteractiveMenu","e","window","__AI_MENU_INTERACTIVE","Element","hasAttribute","path","composedPath","el","onFocusIn","clearTimeout","setTimeout","onPointerDown","onKeyDown","key","requestAnimationFrame","activeElement","onVisibilityChange","hidden","useActiveFieldTracking","pluginWindow","__aiComposeTrackingCount","__aiComposeTracking","controller","AbortController","__aiComposeTrackingController","addEventListener","capture","signal","passive","abort","undefined"],"mappings":"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"}