@automattic/jetpack-ai-client 0.25.6 → 0.26.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 (227) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/build/components/ai-icon/index.d.ts +10 -0
  3. package/build/components/ai-icon/index.js +16 -0
  4. package/build/components/ai-image/components/ai-image-modal.d.ts +57 -0
  5. package/build/components/ai-image/components/ai-image-modal.js +92 -0
  6. package/build/components/ai-image/components/carrousel.d.ts +28 -0
  7. package/build/components/ai-image/components/carrousel.js +69 -0
  8. package/build/components/ai-image/components/usage-counter.d.ts +16 -0
  9. package/build/components/ai-image/components/usage-counter.js +29 -0
  10. package/build/components/ai-image/featured-image.d.ts +17 -0
  11. package/build/components/ai-image/featured-image.js +278 -0
  12. package/build/components/ai-image/general-purpose-image.d.ts +23 -0
  13. package/build/components/ai-image/general-purpose-image.js +184 -0
  14. package/build/components/ai-image/hooks/use-ai-image.d.ts +48 -0
  15. package/build/components/ai-image/hooks/use-ai-image.js +219 -0
  16. package/build/components/ai-image/hooks/use-site-type.d.ts +6 -0
  17. package/build/components/ai-image/hooks/use-site-type.js +23 -0
  18. package/build/components/ai-image/index.d.ts +4 -0
  19. package/build/components/ai-image/index.js +4 -0
  20. package/build/components/ai-image/types.d.ts +16 -0
  21. package/build/components/ai-image/types.js +6 -0
  22. package/build/{ai-client/src/components → components}/index.d.ts +4 -0
  23. package/build/{ai-client/src/components → components}/index.js +4 -0
  24. package/build/components/modal/index.d.ts +18 -0
  25. package/build/components/modal/index.js +23 -0
  26. package/build/components/quota-exceeded-message/index.d.ts +13 -0
  27. package/build/components/quota-exceeded-message/index.js +152 -0
  28. package/build/components/quota-exceeded-message/light-nudge.d.ts +11 -0
  29. package/build/components/quota-exceeded-message/light-nudge.js +8 -0
  30. package/build/{ai-client/src/constants.d.ts → constants.d.ts} +3 -0
  31. package/build/{ai-client/src/constants.js → constants.js} +4 -0
  32. package/build/hooks/use-ai-checkout/index.d.ts +13 -0
  33. package/build/hooks/use-ai-checkout/index.js +41 -0
  34. package/build/hooks/use-ai-feature/index.d.ts +33 -0
  35. package/build/hooks/use-ai-feature/index.js +37 -0
  36. package/build/hooks/use-post-content.d.ts +5 -0
  37. package/build/hooks/use-post-content.js +20 -0
  38. package/build/hooks/use-save-to-media-library.d.ts +12 -0
  39. package/build/hooks/use-save-to-media-library.js +74 -0
  40. package/build/{ai-client/src/index.d.ts → index.d.ts} +3 -0
  41. package/build/{ai-client/src/index.js → index.js} +3 -0
  42. package/build/{ai-client/src/logo-generator → logo-generator}/components/upgrade-screen.js +1 -1
  43. package/build/{ai-client/src/logo-generator → logo-generator}/hooks/use-fair-usage-notice-message.js +1 -1
  44. package/package.json +20 -14
  45. package/src/components/ai-icon/index.tsx +39 -0
  46. package/src/components/ai-image/components/ai-image-modal.scss +88 -0
  47. package/src/components/ai-image/components/ai-image-modal.tsx +240 -0
  48. package/src/components/ai-image/components/carrousel.scss +163 -0
  49. package/src/components/ai-image/components/carrousel.tsx +217 -0
  50. package/src/components/ai-image/components/usage-counter.scss +19 -0
  51. package/src/components/ai-image/components/usage-counter.tsx +54 -0
  52. package/src/components/ai-image/featured-image.tsx +439 -0
  53. package/src/components/ai-image/general-purpose-image.tsx +303 -0
  54. package/src/components/ai-image/hooks/use-ai-image.ts +339 -0
  55. package/src/components/ai-image/hooks/use-site-type.ts +26 -0
  56. package/src/components/ai-image/index.ts +10 -0
  57. package/src/components/ai-image/style.scss +95 -0
  58. package/src/components/ai-image/types.ts +19 -0
  59. package/src/components/index.ts +12 -0
  60. package/src/components/modal/index.tsx +70 -0
  61. package/src/components/modal/style.scss +45 -0
  62. package/src/components/quota-exceeded-message/index.tsx +319 -0
  63. package/src/components/quota-exceeded-message/light-nudge.tsx +38 -0
  64. package/src/components/quota-exceeded-message/style.scss +35 -0
  65. package/src/constants.ts +5 -0
  66. package/src/hooks/use-ai-checkout/index.ts +65 -0
  67. package/src/hooks/use-ai-feature/Readme.md +20 -0
  68. package/src/hooks/use-ai-feature/index.ts +62 -0
  69. package/src/hooks/use-post-content.ts +27 -0
  70. package/src/hooks/use-save-to-media-library.ts +100 -0
  71. package/src/index.ts +3 -0
  72. package/src/logo-generator/components/upgrade-screen.tsx +1 -1
  73. package/src/logo-generator/hooks/use-fair-usage-notice-message.tsx +1 -1
  74. package/build/components/tools/jp-redirect/index.d.ts +0 -20
  75. package/build/components/tools/jp-redirect/index.js +0 -50
  76. package/build/components/tools/jp-redirect/types.d.ts +0 -39
  77. package/build/components/tools/jp-redirect/types.js +0 -1
  78. /package/build/{ai-client/src/api-fetch → api-fetch}/index.d.ts +0 -0
  79. /package/build/{ai-client/src/api-fetch → api-fetch}/index.js +0 -0
  80. /package/build/{ai-client/src/ask-question → ask-question}/index.d.ts +0 -0
  81. /package/build/{ai-client/src/ask-question → ask-question}/index.js +0 -0
  82. /package/build/{ai-client/src/ask-question → ask-question}/sync.d.ts +0 -0
  83. /package/build/{ai-client/src/ask-question → ask-question}/sync.js +0 -0
  84. /package/build/{ai-client/src/audio-transcription → audio-transcription}/index.d.ts +0 -0
  85. /package/build/{ai-client/src/audio-transcription → audio-transcription}/index.js +0 -0
  86. /package/build/{ai-client/src/components → components}/ai-control/ai-control.d.ts +0 -0
  87. /package/build/{ai-client/src/components → components}/ai-control/ai-control.js +0 -0
  88. /package/build/{ai-client/src/components → components}/ai-control/block-ai-control.d.ts +0 -0
  89. /package/build/{ai-client/src/components → components}/ai-control/block-ai-control.js +0 -0
  90. /package/build/{ai-client/src/components → components}/ai-control/extension-ai-control.d.ts +0 -0
  91. /package/build/{ai-client/src/components → components}/ai-control/extension-ai-control.js +0 -0
  92. /package/build/{ai-client/src/components → components}/ai-control/index.d.ts +0 -0
  93. /package/build/{ai-client/src/components → components}/ai-control/index.js +0 -0
  94. /package/build/{ai-client/src/components → components}/ai-feedback/index.d.ts +0 -0
  95. /package/build/{ai-client/src/components → components}/ai-feedback/index.js +0 -0
  96. /package/build/{ai-client/src/components → components}/ai-modal-footer/index.d.ts +0 -0
  97. /package/build/{ai-client/src/components → components}/ai-modal-footer/index.js +0 -0
  98. /package/build/{ai-client/src/components → components}/ai-status-indicator/index.d.ts +0 -0
  99. /package/build/{ai-client/src/components → components}/ai-status-indicator/index.js +0 -0
  100. /package/build/{ai-client/src/components → components}/audio-duration-display/index.d.ts +0 -0
  101. /package/build/{ai-client/src/components → components}/audio-duration-display/index.js +0 -0
  102. /package/build/{ai-client/src/components → components}/audio-duration-display/lib/media.d.ts +0 -0
  103. /package/build/{ai-client/src/components → components}/audio-duration-display/lib/media.js +0 -0
  104. /package/build/{ai-client/src/components → components}/message/index.d.ts +0 -0
  105. /package/build/{ai-client/src/components → components}/message/index.js +0 -0
  106. /package/build/{ai-client/src/data-flow → data-flow}/context.d.ts +0 -0
  107. /package/build/{ai-client/src/data-flow → data-flow}/context.js +0 -0
  108. /package/build/{ai-client/src/data-flow → data-flow}/index.d.ts +0 -0
  109. /package/build/{ai-client/src/data-flow → data-flow}/index.js +0 -0
  110. /package/build/{ai-client/src/data-flow → data-flow}/use-ai-context.d.ts +0 -0
  111. /package/build/{ai-client/src/data-flow → data-flow}/use-ai-context.js +0 -0
  112. /package/build/{ai-client/src/data-flow → data-flow}/with-ai-assistant-data.d.ts +0 -0
  113. /package/build/{ai-client/src/data-flow → data-flow}/with-ai-assistant-data.js +0 -0
  114. /package/build/{ai-client/src/hooks → hooks}/use-ai-suggestions/index.d.ts +0 -0
  115. /package/build/{ai-client/src/hooks → hooks}/use-ai-suggestions/index.js +0 -0
  116. /package/build/{ai-client/src/hooks → hooks}/use-audio-transcription/index.d.ts +0 -0
  117. /package/build/{ai-client/src/hooks → hooks}/use-audio-transcription/index.js +0 -0
  118. /package/build/{ai-client/src/hooks → hooks}/use-audio-validation/index.d.ts +0 -0
  119. /package/build/{ai-client/src/hooks → hooks}/use-audio-validation/index.js +0 -0
  120. /package/build/{ai-client/src/hooks → hooks}/use-image-generator/constants.d.ts +0 -0
  121. /package/build/{ai-client/src/hooks → hooks}/use-image-generator/constants.js +0 -0
  122. /package/build/{ai-client/src/hooks → hooks}/use-image-generator/index.d.ts +0 -0
  123. /package/build/{ai-client/src/hooks → hooks}/use-image-generator/index.js +0 -0
  124. /package/build/{ai-client/src/hooks → hooks}/use-media-recording/index.d.ts +0 -0
  125. /package/build/{ai-client/src/hooks → hooks}/use-media-recording/index.js +0 -0
  126. /package/build/{ai-client/src/hooks → hooks}/use-save-to-media-library/index.d.ts +0 -0
  127. /package/build/{ai-client/src/hooks → hooks}/use-save-to-media-library/index.js +0 -0
  128. /package/build/{ai-client/src/hooks → hooks}/use-transcription-post-processing/index.d.ts +0 -0
  129. /package/build/{ai-client/src/hooks → hooks}/use-transcription-post-processing/index.js +0 -0
  130. /package/build/{ai-client/src/icons → icons}/ai-assistant.d.ts +0 -0
  131. /package/build/{ai-client/src/icons → icons}/ai-assistant.js +0 -0
  132. /package/build/{ai-client/src/icons → icons}/error-exclamation.d.ts +0 -0
  133. /package/build/{ai-client/src/icons → icons}/error-exclamation.js +0 -0
  134. /package/build/{ai-client/src/icons → icons}/index.d.ts +0 -0
  135. /package/build/{ai-client/src/icons → icons}/index.js +0 -0
  136. /package/build/{ai-client/src/icons → icons}/mic.d.ts +0 -0
  137. /package/build/{ai-client/src/icons → icons}/mic.js +0 -0
  138. /package/build/{ai-client/src/icons → icons}/origami-plane.d.ts +0 -0
  139. /package/build/{ai-client/src/icons → icons}/origami-plane.js +0 -0
  140. /package/build/{ai-client/src/icons → icons}/player-pause.d.ts +0 -0
  141. /package/build/{ai-client/src/icons → icons}/player-pause.js +0 -0
  142. /package/build/{ai-client/src/icons → icons}/player-play.d.ts +0 -0
  143. /package/build/{ai-client/src/icons → icons}/player-play.js +0 -0
  144. /package/build/{ai-client/src/icons → icons}/player-stop.d.ts +0 -0
  145. /package/build/{ai-client/src/icons → icons}/player-stop.js +0 -0
  146. /package/build/{ai-client/src/icons → icons}/speak-tone.d.ts +0 -0
  147. /package/build/{ai-client/src/icons → icons}/speak-tone.js +0 -0
  148. /package/build/{ai-client/src/jwt → jwt}/index.d.ts +0 -0
  149. /package/build/{ai-client/src/jwt → jwt}/index.js +0 -0
  150. /package/build/{ai-client/src/libs → libs}/index.d.ts +0 -0
  151. /package/build/{ai-client/src/libs → libs}/index.js +0 -0
  152. /package/build/{ai-client/src/libs → libs}/map-action-to-human-text.d.ts +0 -0
  153. /package/build/{ai-client/src/libs → libs}/map-action-to-human-text.js +0 -0
  154. /package/build/{ai-client/src/libs → libs}/markdown/html-to-markdown.d.ts +0 -0
  155. /package/build/{ai-client/src/libs → libs}/markdown/html-to-markdown.js +0 -0
  156. /package/build/{ai-client/src/libs → libs}/markdown/index.d.ts +0 -0
  157. /package/build/{ai-client/src/libs → libs}/markdown/index.js +0 -0
  158. /package/build/{ai-client/src/libs → libs}/markdown/markdown-to-html.d.ts +0 -0
  159. /package/build/{ai-client/src/libs → libs}/markdown/markdown-to-html.js +0 -0
  160. /package/build/{ai-client/src/logo-generator → logo-generator}/assets/icons/ai.d.ts +0 -0
  161. /package/build/{ai-client/src/logo-generator → logo-generator}/assets/icons/ai.js +0 -0
  162. /package/build/{ai-client/src/logo-generator → logo-generator}/assets/icons/check.d.ts +0 -0
  163. /package/build/{ai-client/src/logo-generator → logo-generator}/assets/icons/check.js +0 -0
  164. /package/build/{ai-client/src/logo-generator → logo-generator}/assets/icons/logo.d.ts +0 -0
  165. /package/build/{ai-client/src/logo-generator → logo-generator}/assets/icons/logo.js +0 -0
  166. /package/build/{ai-client/src/logo-generator → logo-generator}/assets/icons/media.d.ts +0 -0
  167. /package/build/{ai-client/src/logo-generator → logo-generator}/assets/icons/media.js +0 -0
  168. /package/build/{ai-client/src/logo-generator → logo-generator}/components/fair-usage-notice.d.ts +0 -0
  169. /package/build/{ai-client/src/logo-generator → logo-generator}/components/fair-usage-notice.js +0 -0
  170. /package/build/{ai-client/src/logo-generator → logo-generator}/components/feature-fetch-failure-screen.d.ts +0 -0
  171. /package/build/{ai-client/src/logo-generator → logo-generator}/components/feature-fetch-failure-screen.js +0 -0
  172. /package/build/{ai-client/src/logo-generator → logo-generator}/components/first-load-screen.d.ts +0 -0
  173. /package/build/{ai-client/src/logo-generator → logo-generator}/components/first-load-screen.js +0 -0
  174. /package/build/{ai-client/src/logo-generator → logo-generator}/components/generator-modal.d.ts +0 -0
  175. /package/build/{ai-client/src/logo-generator → logo-generator}/components/generator-modal.js +0 -0
  176. /package/build/{ai-client/src/logo-generator → logo-generator}/components/history-carousel.d.ts +0 -0
  177. /package/build/{ai-client/src/logo-generator → logo-generator}/components/history-carousel.js +0 -0
  178. /package/build/{ai-client/src/logo-generator → logo-generator}/components/image-loader.d.ts +0 -0
  179. /package/build/{ai-client/src/logo-generator → logo-generator}/components/image-loader.js +0 -0
  180. /package/build/{ai-client/src/logo-generator → logo-generator}/components/logo-presenter.d.ts +0 -0
  181. /package/build/{ai-client/src/logo-generator → logo-generator}/components/logo-presenter.js +0 -0
  182. /package/build/{ai-client/src/logo-generator → logo-generator}/components/prompt.d.ts +0 -0
  183. /package/build/{ai-client/src/logo-generator → logo-generator}/components/prompt.js +0 -0
  184. /package/build/{ai-client/src/logo-generator → logo-generator}/components/upgrade-nudge.d.ts +0 -0
  185. /package/build/{ai-client/src/logo-generator → logo-generator}/components/upgrade-nudge.js +0 -0
  186. /package/build/{ai-client/src/logo-generator → logo-generator}/components/upgrade-screen.d.ts +0 -0
  187. /package/build/{ai-client/src/logo-generator → logo-generator}/components/visit-site-banner.d.ts +0 -0
  188. /package/build/{ai-client/src/logo-generator → logo-generator}/components/visit-site-banner.js +0 -0
  189. /package/build/{ai-client/src/logo-generator → logo-generator}/constants.d.ts +0 -0
  190. /package/build/{ai-client/src/logo-generator → logo-generator}/constants.js +0 -0
  191. /package/build/{ai-client/src/logo-generator → logo-generator}/hooks/use-checkout.d.ts +0 -0
  192. /package/build/{ai-client/src/logo-generator → logo-generator}/hooks/use-checkout.js +0 -0
  193. /package/build/{ai-client/src/logo-generator → logo-generator}/hooks/use-fair-usage-notice-message.d.ts +0 -0
  194. /package/build/{ai-client/src/logo-generator → logo-generator}/hooks/use-logo-generator.d.ts +0 -0
  195. /package/build/{ai-client/src/logo-generator → logo-generator}/hooks/use-logo-generator.js +0 -0
  196. /package/build/{ai-client/src/logo-generator → logo-generator}/hooks/use-request-errors.d.ts +0 -0
  197. /package/build/{ai-client/src/logo-generator → logo-generator}/hooks/use-request-errors.js +0 -0
  198. /package/build/{ai-client/src/logo-generator → logo-generator}/index.d.ts +0 -0
  199. /package/build/{ai-client/src/logo-generator → logo-generator}/index.js +0 -0
  200. /package/build/{ai-client/src/logo-generator → logo-generator}/lib/logo-storage.d.ts +0 -0
  201. /package/build/{ai-client/src/logo-generator → logo-generator}/lib/logo-storage.js +0 -0
  202. /package/build/{ai-client/src/logo-generator → logo-generator}/lib/media-exists.d.ts +0 -0
  203. /package/build/{ai-client/src/logo-generator → logo-generator}/lib/media-exists.js +0 -0
  204. /package/build/{ai-client/src/logo-generator → logo-generator}/lib/set-site-logo.d.ts +0 -0
  205. /package/build/{ai-client/src/logo-generator → logo-generator}/lib/set-site-logo.js +0 -0
  206. /package/build/{ai-client/src/logo-generator → logo-generator}/lib/wpcom-limited-request.d.ts +0 -0
  207. /package/build/{ai-client/src/logo-generator → logo-generator}/lib/wpcom-limited-request.js +0 -0
  208. /package/build/{ai-client/src/logo-generator → logo-generator}/store/actions.d.ts +0 -0
  209. /package/build/{ai-client/src/logo-generator → logo-generator}/store/actions.js +0 -0
  210. /package/build/{ai-client/src/logo-generator → logo-generator}/store/constants.d.ts +0 -0
  211. /package/build/{ai-client/src/logo-generator → logo-generator}/store/constants.js +0 -0
  212. /package/build/{ai-client/src/logo-generator → logo-generator}/store/index.d.ts +0 -0
  213. /package/build/{ai-client/src/logo-generator → logo-generator}/store/index.js +0 -0
  214. /package/build/{ai-client/src/logo-generator → logo-generator}/store/initial-state.d.ts +0 -0
  215. /package/build/{ai-client/src/logo-generator → logo-generator}/store/initial-state.js +0 -0
  216. /package/build/{ai-client/src/logo-generator → logo-generator}/store/reducer.d.ts +0 -0
  217. /package/build/{ai-client/src/logo-generator → logo-generator}/store/reducer.js +0 -0
  218. /package/build/{ai-client/src/logo-generator → logo-generator}/store/selectors.d.ts +0 -0
  219. /package/build/{ai-client/src/logo-generator → logo-generator}/store/selectors.js +0 -0
  220. /package/build/{ai-client/src/logo-generator → logo-generator}/store/types.d.ts +0 -0
  221. /package/build/{ai-client/src/logo-generator → logo-generator}/store/types.js +0 -0
  222. /package/build/{ai-client/src/logo-generator → logo-generator}/types.d.ts +0 -0
  223. /package/build/{ai-client/src/logo-generator → logo-generator}/types.js +0 -0
  224. /package/build/{ai-client/src/suggestions-event-source → suggestions-event-source}/index.d.ts +0 -0
  225. /package/build/{ai-client/src/suggestions-event-source → suggestions-event-source}/index.js +0 -0
  226. /package/build/{ai-client/src/types.d.ts → types.d.ts} +0 -0
  227. /package/build/{ai-client/src/types.js → types.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.26.0] - 2025-02-10
9
+ ### Added
10
+ - Add shared components from ai-assistant-plugin [#41078]
11
+
12
+ ### Changed
13
+ - Updated package dependencies. [#41491] [#41577]
14
+
15
+ ## [0.25.7] - 2025-01-27
16
+ ### Changed
17
+ - Internal updates.
18
+
8
19
  ## [0.25.6] - 2025-01-20
9
20
  ### Changed
10
21
  - Updated package dependencies. [#41099]
@@ -506,6 +517,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
506
517
  - AI Client: stop using smart document visibility handling on the fetchEventSource library, so it does not restart the completion when changing tabs. [#32004]
507
518
  - Updated package dependencies. [#31468] [#31659] [#31785]
508
519
 
520
+ [0.26.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.25.7...v0.26.0
521
+ [0.25.7]: https://github.com/Automattic/jetpack-ai-client/compare/v0.25.6...v0.25.7
509
522
  [0.25.6]: https://github.com/Automattic/jetpack-ai-client/compare/v0.25.5...v0.25.6
510
523
  [0.25.5]: https://github.com/Automattic/jetpack-ai-client/compare/v0.25.4...v0.25.5
511
524
  [0.25.4]: https://github.com/Automattic/jetpack-ai-client/compare/v0.25.3...v0.25.4
@@ -0,0 +1,10 @@
1
+ export declare const AiSVG: import("react/jsx-runtime").JSX.Element;
2
+ /**
3
+ * AiIcon component
4
+ * @param {string} className - The wrapper class name.
5
+ * @return {React.ReactElement} The `AiIcon` component.
6
+ */
7
+ export default function AiIcon({ className, size }: {
8
+ className?: string;
9
+ size?: number;
10
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * External dependencies
4
+ */
5
+ import { G, Path, SVG, Rect } from '@wordpress/components';
6
+ import { Icon } from '@wordpress/icons';
7
+ import { Defs } from '@wordpress/primitives';
8
+ export const AiSVG = (_jsxs(SVG, { width: "42", height: "42", viewBox: "0 0 42 42", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [_jsxs(G, { clipPath: "url(#clip0_4479_1006)", children: [_jsx(Path, { d: "M7.87488 0L10.1022 5.64753L15.7498 7.87488L10.1022 10.1022L7.87488 15.7498L5.64753 10.1022L0 7.87488L5.64753 5.64753L7.87488 0Z", fill: "#A7AAAD" }), _jsx(Path, { d: "M31.4998 0L34.4696 7.53004L41.9997 10.4998L34.4696 13.4696L31.4998 20.9997L28.53 13.4696L21 10.4998L28.53 7.53004L31.4998 0Z", fill: "#A7AAAD" }), _jsx(Path, { d: "M18.3748 15.7496L22.0871 25.1621L31.4996 28.8744L22.0871 32.5866L18.3748 41.9992L14.6625 32.5866L5.25 28.8744L14.6625 25.1621L18.3748 15.7496Z", fill: "#A7AAAD" })] }), _jsx(Defs, { children: _jsx("clipPath", { id: "clip0_4479_1006", children: _jsx(Rect, { width: "41.9997", height: "41.9992", fill: "white" }) }) })] }));
9
+ /**
10
+ * AiIcon component
11
+ * @param {string} className - The wrapper class name.
12
+ * @return {React.ReactElement} The `AiIcon` component.
13
+ */
14
+ export default function AiIcon({ className, size = 42 }) {
15
+ return _jsx(Icon, { icon: AiSVG, width: size, height: size, className: className });
16
+ }
@@ -0,0 +1,57 @@
1
+ /// <reference types="react" resolution-mode="require"/>
2
+ /**
3
+ * Internal dependencies
4
+ */
5
+ import { ImageStyleObject, ImageStyle } from '../../../hooks/use-image-generator/constants.js';
6
+ import { CarrouselImages } from './carrousel.js';
7
+ import './ai-image-modal.scss';
8
+ type AiImageModalProps = {
9
+ title: string;
10
+ cost: number;
11
+ open: boolean;
12
+ placement: string;
13
+ images: CarrouselImages;
14
+ currentIndex: number;
15
+ onClose: () => void;
16
+ onTryAgain: ({ userPrompt, style }: {
17
+ userPrompt?: string;
18
+ style?: string;
19
+ }) => void;
20
+ onGenerate: ({ userPrompt, style }: {
21
+ userPrompt?: string;
22
+ style?: string;
23
+ }) => void;
24
+ generating: boolean;
25
+ notEnoughRequests: boolean;
26
+ requireUpgrade: boolean;
27
+ currentLimit: number;
28
+ currentUsage: number;
29
+ isUnlimited: boolean;
30
+ upgradeDescription: string;
31
+ hasError: boolean;
32
+ postContent?: string | boolean | null;
33
+ handlePreviousImage: () => void;
34
+ handleNextImage: () => void;
35
+ acceptButton: React.JSX.Element;
36
+ autoStart?: boolean;
37
+ autoStartAction?: ({ userPrompt, style }: {
38
+ userPrompt?: string;
39
+ style?: string;
40
+ }) => void;
41
+ generateButtonLabel: string;
42
+ instructionsPlaceholder: string;
43
+ imageStyles?: Array<ImageStyleObject>;
44
+ onGuessStyle?: (userPrompt: string) => Promise<ImageStyle>;
45
+ prompt?: string;
46
+ setPrompt?: (userPrompt: string) => void;
47
+ initialStyle?: ImageStyle;
48
+ inputDisabled?: boolean;
49
+ actionDisabled?: boolean;
50
+ };
51
+ /**
52
+ * AiImageModal component
53
+ * @param {AiImageModalProps} props - The component properties.
54
+ * @return {React.ReactElement} - rendered component.
55
+ */
56
+ export default function AiImageModal({ title, cost, open, images, currentIndex, onClose, onTryAgain, onGenerate, generating, notEnoughRequests, requireUpgrade, currentLimit, currentUsage, isUnlimited, upgradeDescription, hasError, handlePreviousImage, handleNextImage, acceptButton, autoStart, autoStartAction, instructionsPlaceholder, imageStyles, onGuessStyle, prompt, setPrompt, initialStyle, inputDisabled, actionDisabled, }: AiImageModalProps): import("react/jsx-runtime").JSX.Element;
57
+ export {};
@@ -0,0 +1,92 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /**
3
+ * External dependencies
4
+ */
5
+ import { useAnalytics } from '@automattic/jetpack-shared-extension-utils';
6
+ import { SelectControl } from '@wordpress/components';
7
+ import { useCallback, useRef, useState, useEffect } from '@wordpress/element';
8
+ import { __ } from '@wordpress/i18n';
9
+ import debugFactory from 'debug';
10
+ /**
11
+ * Internal dependencies
12
+ */
13
+ import { IMAGE_STYLE_NONE, IMAGE_STYLE_AUTO, } from '../../../hooks/use-image-generator/constants.js';
14
+ import { AiModalPromptInput } from '../../../logo-generator/index.js';
15
+ import AiModalFooter from '../../ai-modal-footer/index.js';
16
+ import AiAssistantModal from '../../modal/index.js';
17
+ import QuotaExceededMessage from '../../quota-exceeded-message/index.js';
18
+ import Carrousel from './carrousel.js';
19
+ import UsageCounter from './usage-counter.js';
20
+ import './ai-image-modal.scss';
21
+ const FEATURED_IMAGE_UPGRADE_PROMPT_PLACEMENT = 'ai-image-generator';
22
+ const debug = debugFactory('jetpack-ai-client:ai-image-modal');
23
+ /**
24
+ * AiImageModal component
25
+ * @param {AiImageModalProps} props - The component properties.
26
+ * @return {React.ReactElement} - rendered component.
27
+ */
28
+ export default function AiImageModal({ title, cost, open, images, currentIndex = 0, onClose = null, onTryAgain = null, onGenerate = null, generating = false, notEnoughRequests = false, requireUpgrade = false, currentLimit = null, currentUsage = null, isUnlimited = false, upgradeDescription = null, hasError = false, handlePreviousImage = () => { }, handleNextImage = () => { }, acceptButton = null, autoStart = false, autoStartAction = null, instructionsPlaceholder = null, imageStyles = [], onGuessStyle = null, prompt = '', setPrompt = () => { }, initialStyle = null, inputDisabled = false, actionDisabled = false, }) {
29
+ const { tracks } = useAnalytics();
30
+ const { recordEvent: recordTracksEvent } = tracks;
31
+ const triggeredAutoGeneration = useRef(false);
32
+ const [showStyleSelector, setShowStyleSelector] = useState(false);
33
+ const [style, setStyle] = useState(null);
34
+ const [styles, setStyles] = useState(imageStyles || []);
35
+ const handleTryAgain = useCallback(() => {
36
+ onTryAgain?.({ userPrompt: prompt, style });
37
+ }, [onTryAgain, prompt, style]);
38
+ const handleGenerate = useCallback(async () => {
39
+ if (style === IMAGE_STYLE_AUTO && onGuessStyle) {
40
+ recordTracksEvent('jetpack_ai_general_image_guess_style', {
41
+ context: 'block-editor',
42
+ tool: 'image',
43
+ });
44
+ const guessedStyle = (await onGuessStyle(prompt)) || IMAGE_STYLE_NONE;
45
+ setStyle(guessedStyle);
46
+ debug('guessed style', guessedStyle);
47
+ onGenerate?.({ userPrompt: prompt, style: guessedStyle });
48
+ }
49
+ else {
50
+ onGenerate?.({ userPrompt: prompt, style });
51
+ }
52
+ }, [onGenerate, prompt, style, onGuessStyle, recordTracksEvent]);
53
+ const updateStyle = useCallback((imageStyle) => {
54
+ debug('change style', imageStyle);
55
+ setStyle(imageStyle);
56
+ recordTracksEvent('jetpack_ai_image_generator_switch_style', {
57
+ context: 'block-editor',
58
+ style: imageStyle,
59
+ });
60
+ }, [setStyle, recordTracksEvent]);
61
+ // Controllers
62
+ const upgradePromptVisible = (requireUpgrade || notEnoughRequests) && !generating;
63
+ const counterVisible = Boolean(!isUnlimited && cost && currentLimit);
64
+ const generateLabel = __('Generate', 'jetpack-ai-client');
65
+ const tryAgainLabel = __('Try again', 'jetpack-ai-client');
66
+ /**
67
+ * Trigger image generation automatically.
68
+ */
69
+ useEffect(() => {
70
+ if (autoStart && open) {
71
+ if (!triggeredAutoGeneration.current) {
72
+ triggeredAutoGeneration.current = true;
73
+ autoStartAction?.({});
74
+ }
75
+ }
76
+ }, [autoStart, autoStartAction, open]);
77
+ // initialize styles dropdown
78
+ useEffect(() => {
79
+ if (imageStyles && imageStyles.length > 0) {
80
+ // Sort styles to have "None" and "Auto" first
81
+ setStyles([
82
+ imageStyles.find(({ value }) => value === IMAGE_STYLE_NONE),
83
+ imageStyles.find(({ value }) => value === IMAGE_STYLE_AUTO),
84
+ ...imageStyles.filter(({ value }) => ![IMAGE_STYLE_NONE, IMAGE_STYLE_AUTO].includes(value)),
85
+ ].filter(v => v) // simplest way to get rid of empty values
86
+ );
87
+ setShowStyleSelector(true);
88
+ setStyle(initialStyle || IMAGE_STYLE_NONE);
89
+ }
90
+ }, [imageStyles, initialStyle]);
91
+ return (_jsx(_Fragment, { children: open && (_jsxs(AiAssistantModal, { handleClose: onClose, title: title, children: [_jsxs("div", { className: "ai-image-modal__content", children: [showStyleSelector && (_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 16 }, children: [_jsx("div", { style: { fontWeight: 500, flexGrow: 1 }, children: __('Generate image', 'jetpack-ai-client') }), _jsx("div", { children: _jsx(SelectControl, { __nextHasNoMarginBottom: true, value: style, options: styles, onChange: updateStyle }) })] })), _jsx(AiModalPromptInput, { prompt: prompt, setPrompt: setPrompt, disabled: inputDisabled, actionDisabled: actionDisabled, generateHandler: hasError ? handleTryAgain : handleGenerate, placeholder: instructionsPlaceholder, buttonLabel: hasError ? tryAgainLabel : generateLabel }), upgradePromptVisible && (_jsx(QuotaExceededMessage, { description: upgradeDescription, placement: FEATURED_IMAGE_UPGRADE_PROMPT_PLACEMENT, useLightNudge: true })), _jsx("div", { className: "ai-image-modal__actions", children: _jsx("div", { className: "ai-image-modal__actions-left", children: counterVisible && (_jsx(UsageCounter, { cost: cost, currentLimit: currentLimit, currentUsage: currentUsage })) }) }), _jsx("div", { className: "ai-image-modal__image-canvas", children: _jsx(Carrousel, { images: images, current: currentIndex, handlePreviousImage: handlePreviousImage, handleNextImage: handleNextImage, actions: acceptButton }) })] }), _jsx("div", { className: "ai-image-modal__footer", children: _jsx(AiModalFooter, {}) })] })) }));
92
+ }
@@ -0,0 +1,28 @@
1
+ /// <reference types="react" resolution-mode="require"/>
2
+ import './carrousel.scss';
3
+ export type CarrouselImageData = {
4
+ image?: string;
5
+ libraryId?: number | string;
6
+ prompt?: string;
7
+ revisedPrompt?: string;
8
+ libraryUrl?: string;
9
+ generating?: boolean;
10
+ error?: {
11
+ message: string;
12
+ };
13
+ };
14
+ export type CarrouselImages = CarrouselImageData[];
15
+ type CarrouselProps = {
16
+ images: CarrouselImages;
17
+ current: number;
18
+ handlePreviousImage: () => void;
19
+ handleNextImage: () => void;
20
+ actions?: React.JSX.Element;
21
+ };
22
+ /**
23
+ * Carrousel component
24
+ * @param {CarrouselProps} props - The component properties.
25
+ * @return {React.ReactElement} - rendered component.
26
+ */
27
+ export default function Carrousel({ images, current, handlePreviousImage, handleNextImage, actions, }: CarrouselProps): import("react/jsx-runtime").JSX.Element;
28
+ export {};
@@ -0,0 +1,69 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /**
3
+ * External dependencies
4
+ */
5
+ import { Spinner } from '@wordpress/components';
6
+ import { useEffect, useState } from '@wordpress/element';
7
+ import { __ } from '@wordpress/i18n';
8
+ import { Icon, chevronLeft, chevronRight } from '@wordpress/icons';
9
+ import clsx from 'clsx';
10
+ /**
11
+ * Internal dependencies
12
+ */
13
+ import AiFeedbackThumbs from '../../ai-feedback/index.js';
14
+ import AiIcon from '../../ai-icon/index.js';
15
+ import './carrousel.scss';
16
+ /**
17
+ * BlankImage component
18
+ * @param {BlankImageProps} props - The component properties.
19
+ * @return {React.ReactElement} - rendered component.
20
+ */
21
+ function BlankImage({ children, isDotted = false, contentClassName = '' }) {
22
+ const blankImage = (_jsx("img", { className: "ai-assistant-image__carrousel-image", src: "data:image/svg+xml;utf8,<svg viewBox='0 0 1 1' width='1024' height='768' xmlns='http://www.w3.org/2000/svg'><path d='M0 0 L1 0 L1 1 L0 1 L0 0 Z' fill='none' /></svg>", alt: "" }));
23
+ return (_jsxs("div", { className: "ai-assistant-image__blank", children: [blankImage, _jsx("div", { className: clsx('ai-assistant-image__blank-content', contentClassName, {
24
+ 'is-dotted': isDotted,
25
+ }), children: children })] }));
26
+ }
27
+ /**
28
+ * Carrousel component
29
+ * @param {CarrouselProps} props - The component properties.
30
+ * @return {React.ReactElement} - rendered component.
31
+ */
32
+ export default function Carrousel({ images, current, handlePreviousImage, handleNextImage, actions = null, }) {
33
+ const [imageFeedbackDisabled, setImageFeedbackDisabled] = useState(false);
34
+ const prevButton = (_jsx("button", { className: "ai-carrousel__prev", onClick: handlePreviousImage, children: _jsx(Icon, { icon: chevronLeft, className: clsx('ai-carrousel__prev-icon', {
35
+ 'is-disabled': current === 0,
36
+ }) }) }));
37
+ const nextButton = (_jsx("button", { className: "ai-carrousel__next", onClick: handleNextImage, children: _jsx(Icon, { icon: chevronRight, className: clsx('ai-carrousel__next-icon', {
38
+ 'is-disabled': current + 1 === images.length,
39
+ }) }) }));
40
+ const total = images?.filter?.(item => item?.generating || Object.hasOwn(item, 'image') || Object.hasOwn(item, 'libraryId'))?.length;
41
+ const actual = current === 0 && total === 0 ? 0 : current + 1;
42
+ useEffect(() => {
43
+ const imageData = images[current];
44
+ if (!imageData) {
45
+ setImageFeedbackDisabled(true);
46
+ }
47
+ const { image, generating, error } = imageData || {};
48
+ // disable if there's an empty modal
49
+ if (!image && !generating && !error) {
50
+ return setImageFeedbackDisabled(true);
51
+ }
52
+ // also disable if we're generating or have an error
53
+ if (generating || error) {
54
+ return setImageFeedbackDisabled(true);
55
+ }
56
+ setImageFeedbackDisabled(false);
57
+ }, [current, images]);
58
+ return (_jsxs("div", { className: "ai-assistant-image__carrousel", children: [_jsxs("div", { className: "ai-assistant-image__carrousel-images", children: [images.length > 1 && prevButton, images.map(({ image, generating, error, revisedPrompt, libraryUrl }, index) => (_jsx("div", { className: clsx('ai-assistant-image__carrousel-image-container', {
59
+ 'is-current': current === index,
60
+ 'is-prev': current > index,
61
+ }), children: generating ? (_jsxs(BlankImage, { contentClassName: "ai-assistant-image__loading", children: [__('Creating image…', 'jetpack-ai-client'), _jsx(Spinner, { style: {
62
+ width: '50px',
63
+ height: '50px',
64
+ } })] })) : (_jsx(_Fragment, { children: error ? (_jsx(BlankImage, { isDotted: true, children: _jsxs("div", { className: "ai-assistant-image__error", children: [__('An error occurred while generating the image. Please, try again!', 'jetpack-ai-client'), error?.message && (_jsx("span", { className: "ai-assistant-image__error-message", children: error?.message }))] }) })) : (_jsx(_Fragment, { children: !generating && !image && !libraryUrl ? (_jsx(BlankImage, { children: _jsx(AiIcon, {}) })) : (_jsx("img", { className: "ai-assistant-image__carrousel-image", src: image || libraryUrl, alt: revisedPrompt })) })) })) }, `image:` + index))), images.length > 1 && nextButton] }), _jsxs("div", { className: "ai-assistant-image__carrousel-footer", children: [_jsxs("div", { className: "ai-assistant-image__carrousel-footer-left", children: [_jsxs("div", { className: "ai-assistant-image__carrousel-counter", children: [prevButton, actual, " / ", total, nextButton] }), _jsx(AiFeedbackThumbs, { disabled: imageFeedbackDisabled, ratedItem: images[current]?.libraryUrl || '', iconSize: 20, options: {
65
+ mediaLibraryId: Number(images[current].libraryId),
66
+ prompt: images[current].prompt,
67
+ revisedPrompt: images[current].revisedPrompt,
68
+ }, feature: "image-generator" })] }), _jsx("div", { className: "ai-assistant-image__carrousel-actions", children: actions })] })] }));
69
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import './usage-counter.scss';
5
+ type UsageCounterProps = {
6
+ currentLimit: number;
7
+ currentUsage: number;
8
+ cost: number;
9
+ };
10
+ /**
11
+ * UsageCounter component
12
+ * @param {UsageCounterProps} props - The component properties.
13
+ * @return {React.ReactElement} - rendered component.
14
+ */
15
+ export default function UsageCounter({ currentLimit, currentUsage, cost }: UsageCounterProps): import("react/jsx-runtime").JSX.Element;
16
+ export {};
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * External dependencies
4
+ */
5
+ import { createInterpolateElement } from '@wordpress/element';
6
+ import { __, sprintf } from '@wordpress/i18n';
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import './usage-counter.scss';
11
+ /**
12
+ * UsageCounter component
13
+ * @param {UsageCounterProps} props - The component properties.
14
+ * @return {React.ReactElement} - rendered component.
15
+ */
16
+ export default function UsageCounter({ currentLimit, currentUsage, cost }) {
17
+ const requestsBalance = currentLimit - currentUsage;
18
+ const requestsNeeded = createInterpolateElement(
19
+ // Translators: %d is the cost of one image.
20
+ sprintf(__('Requests needed: <counter>%d</counter>', 'jetpack-ai-client'), cost), {
21
+ counter: _jsx("span", {}),
22
+ });
23
+ const requestsAvailable = createInterpolateElement(sprintf(
24
+ // Translators: %d is the current requests balance.
25
+ __('Requests available: <counter>%d</counter>', 'jetpack-ai-client'), requestsBalance), {
26
+ counter: requestsBalance < cost ? (_jsx("span", { className: "ai-assistant-featured-image__usage-counter-no-limit" })) : (_jsx("strong", {})),
27
+ });
28
+ return (_jsxs("div", { className: "ai-assistant-featured-image__usage-counter", children: [_jsx("span", { children: requestsNeeded }), _jsx("span", { children: requestsAvailable })] }));
29
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import './style.scss';
5
+ type FeaturedImageProps = {
6
+ busy: boolean;
7
+ disabled: boolean;
8
+ placement: string;
9
+ onClose?: () => void;
10
+ };
11
+ /**
12
+ * FeaturedImage component
13
+ * @param {FeaturedImageProps} props - The component properties.
14
+ * @return {React.ReactElement} - rendered component.
15
+ */
16
+ export default function FeaturedImage({ busy, disabled, placement, onClose, }: FeaturedImageProps): import("react/jsx-runtime").JSX.Element;
17
+ export {};
@@ -0,0 +1,278 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * External dependencies
4
+ */
5
+ import { useAnalytics, PLAN_TYPE_UNLIMITED, usePlanType, } from '@automattic/jetpack-shared-extension-utils';
6
+ import { Button } from '@wordpress/components';
7
+ import { useDispatch, useSelect } from '@wordpress/data';
8
+ import { store as editorStore } from '@wordpress/editor';
9
+ import { useCallback, useState } from '@wordpress/element';
10
+ import { __, sprintf } from '@wordpress/i18n';
11
+ import debugFactory from 'debug';
12
+ /**
13
+ * Internal dependencies
14
+ */
15
+ import './style.scss';
16
+ import { PLACEMENT_JETPACK_SIDEBAR, PLACEMENT_DOCUMENT_SETTINGS } from '../../constants.js';
17
+ import useAiFeature from '../../hooks/use-ai-feature/index.js';
18
+ import usePostContent from '../../hooks/use-post-content.js';
19
+ import useSaveToMediaLibrary from '../../hooks/use-save-to-media-library.js';
20
+ import AiImageModal from './components/ai-image-modal.js';
21
+ import useAiImage from './hooks/use-ai-image.js';
22
+ import useSiteType from './hooks/use-site-type.js';
23
+ import { FEATURED_IMAGE_FEATURE_NAME, IMAGE_GENERATION_MODEL_STABLE_DIFFUSION, IMAGE_GENERATION_MODEL_DALL_E_3, PLACEMENT_MEDIA_SOURCE_DROPDOWN, } from './types.js';
24
+ const debug = debugFactory('jetpack-ai-client:featured-image');
25
+ /**
26
+ * FeaturedImage component
27
+ * @param {FeaturedImageProps} props - The component properties.
28
+ * @return {React.ReactElement} - rendered component.
29
+ */
30
+ export default function FeaturedImage({ busy, disabled, placement, onClose = () => { }, }) {
31
+ const [isFeaturedImageModalVisible, setIsFeaturedImageModalVisible] = useState(placement === PLACEMENT_MEDIA_SOURCE_DROPDOWN);
32
+ const siteType = useSiteType();
33
+ const postContent = usePostContent();
34
+ const { postTitle, postFeaturedMediaId, isEditorPanelOpened } = useSelect(select => {
35
+ return {
36
+ postTitle: select(editorStore).getEditedPostAttribute('title'),
37
+ postFeaturedMediaId: select(editorStore).getEditedPostAttribute('featured_media'),
38
+ isEditorPanelOpened: select(editorStore).isEditorPanelOpened ??
39
+ select('core/edit-post').isEditorPanelOpened,
40
+ };
41
+ }, []);
42
+ const { saveToMediaLibrary } = useSaveToMediaLibrary();
43
+ const { tracks } = useAnalytics();
44
+ const { recordEvent } = tracks;
45
+ const [requestStyle, setRequestStyle] = useState(null);
46
+ const [prompt, setPrompt] = useState('');
47
+ // Editor actions
48
+ const { enableComplementaryArea } = useDispatch('core/interface');
49
+ const { clearSelectedBlock } = useDispatch('core/block-editor');
50
+ const { toggleEditorPanelOpened: toggleEditorPanelOpenedFromEditPost } = useDispatch('core/edit-post');
51
+ const { editPost, toggleEditorPanelOpened: toggleEditorPanelOpenedFromEditor } = useDispatch(editorStore);
52
+ // Get feature data
53
+ const { requireUpgrade, requestsCount, requestsLimit, currentTier, costs } = useAiFeature();
54
+ const planType = usePlanType(currentTier);
55
+ const featuredImageCost = costs?.[FEATURED_IMAGE_FEATURE_NAME]?.activeModel ?? 10;
56
+ const featuredImageActiveModel = featuredImageCost === costs?.[FEATURED_IMAGE_FEATURE_NAME]?.stableDiffusion
57
+ ? IMAGE_GENERATION_MODEL_STABLE_DIFFUSION
58
+ : IMAGE_GENERATION_MODEL_DALL_E_3;
59
+ const isUnlimited = planType === PLAN_TYPE_UNLIMITED;
60
+ const requestsBalance = requestsLimit - requestsCount;
61
+ const notEnoughRequests = requestsBalance < featuredImageCost;
62
+ // Handle deprecation and move of toggle action from edit-post.
63
+ // https://github.com/WordPress/gutenberg/blob/fe4d8cb936df52945c01c1863f7b87b58b7cc69f/packages/edit-post/CHANGELOG.md?plain=1#L19
64
+ const toggleEditorPanelOpened = toggleEditorPanelOpenedFromEditor ?? toggleEditorPanelOpenedFromEditPost;
65
+ const { pointer, current, setCurrent, processImageGeneration, handlePreviousImage, handleNextImage, currentImage, currentPointer, images, imageStyles, guessStyle, } = useAiImage({
66
+ autoStart: false,
67
+ cost: featuredImageCost,
68
+ type: 'featured-image-generation',
69
+ feature: FEATURED_IMAGE_FEATURE_NAME,
70
+ previousMediaId: postFeaturedMediaId,
71
+ });
72
+ const handleModalClose = useCallback(() => {
73
+ setIsFeaturedImageModalVisible(false);
74
+ onClose?.();
75
+ }, [onClose]);
76
+ const handleModalOpen = useCallback(() => {
77
+ setIsFeaturedImageModalVisible(true);
78
+ }, []);
79
+ /**
80
+ * Handle the guess style for the image. It is reworked here to include the post content.
81
+ */
82
+ const handleGuessStyle = useCallback(userPrompt => {
83
+ const content = postTitle + '\n\n' + postContent;
84
+ return guessStyle(userPrompt, 'featured-image-guess-style', content);
85
+ }, [postContent, postTitle, guessStyle]);
86
+ const handleGenerate = useCallback(({ userPrompt, style, }) => {
87
+ // track the generate image event
88
+ recordEvent('jetpack_ai_featured_image_generation_generate_image', {
89
+ placement,
90
+ model: featuredImageActiveModel,
91
+ site_type: siteType,
92
+ style,
93
+ userPrompt,
94
+ });
95
+ setIsFeaturedImageModalVisible(true);
96
+ return processImageGeneration({
97
+ userPrompt,
98
+ postContent: postTitle + '\n\n' + postContent,
99
+ notEnoughRequests,
100
+ style,
101
+ }).catch(error => {
102
+ recordEvent('jetpack_ai_featured_image_generation_error', {
103
+ placement,
104
+ error: error?.message,
105
+ model: featuredImageActiveModel,
106
+ site_type: siteType,
107
+ style,
108
+ });
109
+ });
110
+ }, [
111
+ recordEvent,
112
+ placement,
113
+ featuredImageActiveModel,
114
+ siteType,
115
+ processImageGeneration,
116
+ postContent,
117
+ notEnoughRequests,
118
+ postTitle,
119
+ ]);
120
+ const handleFirstGenerate = useCallback(async () => {
121
+ currentPointer.generating = true;
122
+ const guessedStyle = await handleGuessStyle('');
123
+ setRequestStyle(guessedStyle);
124
+ const response = await handleGenerate({ userPrompt: '', style: guessedStyle });
125
+ if (response) {
126
+ debug('handleFirstGenerate', response.revisedPrompt);
127
+ setPrompt(response.revisedPrompt || '');
128
+ }
129
+ }, [currentPointer, handleGenerate, handleGuessStyle]);
130
+ const handleRegenerate = useCallback(({ userPrompt, style }) => {
131
+ // track the regenerate image event
132
+ recordEvent('jetpack_ai_featured_image_generation_generate_another_image', {
133
+ placement,
134
+ model: featuredImageActiveModel,
135
+ site_type: siteType,
136
+ style: style,
137
+ });
138
+ setCurrent(() => images.length);
139
+ processImageGeneration({
140
+ userPrompt,
141
+ postContent: postTitle + '\n\n' + postContent,
142
+ notEnoughRequests,
143
+ style,
144
+ }).catch(error => {
145
+ recordEvent('jetpack_ai_featured_image_generation_error', {
146
+ placement,
147
+ error: error?.message,
148
+ model: featuredImageActiveModel,
149
+ site_type: siteType,
150
+ style,
151
+ userPrompt,
152
+ });
153
+ });
154
+ }, [
155
+ recordEvent,
156
+ placement,
157
+ featuredImageActiveModel,
158
+ siteType,
159
+ setCurrent,
160
+ processImageGeneration,
161
+ postTitle,
162
+ postContent,
163
+ notEnoughRequests,
164
+ images,
165
+ ]);
166
+ const handleTryAgain = useCallback(({ userPrompt, style }) => {
167
+ // track the try again event
168
+ recordEvent('jetpack_ai_featured_image_generation_try_again', {
169
+ placement,
170
+ model: featuredImageActiveModel,
171
+ site_type: siteType,
172
+ style,
173
+ });
174
+ processImageGeneration({
175
+ userPrompt,
176
+ postContent: postTitle + '\n\n' + postContent,
177
+ notEnoughRequests,
178
+ style,
179
+ }).catch(error => {
180
+ recordEvent('jetpack_ai_featured_image_generation_error', {
181
+ placement,
182
+ error: error?.message,
183
+ model: featuredImageActiveModel,
184
+ site_type: siteType,
185
+ style,
186
+ });
187
+ });
188
+ }, [
189
+ recordEvent,
190
+ placement,
191
+ featuredImageActiveModel,
192
+ siteType,
193
+ processImageGeneration,
194
+ postContent,
195
+ notEnoughRequests,
196
+ postTitle,
197
+ ]);
198
+ const triggerComplementaryArea = useCallback(() => {
199
+ // clear any block selection, because selected blocks have precedence on settings sidebar
200
+ clearSelectedBlock();
201
+ return enableComplementaryArea('core/edit-post', 'edit-post/document');
202
+ }, [clearSelectedBlock, enableComplementaryArea]);
203
+ const handleAccept = useCallback(() => {
204
+ // track the accept/use image event
205
+ recordEvent('jetpack_ai_featured_image_generation_use_image', {
206
+ placement,
207
+ model: featuredImageActiveModel,
208
+ site_type: siteType,
209
+ });
210
+ const setAsFeaturedImage = image => {
211
+ editPost({ featured_media: image });
212
+ handleModalClose();
213
+ // Open the featured image panel for users to see the new image.
214
+ setTimeout(() => {
215
+ const isFeaturedImagePanelOpened = isEditorPanelOpened('featured-image');
216
+ const isPostStatusPanelOpened = isEditorPanelOpened('post-status');
217
+ // open the complementary area and then trigger the featured image panel.
218
+ triggerComplementaryArea().then(() => {
219
+ if (!isFeaturedImagePanelOpened) {
220
+ toggleEditorPanelOpened('featured-image');
221
+ }
222
+ // handle the case where the featured image panel is not present
223
+ if (!isPostStatusPanelOpened) {
224
+ toggleEditorPanelOpened('post-status');
225
+ }
226
+ });
227
+ }, 500);
228
+ };
229
+ // If the image is already in the media library, use it directly, if it failed for some reason
230
+ // save it to the media library and then use it.
231
+ if (currentImage?.libraryId) {
232
+ setAsFeaturedImage(currentImage?.libraryId);
233
+ }
234
+ else {
235
+ saveToMediaLibrary(currentImage?.image)
236
+ .then(image => {
237
+ setAsFeaturedImage(image?.id);
238
+ })
239
+ .catch(error => {
240
+ recordEvent('jetpack_ai_featured_image_saving_error', {
241
+ placement,
242
+ error: error?.message,
243
+ model: featuredImageActiveModel,
244
+ site_type: siteType,
245
+ });
246
+ });
247
+ }
248
+ }, [
249
+ recordEvent,
250
+ placement,
251
+ featuredImageActiveModel,
252
+ siteType,
253
+ currentImage?.libraryId,
254
+ currentImage?.image,
255
+ editPost,
256
+ handleModalClose,
257
+ isEditorPanelOpened,
258
+ triggerComplementaryArea,
259
+ toggleEditorPanelOpened,
260
+ saveToMediaLibrary,
261
+ ]);
262
+ const generateAgainText = __('Generate another image', 'jetpack-ai-client');
263
+ const generateText = __('Generate', 'jetpack-ai-client');
264
+ const hasContent = postContent.trim?.() || postTitle.trim?.() ? true : false;
265
+ const hasPrompt = hasContent ? prompt.length >= 0 : prompt.length >= 3;
266
+ const disableInput = notEnoughRequests || currentPointer?.generating || requireUpgrade;
267
+ const disableAction = disableInput || (!hasContent && !hasPrompt);
268
+ const upgradeDescription = notEnoughRequests
269
+ ? sprintf(
270
+ // Translators: %d is the cost of generating a featured image.
271
+ __("Featured image generation costs %d requests per image. You don't have enough requests to generate another image.", 'jetpack-ai-client'), featuredImageCost)
272
+ : null;
273
+ const acceptButton = (_jsx(Button, { onClick: handleAccept, variant: "primary", disabled: !currentImage?.image ||
274
+ currentImage?.generating ||
275
+ currentImage?.libraryId === postFeaturedMediaId, children: __('Set as featured image', 'jetpack-ai-client') }));
276
+ return (_jsxs(_Fragment, { children: [(placement === PLACEMENT_JETPACK_SIDEBAR ||
277
+ placement === PLACEMENT_DOCUMENT_SETTINGS) && (_jsxs(_Fragment, { children: [_jsx("p", { className: "jetpack-ai-assistant__help-text", children: __('Based on your post content.', 'jetpack-ai-client') }), _jsx(Button, { onClick: handleModalOpen, isBusy: busy, disabled: disabled || notEnoughRequests, variant: "secondary", __next40pxDefaultSize: true, children: __('Generate image', 'jetpack-ai-client') })] })), _jsx(AiImageModal, { postContent: hasContent, autoStart: hasContent && !postFeaturedMediaId, autoStartAction: handleFirstGenerate, images: images, currentIndex: current, title: __('Generate a featured image with AI', 'jetpack-ai-client'), cost: featuredImageCost, open: isFeaturedImageModalVisible, placement: placement, onClose: handleModalClose, onTryAgain: handleTryAgain, onGenerate: pointer?.current > 0 || postFeaturedMediaId ? handleRegenerate : handleGenerate, generating: currentPointer?.generating, notEnoughRequests: notEnoughRequests, requireUpgrade: requireUpgrade, upgradeDescription: upgradeDescription, currentLimit: requestsLimit, currentUsage: requestsCount, isUnlimited: isUnlimited, hasError: Boolean(currentPointer?.error), handlePreviousImage: handlePreviousImage, handleNextImage: handleNextImage, acceptButton: acceptButton, generateButtonLabel: pointer?.current > 0 ? generateAgainText : generateText, instructionsPlaceholder: __("Describe the featured image you'd like to create and select a style.", 'jetpack-ai-client'), imageStyles: imageStyles, onGuessStyle: handleGuessStyle, prompt: prompt, setPrompt: setPrompt, initialStyle: requestStyle, inputDisabled: disableInput, actionDisabled: disableAction })] }));
278
+ }