@automattic/jetpack-ai-client 0.12.1 → 0.12.3
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.
- package/CHANGELOG.md +10 -0
- package/build/components/ai-control/ai-control.d.ts +28 -0
- package/build/components/ai-control/ai-control.js +22 -0
- package/build/components/ai-control/block-ai-control.d.ts +37 -0
- package/build/components/ai-control/block-ai-control.js +82 -0
- package/build/components/ai-control/extension-ai-control.d.ts +35 -0
- package/build/components/ai-control/extension-ai-control.js +86 -0
- package/build/components/ai-control/index.d.ts +3 -40
- package/build/components/ai-control/index.js +3 -86
- package/build/components/index.d.ts +2 -2
- package/build/components/index.js +2 -2
- package/build/components/{ai-control/message.d.ts → message/index.d.ts} +25 -8
- package/build/components/message/index.js +69 -0
- package/build/icons/error-exclamation.d.ts +2 -0
- package/build/icons/error-exclamation.js +7 -0
- package/build/index.d.ts +1 -0
- package/build/index.js +4 -0
- package/build/libs/index.d.ts +1 -0
- package/build/libs/index.js +1 -0
- package/build/libs/markdown/html-to-markdown.d.ts +23 -0
- package/build/libs/markdown/html-to-markdown.js +31 -0
- package/build/libs/markdown/index.d.ts +17 -0
- package/build/libs/markdown/index.js +14 -0
- package/build/libs/markdown/markdown-to-html.d.ts +24 -0
- package/build/libs/markdown/markdown-to-html.js +33 -0
- package/build/types.d.ts +10 -0
- package/package.json +8 -3
- package/src/components/ai-control/ai-control.tsx +79 -0
- package/src/components/ai-control/block-ai-control.tsx +278 -0
- package/src/components/ai-control/extension-ai-control.tsx +217 -0
- package/src/components/ai-control/index.tsx +3 -281
- package/src/components/ai-control/style.scss +4 -42
- package/src/components/index.ts +3 -2
- package/src/components/message/index.tsx +157 -0
- package/src/components/message/style.scss +83 -0
- package/src/icons/error-exclamation.tsx +18 -0
- package/src/index.ts +5 -0
- package/src/libs/index.ts +6 -0
- package/src/libs/markdown/README.md +74 -0
- package/src/libs/markdown/html-to-markdown.ts +42 -0
- package/src/libs/markdown/index.ts +28 -0
- package/src/libs/markdown/markdown-to-html.ts +48 -0
- package/src/types.ts +11 -0
- package/build/components/ai-control/message.js +0 -57
- package/src/components/ai-control/message.tsx +0 -118
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import TurndownService from 'turndown';
|
|
5
|
+
/**
|
|
6
|
+
* Types
|
|
7
|
+
*/
|
|
8
|
+
import type { Options, Rule } from 'turndown';
|
|
9
|
+
export default class HTMLToMarkdown {
|
|
10
|
+
turndownService: TurndownService;
|
|
11
|
+
constructor(options?: Options, rules?: {
|
|
12
|
+
[key: string]: Rule;
|
|
13
|
+
});
|
|
14
|
+
/**
|
|
15
|
+
* Renders HTML from Markdown content with specified processing rules.
|
|
16
|
+
* @param {object} options - The options to use when rendering the Markdown content
|
|
17
|
+
* @param {string} options.content - The HTML content to render
|
|
18
|
+
* @returns {string} The rendered Markdown content
|
|
19
|
+
*/
|
|
20
|
+
render({ content }: {
|
|
21
|
+
content: string;
|
|
22
|
+
}): string;
|
|
23
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import TurndownService from 'turndown';
|
|
5
|
+
const defaultTurndownOptions = { emDelimiter: '_', headingStyle: 'atx' };
|
|
6
|
+
const defaultTurndownRules = {
|
|
7
|
+
strikethrough: {
|
|
8
|
+
filter: ['del', 's'],
|
|
9
|
+
replacement: function (content) {
|
|
10
|
+
return '~~' + content + '~~';
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
export default class HTMLToMarkdown {
|
|
15
|
+
turndownService;
|
|
16
|
+
constructor(options = defaultTurndownOptions, rules = defaultTurndownRules) {
|
|
17
|
+
this.turndownService = new TurndownService(options);
|
|
18
|
+
for (const rule in rules) {
|
|
19
|
+
this.turndownService.addRule(rule, rules[rule]);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Renders HTML from Markdown content with specified processing rules.
|
|
24
|
+
* @param {object} options - The options to use when rendering the Markdown content
|
|
25
|
+
* @param {string} options.content - The HTML content to render
|
|
26
|
+
* @returns {string} The rendered Markdown content
|
|
27
|
+
*/
|
|
28
|
+
render({ content }) {
|
|
29
|
+
return this.turndownService.turndown(content);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal dependencies
|
|
3
|
+
*/
|
|
4
|
+
import HTMLToMarkdown from './html-to-markdown.js';
|
|
5
|
+
import MarkdownToHTML from './markdown-to-html.js';
|
|
6
|
+
/**
|
|
7
|
+
* Types
|
|
8
|
+
*/
|
|
9
|
+
import type { Fix as HTMLFix } from './markdown-to-html.js';
|
|
10
|
+
declare const renderHTMLFromMarkdown: ({ content, rules, }: {
|
|
11
|
+
content: string;
|
|
12
|
+
rules?: Array<HTMLFix> | 'all';
|
|
13
|
+
}) => string;
|
|
14
|
+
declare const renderMarkdownFromHTML: ({ content }: {
|
|
15
|
+
content: string;
|
|
16
|
+
}) => string;
|
|
17
|
+
export { MarkdownToHTML, HTMLToMarkdown, renderHTMLFromMarkdown, renderMarkdownFromHTML };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal dependencies
|
|
3
|
+
*/
|
|
4
|
+
import HTMLToMarkdown from './html-to-markdown.js';
|
|
5
|
+
import MarkdownToHTML from './markdown-to-html.js';
|
|
6
|
+
const defaultMarkdownConverter = new MarkdownToHTML();
|
|
7
|
+
const defaultHTMLConverter = new HTMLToMarkdown();
|
|
8
|
+
const renderHTMLFromMarkdown = ({ content, rules = 'all', }) => {
|
|
9
|
+
return defaultMarkdownConverter.render({ content, rules });
|
|
10
|
+
};
|
|
11
|
+
const renderMarkdownFromHTML = ({ content }) => {
|
|
12
|
+
return defaultHTMLConverter.render({ content });
|
|
13
|
+
};
|
|
14
|
+
export { MarkdownToHTML, HTMLToMarkdown, renderHTMLFromMarkdown, renderMarkdownFromHTML };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import MarkdownIt from 'markdown-it';
|
|
5
|
+
/**
|
|
6
|
+
* Types
|
|
7
|
+
*/
|
|
8
|
+
import type { Options } from 'markdown-it';
|
|
9
|
+
export type Fix = 'list';
|
|
10
|
+
export default class MarkdownToHTML {
|
|
11
|
+
markdownConverter: MarkdownIt;
|
|
12
|
+
constructor(options?: Options);
|
|
13
|
+
/**
|
|
14
|
+
* Renders HTML from Markdown content with specified processing rules.
|
|
15
|
+
* @param {object} options - The options to use when rendering the HTML content
|
|
16
|
+
* @param {string} options.content - The Markdown content to render
|
|
17
|
+
* @param {string} options.rules - The rules to apply to the rendered content
|
|
18
|
+
* @returns {string} The rendered HTML content
|
|
19
|
+
*/
|
|
20
|
+
render({ content, rules }: {
|
|
21
|
+
content: string;
|
|
22
|
+
rules: Array<Fix> | 'all';
|
|
23
|
+
}): string;
|
|
24
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import MarkdownIt from 'markdown-it';
|
|
5
|
+
const fixes = {
|
|
6
|
+
list: (content) => {
|
|
7
|
+
// Fix list indentation
|
|
8
|
+
return content.replace(/<li>\s+<p>/g, '<li>').replace(/<\/p>\s+<\/li>/g, '</li>');
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
const defaultMarkdownItOptions = {
|
|
12
|
+
breaks: true,
|
|
13
|
+
};
|
|
14
|
+
export default class MarkdownToHTML {
|
|
15
|
+
markdownConverter;
|
|
16
|
+
constructor(options = defaultMarkdownItOptions) {
|
|
17
|
+
this.markdownConverter = new MarkdownIt(options);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Renders HTML from Markdown content with specified processing rules.
|
|
21
|
+
* @param {object} options - The options to use when rendering the HTML content
|
|
22
|
+
* @param {string} options.content - The Markdown content to render
|
|
23
|
+
* @param {string} options.rules - The rules to apply to the rendered content
|
|
24
|
+
* @returns {string} The rendered HTML content
|
|
25
|
+
*/
|
|
26
|
+
render({ content, rules = 'all' }) {
|
|
27
|
+
const rendered = this.markdownConverter.render(content);
|
|
28
|
+
const rulesToApply = rules === 'all' ? Object.keys(fixes) : rules;
|
|
29
|
+
return rulesToApply.reduce((renderedContent, rule) => {
|
|
30
|
+
return fixes[rule](renderedContent);
|
|
31
|
+
}, rendered);
|
|
32
|
+
}
|
|
33
|
+
}
|
package/build/types.d.ts
CHANGED
|
@@ -28,4 +28,14 @@ export type { RecordingState } from './hooks/use-media-recording/index.js';
|
|
|
28
28
|
export type CancelablePromise<T = void> = Promise<T> & {
|
|
29
29
|
canceled?: boolean;
|
|
30
30
|
};
|
|
31
|
+
export type Block = {
|
|
32
|
+
attributes?: {
|
|
33
|
+
[key: string]: unknown;
|
|
34
|
+
};
|
|
35
|
+
clientId?: string;
|
|
36
|
+
innerBlocks?: Block[];
|
|
37
|
+
isValid?: boolean;
|
|
38
|
+
name?: string;
|
|
39
|
+
originalContent?: string;
|
|
40
|
+
};
|
|
31
41
|
export type TranscriptionState = RecordingState | 'validating' | 'processing' | 'error';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"private": false,
|
|
3
3
|
"name": "@automattic/jetpack-ai-client",
|
|
4
|
-
"version": "0.12.
|
|
4
|
+
"version": "0.12.3",
|
|
5
5
|
"description": "A JS client for consuming Jetpack AI services",
|
|
6
6
|
"homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/ai-client/#readme",
|
|
7
7
|
"bugs": {
|
|
@@ -25,7 +25,10 @@
|
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@storybook/addon-actions": "8.0.6",
|
|
27
27
|
"@storybook/blocks": "8.0.6",
|
|
28
|
+
"@storybook/preview-api": "8.0.6",
|
|
28
29
|
"@storybook/react": "8.0.6",
|
|
30
|
+
"@types/markdown-it": "14.0.0",
|
|
31
|
+
"@types/turndown": "5.0.4",
|
|
29
32
|
"jest": "^29.6.2",
|
|
30
33
|
"jest-environment-jsdom": "29.7.0",
|
|
31
34
|
"typescript": "5.0.4"
|
|
@@ -39,7 +42,7 @@
|
|
|
39
42
|
"main": "./build/index.js",
|
|
40
43
|
"types": "./build/index.d.ts",
|
|
41
44
|
"dependencies": {
|
|
42
|
-
"@automattic/jetpack-base-styles": "^0.6.
|
|
45
|
+
"@automattic/jetpack-base-styles": "^0.6.23",
|
|
43
46
|
"@automattic/jetpack-connection": "^0.33.8",
|
|
44
47
|
"@automattic/jetpack-shared-extension-utils": "^0.14.10",
|
|
45
48
|
"@microsoft/fetch-event-source": "2.0.1",
|
|
@@ -54,7 +57,9 @@
|
|
|
54
57
|
"@wordpress/icons": "9.46.0",
|
|
55
58
|
"classnames": "2.3.2",
|
|
56
59
|
"debug": "4.3.4",
|
|
60
|
+
"markdown-it": "14.0.0",
|
|
57
61
|
"react": "18.2.0",
|
|
58
|
-
"react-dom": "18.2.0"
|
|
62
|
+
"react-dom": "18.2.0",
|
|
63
|
+
"turndown": "7.1.2"
|
|
59
64
|
}
|
|
60
65
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { PlainText } from '@wordpress/block-editor';
|
|
5
|
+
import classNames from 'classnames';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
/**
|
|
8
|
+
* Internal dependencies
|
|
9
|
+
*/
|
|
10
|
+
import AiStatusIndicator from '../ai-status-indicator/index.js';
|
|
11
|
+
import './style.scss';
|
|
12
|
+
/**
|
|
13
|
+
* Types
|
|
14
|
+
*/
|
|
15
|
+
import type { RequestingStateProp } from '../../types.js';
|
|
16
|
+
import type { ReactElement } from 'react';
|
|
17
|
+
|
|
18
|
+
type AIControlProps = {
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
value: string;
|
|
21
|
+
placeholder?: string;
|
|
22
|
+
isTransparent?: boolean;
|
|
23
|
+
state?: RequestingStateProp;
|
|
24
|
+
onChange?: ( newValue: string ) => void;
|
|
25
|
+
banner?: ReactElement;
|
|
26
|
+
error?: ReactElement;
|
|
27
|
+
actions?: ReactElement;
|
|
28
|
+
message?: ReactElement;
|
|
29
|
+
promptUserInputRef?: React.MutableRefObject< HTMLInputElement >;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Base AIControl component. Contains the main structure of the control component and slots for banner, error, actions and message.
|
|
34
|
+
*
|
|
35
|
+
* @param {AIControlProps} props - Component props
|
|
36
|
+
* @returns {ReactElement} Rendered component
|
|
37
|
+
*/
|
|
38
|
+
export default function AIControl( {
|
|
39
|
+
disabled = false,
|
|
40
|
+
value = '',
|
|
41
|
+
placeholder = '',
|
|
42
|
+
isTransparent = false,
|
|
43
|
+
state = 'init',
|
|
44
|
+
onChange,
|
|
45
|
+
banner = null,
|
|
46
|
+
error = null,
|
|
47
|
+
actions = null,
|
|
48
|
+
message = null,
|
|
49
|
+
promptUserInputRef = null,
|
|
50
|
+
}: AIControlProps ): ReactElement {
|
|
51
|
+
return (
|
|
52
|
+
<div className="jetpack-components-ai-control__container-wrapper">
|
|
53
|
+
{ error }
|
|
54
|
+
<div className="jetpack-components-ai-control__container">
|
|
55
|
+
{ banner }
|
|
56
|
+
<div
|
|
57
|
+
className={ classNames( 'jetpack-components-ai-control__wrapper', {
|
|
58
|
+
'is-transparent': isTransparent,
|
|
59
|
+
} ) }
|
|
60
|
+
>
|
|
61
|
+
<AiStatusIndicator state={ state } />
|
|
62
|
+
|
|
63
|
+
<div className="jetpack-components-ai-control__input-wrapper">
|
|
64
|
+
<PlainText
|
|
65
|
+
value={ value }
|
|
66
|
+
onChange={ onChange }
|
|
67
|
+
placeholder={ placeholder }
|
|
68
|
+
className="jetpack-components-ai-control__input"
|
|
69
|
+
disabled={ disabled }
|
|
70
|
+
ref={ promptUserInputRef }
|
|
71
|
+
/>
|
|
72
|
+
</div>
|
|
73
|
+
{ actions }
|
|
74
|
+
</div>
|
|
75
|
+
{ message }
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { Button, ButtonGroup } from '@wordpress/components';
|
|
5
|
+
import { useKeyboardShortcut } from '@wordpress/compose';
|
|
6
|
+
import { useImperativeHandle, useRef, useEffect, useCallback, useState } from '@wordpress/element';
|
|
7
|
+
import { __ } from '@wordpress/i18n';
|
|
8
|
+
import {
|
|
9
|
+
Icon,
|
|
10
|
+
closeSmall,
|
|
11
|
+
check,
|
|
12
|
+
arrowUp,
|
|
13
|
+
trash,
|
|
14
|
+
reusableBlock as regenerate,
|
|
15
|
+
} from '@wordpress/icons';
|
|
16
|
+
import debugFactory from 'debug';
|
|
17
|
+
import React, { forwardRef } from 'react';
|
|
18
|
+
/**
|
|
19
|
+
* Internal dependencies
|
|
20
|
+
*/
|
|
21
|
+
import { GuidelineMessage } from '../message/index.js';
|
|
22
|
+
import AIControl from './ai-control.js';
|
|
23
|
+
import './style.scss';
|
|
24
|
+
/**
|
|
25
|
+
* Types
|
|
26
|
+
*/
|
|
27
|
+
import type { RequestingStateProp } from '../../types.js';
|
|
28
|
+
import type { ReactElement } from 'react';
|
|
29
|
+
|
|
30
|
+
type BlockAIControlProps = {
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
value: string;
|
|
33
|
+
placeholder?: string;
|
|
34
|
+
showAccept?: boolean;
|
|
35
|
+
acceptLabel?: string;
|
|
36
|
+
showButtonLabels?: boolean;
|
|
37
|
+
isTransparent?: boolean;
|
|
38
|
+
state?: RequestingStateProp;
|
|
39
|
+
showGuideLine?: boolean;
|
|
40
|
+
customFooter?: ReactElement;
|
|
41
|
+
onChange?: ( newValue: string ) => void;
|
|
42
|
+
onSend?: ( currentValue: string ) => void;
|
|
43
|
+
onStop?: () => void;
|
|
44
|
+
onAccept?: () => void;
|
|
45
|
+
onDiscard?: () => void;
|
|
46
|
+
showRemove?: boolean;
|
|
47
|
+
banner?: ReactElement;
|
|
48
|
+
error?: ReactElement;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const debug = debugFactory( 'jetpack-ai-client:block-ai-control' );
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* BlockAIControl component. Used by the AI Assistant block, adding logic and components to the base AIControl component.
|
|
55
|
+
*
|
|
56
|
+
* @param {BlockAIControlProps} props - Component props
|
|
57
|
+
* @param {React.MutableRefObject} ref - Ref to the component
|
|
58
|
+
* @returns {ReactElement} Rendered component
|
|
59
|
+
*/
|
|
60
|
+
export function BlockAIControl(
|
|
61
|
+
{
|
|
62
|
+
disabled = false,
|
|
63
|
+
value = '',
|
|
64
|
+
placeholder = '',
|
|
65
|
+
showAccept = false,
|
|
66
|
+
acceptLabel = __( 'Accept', 'jetpack-ai-client' ),
|
|
67
|
+
showButtonLabels = true,
|
|
68
|
+
isTransparent = false,
|
|
69
|
+
state = 'init',
|
|
70
|
+
showGuideLine = false,
|
|
71
|
+
customFooter = null,
|
|
72
|
+
onChange,
|
|
73
|
+
onSend,
|
|
74
|
+
onStop,
|
|
75
|
+
onAccept,
|
|
76
|
+
onDiscard,
|
|
77
|
+
showRemove = false,
|
|
78
|
+
banner = null,
|
|
79
|
+
error = null,
|
|
80
|
+
}: BlockAIControlProps,
|
|
81
|
+
ref: React.MutableRefObject< HTMLInputElement >
|
|
82
|
+
): ReactElement {
|
|
83
|
+
const loading = state === 'requesting' || state === 'suggesting';
|
|
84
|
+
const [ editRequest, setEditRequest ] = useState( false );
|
|
85
|
+
const [ lastValue, setLastValue ] = useState( value || null );
|
|
86
|
+
const promptUserInputRef = useRef( null );
|
|
87
|
+
|
|
88
|
+
// Pass the ref to forwardRef.
|
|
89
|
+
useImperativeHandle( ref, () => promptUserInputRef.current );
|
|
90
|
+
|
|
91
|
+
useEffect( () => {
|
|
92
|
+
if ( editRequest ) {
|
|
93
|
+
promptUserInputRef?.current?.focus();
|
|
94
|
+
}
|
|
95
|
+
}, [ editRequest ] );
|
|
96
|
+
|
|
97
|
+
const sendHandler = useCallback( () => {
|
|
98
|
+
setLastValue( value );
|
|
99
|
+
setEditRequest( false );
|
|
100
|
+
onSend?.( value );
|
|
101
|
+
}, [ value ] );
|
|
102
|
+
|
|
103
|
+
const changeHandler = useCallback(
|
|
104
|
+
( newValue: string ) => {
|
|
105
|
+
onChange?.( newValue );
|
|
106
|
+
if ( state === 'init' ) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if ( ! lastValue ) {
|
|
111
|
+
// here we're coming from a one-click action
|
|
112
|
+
setEditRequest( newValue.length > 0 );
|
|
113
|
+
} else {
|
|
114
|
+
// here we're coming from an edit action
|
|
115
|
+
setEditRequest( newValue !== lastValue );
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
[ lastValue, state ]
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const discardHandler = useCallback( () => {
|
|
122
|
+
onDiscard?.();
|
|
123
|
+
}, [] );
|
|
124
|
+
|
|
125
|
+
const cancelEdit = useCallback( () => {
|
|
126
|
+
debug( 'cancelEdit, revert to last value', lastValue );
|
|
127
|
+
onChange?.( lastValue || '' );
|
|
128
|
+
setEditRequest( false );
|
|
129
|
+
}, [ lastValue ] );
|
|
130
|
+
|
|
131
|
+
useKeyboardShortcut(
|
|
132
|
+
'mod+enter',
|
|
133
|
+
() => {
|
|
134
|
+
if ( showAccept ) {
|
|
135
|
+
onAccept?.();
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
target: promptUserInputRef,
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
useKeyboardShortcut(
|
|
144
|
+
'enter',
|
|
145
|
+
e => {
|
|
146
|
+
e.preventDefault();
|
|
147
|
+
sendHandler();
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
target: promptUserInputRef,
|
|
151
|
+
}
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
const actions = (
|
|
155
|
+
<>
|
|
156
|
+
{ ( ! showAccept || editRequest ) && (
|
|
157
|
+
<div className="jetpack-components-ai-control__controls-prompt_button_wrapper">
|
|
158
|
+
{ ! loading ? (
|
|
159
|
+
<>
|
|
160
|
+
{ editRequest && (
|
|
161
|
+
<Button
|
|
162
|
+
className="jetpack-components-ai-control__controls-prompt_button"
|
|
163
|
+
onClick={ cancelEdit }
|
|
164
|
+
variant="secondary"
|
|
165
|
+
label={ __( 'Cancel', 'jetpack-ai-client' ) }
|
|
166
|
+
>
|
|
167
|
+
{ showButtonLabels ? (
|
|
168
|
+
__( 'Cancel', 'jetpack-ai-client' )
|
|
169
|
+
) : (
|
|
170
|
+
<Icon icon={ closeSmall } />
|
|
171
|
+
) }
|
|
172
|
+
</Button>
|
|
173
|
+
) }
|
|
174
|
+
|
|
175
|
+
{ showRemove && ! editRequest && ! value?.length && onDiscard && (
|
|
176
|
+
<Button
|
|
177
|
+
className="jetpack-components-ai-control__controls-prompt_button"
|
|
178
|
+
onClick={ discardHandler }
|
|
179
|
+
variant="secondary"
|
|
180
|
+
label={ __( 'Cancel', 'jetpack-ai-client' ) }
|
|
181
|
+
>
|
|
182
|
+
{ showButtonLabels ? (
|
|
183
|
+
__( 'Cancel', 'jetpack-ai-client' )
|
|
184
|
+
) : (
|
|
185
|
+
<Icon icon={ closeSmall } />
|
|
186
|
+
) }
|
|
187
|
+
</Button>
|
|
188
|
+
) }
|
|
189
|
+
|
|
190
|
+
{ value?.length > 0 && (
|
|
191
|
+
<Button
|
|
192
|
+
className="jetpack-components-ai-control__controls-prompt_button"
|
|
193
|
+
onClick={ sendHandler }
|
|
194
|
+
variant="primary"
|
|
195
|
+
disabled={ ! value?.length || disabled }
|
|
196
|
+
label={ __( 'Send request', 'jetpack-ai-client' ) }
|
|
197
|
+
>
|
|
198
|
+
{ showButtonLabels ? (
|
|
199
|
+
__( 'Generate', 'jetpack-ai-client' )
|
|
200
|
+
) : (
|
|
201
|
+
<Icon icon={ arrowUp } />
|
|
202
|
+
) }
|
|
203
|
+
</Button>
|
|
204
|
+
) }
|
|
205
|
+
</>
|
|
206
|
+
) : (
|
|
207
|
+
<Button
|
|
208
|
+
className="jetpack-components-ai-control__controls-prompt_button"
|
|
209
|
+
onClick={ onStop }
|
|
210
|
+
variant="secondary"
|
|
211
|
+
label={ __( 'Stop request', 'jetpack-ai-client' ) }
|
|
212
|
+
>
|
|
213
|
+
{ showButtonLabels ? (
|
|
214
|
+
__( 'Stop', 'jetpack-ai-client' )
|
|
215
|
+
) : (
|
|
216
|
+
<Icon icon={ closeSmall } />
|
|
217
|
+
) }
|
|
218
|
+
</Button>
|
|
219
|
+
) }
|
|
220
|
+
</div>
|
|
221
|
+
) }
|
|
222
|
+
{ showAccept && ! editRequest && (
|
|
223
|
+
<div className="jetpack-components-ai-control__controls-prompt_button_wrapper">
|
|
224
|
+
{ ( value?.length > 0 || lastValue === null ) && (
|
|
225
|
+
<ButtonGroup>
|
|
226
|
+
<Button
|
|
227
|
+
className="jetpack-components-ai-control__controls-prompt_button"
|
|
228
|
+
label={ __( 'Discard', 'jetpack-ai-client' ) }
|
|
229
|
+
onClick={ discardHandler }
|
|
230
|
+
tooltipPosition="top"
|
|
231
|
+
>
|
|
232
|
+
<Icon icon={ trash } />
|
|
233
|
+
</Button>
|
|
234
|
+
<Button
|
|
235
|
+
className="jetpack-components-ai-control__controls-prompt_button"
|
|
236
|
+
label={ __( 'Regenerate', 'jetpack-ai-client' ) }
|
|
237
|
+
onClick={ () => onSend?.( value ) }
|
|
238
|
+
tooltipPosition="top"
|
|
239
|
+
disabled={ ! value?.length || value === null || disabled }
|
|
240
|
+
>
|
|
241
|
+
<Icon icon={ regenerate } />
|
|
242
|
+
</Button>
|
|
243
|
+
</ButtonGroup>
|
|
244
|
+
) }
|
|
245
|
+
<Button
|
|
246
|
+
className="jetpack-components-ai-control__controls-prompt_button"
|
|
247
|
+
onClick={ onAccept }
|
|
248
|
+
variant="primary"
|
|
249
|
+
label={ acceptLabel }
|
|
250
|
+
>
|
|
251
|
+
{ showButtonLabels ? acceptLabel : <Icon icon={ check } /> }
|
|
252
|
+
</Button>
|
|
253
|
+
</div>
|
|
254
|
+
) }
|
|
255
|
+
</>
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
const message =
|
|
259
|
+
showGuideLine && ! loading && ! editRequest && ( customFooter || <GuidelineMessage /> );
|
|
260
|
+
|
|
261
|
+
return (
|
|
262
|
+
<AIControl
|
|
263
|
+
disabled={ disabled || loading }
|
|
264
|
+
value={ value }
|
|
265
|
+
placeholder={ placeholder }
|
|
266
|
+
isTransparent={ isTransparent }
|
|
267
|
+
state={ state }
|
|
268
|
+
onChange={ changeHandler }
|
|
269
|
+
banner={ banner }
|
|
270
|
+
error={ error }
|
|
271
|
+
actions={ actions }
|
|
272
|
+
message={ message }
|
|
273
|
+
promptUserInputRef={ promptUserInputRef }
|
|
274
|
+
/>
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export default forwardRef( BlockAIControl );
|