diff --git a/projects/js-packages/ai-client/changelog/change-jetpack-ai-modal-prompt-input-reuse b/projects/js-packages/ai-client/changelog/change-jetpack-ai-modal-prompt-input-reuse new file mode 100644 index 0000000000000..c4a38f6eb8440 --- /dev/null +++ b/projects/js-packages/ai-client/changelog/change-jetpack-ai-modal-prompt-input-reuse @@ -0,0 +1,4 @@ +Significance: minor +Type: changed + +AI Client: decouple prompt input as component and export it for reusability diff --git a/projects/js-packages/ai-client/src/logo-generator/components/prompt.tsx b/projects/js-packages/ai-client/src/logo-generator/components/prompt.tsx index 643bd0e3eb9fa..13a83c5a14140 100644 --- a/projects/js-packages/ai-client/src/logo-generator/components/prompt.tsx +++ b/projects/js-packages/ai-client/src/logo-generator/components/prompt.tsx @@ -7,6 +7,7 @@ import { __, sprintf } from '@wordpress/i18n'; import { Icon, info } from '@wordpress/icons'; import debugFactory from 'debug'; import { useCallback, useEffect, useState, useRef } from 'react'; +import { Dispatch, SetStateAction } from 'react'; /** * Internal dependencies */ @@ -37,6 +38,81 @@ type PromptProps = { initialPrompt?: string; }; +export const AiModalPromptInput = ( { + prompt = '', + setPrompt = () => {}, + disabled = false, + generateHandler = () => {}, + placeholder = '', + buttonLabel = '', +}: { + prompt: string; + setPrompt: Dispatch< SetStateAction< string > >; + disabled: boolean; + generateHandler: () => void; + placeholder?: string; + buttonLabel?: string; +} ) => { + const inputRef = useRef< HTMLDivElement | null >( null ); + const hasPrompt = prompt?.length >= MINIMUM_PROMPT_LENGTH; + + const onPromptInput = ( event: React.ChangeEvent< HTMLInputElement > ) => { + setPrompt( event.target.textContent || '' ); + }; + + const onPromptPaste = ( event: React.ClipboardEvent< HTMLInputElement > ) => { + event.preventDefault(); + + const selection = event.currentTarget.ownerDocument.getSelection(); + if ( ! selection || ! selection.rangeCount ) { + return; + } + + // Paste plain text only + const text = event.clipboardData.getData( 'text/plain' ); + + selection.deleteFromDocument(); + const range = selection.getRangeAt( 0 ); + range.insertNode( document.createTextNode( text ) ); + selection.collapseToEnd(); + + setPrompt( inputRef.current?.textContent || '' ); + }; + + const onKeyDown = ( event: React.KeyboardEvent ) => { + if ( event.key === 'Enter' ) { + event.preventDefault(); + generateHandler(); + } + }; + + return ( +