@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.
Files changed (45) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/build/components/ai-control/ai-control.d.ts +28 -0
  3. package/build/components/ai-control/ai-control.js +22 -0
  4. package/build/components/ai-control/block-ai-control.d.ts +37 -0
  5. package/build/components/ai-control/block-ai-control.js +82 -0
  6. package/build/components/ai-control/extension-ai-control.d.ts +35 -0
  7. package/build/components/ai-control/extension-ai-control.js +86 -0
  8. package/build/components/ai-control/index.d.ts +3 -40
  9. package/build/components/ai-control/index.js +3 -86
  10. package/build/components/index.d.ts +2 -2
  11. package/build/components/index.js +2 -2
  12. package/build/components/{ai-control/message.d.ts → message/index.d.ts} +25 -8
  13. package/build/components/message/index.js +69 -0
  14. package/build/icons/error-exclamation.d.ts +2 -0
  15. package/build/icons/error-exclamation.js +7 -0
  16. package/build/index.d.ts +1 -0
  17. package/build/index.js +4 -0
  18. package/build/libs/index.d.ts +1 -0
  19. package/build/libs/index.js +1 -0
  20. package/build/libs/markdown/html-to-markdown.d.ts +23 -0
  21. package/build/libs/markdown/html-to-markdown.js +31 -0
  22. package/build/libs/markdown/index.d.ts +17 -0
  23. package/build/libs/markdown/index.js +14 -0
  24. package/build/libs/markdown/markdown-to-html.d.ts +24 -0
  25. package/build/libs/markdown/markdown-to-html.js +33 -0
  26. package/build/types.d.ts +10 -0
  27. package/package.json +8 -3
  28. package/src/components/ai-control/ai-control.tsx +79 -0
  29. package/src/components/ai-control/block-ai-control.tsx +278 -0
  30. package/src/components/ai-control/extension-ai-control.tsx +217 -0
  31. package/src/components/ai-control/index.tsx +3 -281
  32. package/src/components/ai-control/style.scss +4 -42
  33. package/src/components/index.ts +3 -2
  34. package/src/components/message/index.tsx +157 -0
  35. package/src/components/message/style.scss +83 -0
  36. package/src/icons/error-exclamation.tsx +18 -0
  37. package/src/index.ts +5 -0
  38. package/src/libs/index.ts +6 -0
  39. package/src/libs/markdown/README.md +74 -0
  40. package/src/libs/markdown/html-to-markdown.ts +42 -0
  41. package/src/libs/markdown/index.ts +28 -0
  42. package/src/libs/markdown/markdown-to-html.ts +48 -0
  43. package/src/types.ts +11 -0
  44. package/build/components/ai-control/message.js +0 -57
  45. package/src/components/ai-control/message.tsx +0 -118
@@ -0,0 +1,157 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { ExternalLink, Button } from '@wordpress/components';
5
+ import { __, sprintf } from '@wordpress/i18n';
6
+ import { Icon, check, arrowRight } from '@wordpress/icons';
7
+ import classNames from 'classnames';
8
+ /**
9
+ * Internal dependencies
10
+ */
11
+ import './style.scss';
12
+ import errorExclamation from '../../icons/error-exclamation.js';
13
+ /**
14
+ * Types
15
+ */
16
+ import type React from 'react';
17
+
18
+ export const MESSAGE_SEVERITY_WARNING = 'warning';
19
+ export const MESSAGE_SEVERITY_ERROR = 'error';
20
+ export const MESSAGE_SEVERITY_SUCCESS = 'success';
21
+ export const MESSAGE_SEVERITY_INFO = 'info';
22
+
23
+ const messageSeverityTypes = [
24
+ MESSAGE_SEVERITY_WARNING,
25
+ MESSAGE_SEVERITY_ERROR,
26
+ MESSAGE_SEVERITY_SUCCESS,
27
+ MESSAGE_SEVERITY_INFO,
28
+ ] as const;
29
+
30
+ export type MessageSeverityProp = ( typeof messageSeverityTypes )[ number ] | null;
31
+
32
+ export type MessageProps = {
33
+ icon?: React.ReactNode;
34
+ severity?: MessageSeverityProp;
35
+ showSidebarIcon?: boolean;
36
+ onSidebarIconClick?: () => void;
37
+ children: React.ReactNode;
38
+ };
39
+
40
+ export type UpgradeMessageProps = {
41
+ requestsRemaining: number;
42
+ onUpgradeClick: () => void;
43
+ };
44
+
45
+ export type ErrorMessageProps = {
46
+ error?: string;
47
+ onTryAgainClick: () => void;
48
+ };
49
+
50
+ const messageIconsMap = {
51
+ [ MESSAGE_SEVERITY_INFO ]: null,
52
+ [ MESSAGE_SEVERITY_WARNING ]: null,
53
+ [ MESSAGE_SEVERITY_ERROR ]: errorExclamation,
54
+ [ MESSAGE_SEVERITY_SUCCESS ]: check,
55
+ };
56
+
57
+ /**
58
+ * React component to render a block message.
59
+ *
60
+ * @param {MessageProps} props - Component props.
61
+ * @returns {React.ReactElement } Banner component.
62
+ */
63
+ export default function Message( {
64
+ severity = MESSAGE_SEVERITY_INFO,
65
+ icon = null,
66
+ showSidebarIcon = false,
67
+ onSidebarIconClick = () => {},
68
+ children,
69
+ }: MessageProps ): React.ReactElement {
70
+ return (
71
+ <div
72
+ className={ classNames(
73
+ 'jetpack-ai-assistant__message',
74
+ `jetpack-ai-assistant__message-severity-${ severity }`
75
+ ) }
76
+ >
77
+ { ( messageIconsMap[ severity ] || icon ) && (
78
+ <Icon icon={ messageIconsMap[ severity ] || icon } />
79
+ ) }
80
+ <div className="jetpack-ai-assistant__message-content">{ children }</div>
81
+ { showSidebarIcon && (
82
+ <Button className="jetpack-ai-assistant__message-sidebar" onClick={ onSidebarIconClick }>
83
+ <Icon size={ 20 } icon={ arrowRight } />
84
+ </Button>
85
+ ) }
86
+ </div>
87
+ );
88
+ }
89
+
90
+ /**
91
+ * React component to render a guideline message.
92
+ *
93
+ * @returns {React.ReactElement } - Message component.
94
+ */
95
+ export function GuidelineMessage(): React.ReactElement {
96
+ return (
97
+ <Message>
98
+ <span>
99
+ { __( 'AI-generated content could be inaccurate or biased.', 'jetpack-ai-client' ) }
100
+ </span>
101
+ <ExternalLink href="https://automattic.com/ai-guidelines">
102
+ { __( 'Learn more', 'jetpack-ai-client' ) }
103
+ </ExternalLink>
104
+ </Message>
105
+ );
106
+ }
107
+
108
+ /**
109
+ * React component to render an upgrade message for free tier users
110
+ *
111
+ * @param {number} requestsRemaining - Number of requests remaining.
112
+ * @returns {React.ReactElement } - Message component.
113
+ */
114
+ export function UpgradeMessage( {
115
+ requestsRemaining,
116
+ onUpgradeClick,
117
+ }: UpgradeMessageProps ): React.ReactElement {
118
+ return (
119
+ <Message severity={ MESSAGE_SEVERITY_WARNING }>
120
+ <span>
121
+ { sprintf(
122
+ // translators: %1$d: number of requests remaining
123
+ __( 'You have %1$d free requests remaining.', 'jetpack-ai-client' ),
124
+ requestsRemaining
125
+ ) }
126
+ </span>
127
+ <Button variant="link" onClick={ onUpgradeClick }>
128
+ { __( 'Upgrade now', 'jetpack-ai-client' ) }
129
+ </Button>
130
+ </Message>
131
+ );
132
+ }
133
+
134
+ /**
135
+ * React component to render an error message
136
+ *
137
+ * @param {number} requestsRemaining - Number of requests remaining.
138
+ * @returns {React.ReactElement } - Message component.
139
+ */
140
+ export function ErrorMessage( { error, onTryAgainClick }: ErrorMessageProps ): React.ReactElement {
141
+ const errorMessage = error || __( 'Something went wrong', 'jetpack-ai-client' );
142
+
143
+ return (
144
+ <Message severity={ MESSAGE_SEVERITY_ERROR }>
145
+ <span>
146
+ { sprintf(
147
+ // translators: %1$d: A dynamic error message
148
+ __( 'Error: %1$s.', 'jetpack-ai-client' ),
149
+ errorMessage
150
+ ) }
151
+ </span>
152
+ <Button variant="link" onClick={ onTryAgainClick }>
153
+ { __( 'Try Again', 'jetpack-ai-client' ) }
154
+ </Button>
155
+ </Message>
156
+ );
157
+ }
@@ -0,0 +1,83 @@
1
+ @import '@automattic/jetpack-base-styles/root-variables';
2
+
3
+ .jetpack-ai-assistant__message {
4
+ display: flex;
5
+ line-height: 28px;
6
+ font-size: 12px;
7
+ align-self: center;
8
+ align-items: center;
9
+ padding: 0 12px;
10
+ border-radius: 4px;
11
+ min-height: 28px;
12
+
13
+ > svg {
14
+ fill: var( --jp-gray-40 );
15
+ flex-shrink: 0;
16
+ }
17
+
18
+ .jetpack-ai-assistant__message-content {
19
+ flex-grow: 2;
20
+ margin: 0 8px;
21
+ line-height: 1.4em;
22
+ display: flex;
23
+ gap: 4px;
24
+ align-items: center;
25
+
26
+ span {
27
+ padding: 5px 0;
28
+ }
29
+
30
+ .components-external-link {
31
+ color: var( --jp-gray-50 );
32
+ }
33
+
34
+ // Force padding 0 in link buttons, since default Gutenberg version in WordPress doesn't use iframe and
35
+ // Buttons receive styles from edit-post-visual-editor.
36
+ .components-button.is-link {
37
+ padding: 0;
38
+ }
39
+
40
+ .components-button.is-link,
41
+ .components-external-link {
42
+ flex-shrink: 0;
43
+ }
44
+ }
45
+ }
46
+
47
+ .jetpack-ai-assistant__message-severity-info {
48
+ background-color: var( --jp-gray-0 );
49
+ color: var( --jp-gray-50 );
50
+ }
51
+
52
+ .jetpack-ai-assistant__message-severity-warning {
53
+ background-color: #FEF8EE;
54
+ color: var( --jp-gray-100 );
55
+ }
56
+
57
+ .jetpack-ai-assistant__message-severity-error {
58
+ background-color: var( --jp-red-0 );
59
+ color: var( --jp-gray-100 );
60
+
61
+ > svg {
62
+ fill: var( --jp-red-40, #E65054 );
63
+ }
64
+ }
65
+
66
+ .jetpack-ai-assistant__message-severity-success {
67
+ background-color: var( --jp-green-5 );
68
+ color: var( --jp-gray-100 );
69
+
70
+ > svg {
71
+ fill: var( --jp-green-30 );
72
+ }
73
+ }
74
+
75
+ .jetpack-ai-assistant__message-sidebar {
76
+ display: flex;
77
+ padding: 0;
78
+ height: unset;
79
+
80
+ > svg {
81
+ fill: var( --jp-gray-50 );
82
+ }
83
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { SVG, Path } from '@wordpress/components';
5
+
6
+ const errorExclamation = (
7
+ <SVG width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
8
+ <Path
9
+ fillRule="evenodd"
10
+ clipRule="evenodd"
11
+ d="M10 3.95833C6.66328 3.95833 3.95833 6.66327 3.95833 9.99999C3.95833 13.3367 6.66328 16.0417 10 16.0417C13.3367 16.0417 16.0417 13.3367 16.0417 9.99999C16.0417 6.66327 13.3367 3.95833 10 3.95833ZM2.70833 9.99999C2.70833 5.97292 5.97292 2.70833 10 2.70833C14.0271 2.70833 17.2917 5.97292 17.2917 9.99999C17.2917 14.0271 14.0271 17.2917 10 17.2917C5.97292 17.2917 2.70833 14.0271 2.70833 9.99999Z"
12
+ />
13
+ <Path d="M10.8333 5.83333H9.16667V10.8333H10.8333V5.83333Z" />
14
+ <Path d="M10.8333 12.5H9.16667V14.1667H10.8333V12.5Z" />
15
+ </SVG>
16
+ );
17
+
18
+ export default errorExclamation;
package/src/index.ts CHANGED
@@ -35,3 +35,8 @@ export * from './data-flow/index.js';
35
35
  * Types
36
36
  */
37
37
  export * from './types.js';
38
+
39
+ /*
40
+ * Libs
41
+ */
42
+ export * from './libs/index.js';
@@ -0,0 +1,6 @@
1
+ export {
2
+ MarkdownToHTML,
3
+ HTMLToMarkdown,
4
+ renderHTMLFromMarkdown,
5
+ renderMarkdownFromHTML,
6
+ } from './markdown/index.js';
@@ -0,0 +1,74 @@
1
+ # Markdown converters
2
+
3
+ Typescript functions and classes to convert Markdown to and from HTML.
4
+
5
+ ## HTML to Markdown
6
+
7
+ The HTML to Markdown conversion uses the [Turndown](https://github.com/mixmark-io/turndown) library and supports Turndown's options and rules.
8
+
9
+ Example:
10
+ ```typescript
11
+ /**
12
+ * External dependencies
13
+ */
14
+ import { renderMarkdownFromHTML } from '@automattic/jetpack-ai-client';
15
+
16
+ const htmlContent = '<strong>Hello world</strong>';
17
+ const markdownContent = renderMarkdownFromHTML( { content: htmlContent } );
18
+ // **Hello world**
19
+ ```
20
+
21
+ To use custom options and rules:
22
+ ```typescript
23
+ /**
24
+ * External dependencies
25
+ */
26
+ import { HTMLToMarkdown } from '@automattic/jetpack-ai-client';
27
+
28
+ const htmlContent = '<strong>Hello world</strong>';
29
+ const options = { headingStyle: 'setext' };
30
+ const rules = {
31
+ customStrong: {
32
+ filter: [ 'strong' ],
33
+ replacement: function( content: string ) {
34
+ return '***' + content + '***';
35
+ }
36
+ }
37
+ };
38
+ const renderer = new HTMLToMarkdown( options, rules );
39
+ const markdownContent = renderer.render( { content: htmlContent } );
40
+ // ***Hello world***
41
+ ```
42
+
43
+ ## Markdown to HTML
44
+
45
+ The Markdown to HTML conversion uses the [markdown-it](https://github.com/markdown-it/markdown-it) library and supports markdown-it's options. It also adds access to common fixes.
46
+
47
+ Example:
48
+ ```typescript
49
+ /**
50
+ * External dependencies
51
+ */
52
+ import { renderHTMLFromMarkdown } from '@automattic/jetpack-ai-client';
53
+
54
+ const markdownContent = '**Hello world**';
55
+ const htmlContent = renderHTMLFromMarkdown( { content: markdownContent, rules: 'all' } ); // 'all' is a default value
56
+ // <p><strong>Hello world</strong></p>\n
57
+ ```
58
+
59
+ To use custom options and fixes:
60
+ ```typescript
61
+ /**
62
+ * External dependencies
63
+ */
64
+ import { MarkdownToHTML } from '@automattic/jetpack-ai-client';
65
+
66
+ const markdownContent = '**Hello world**';
67
+ const options = { breaks: 'false' };
68
+ const rules = [ 'list' ];
69
+ const renderer = new MarkdownToHTML( options );
70
+ const htmlContent = renderer.render( { content: markdownContent, rules } );
71
+ // <p><strong>Hello world</strong></p>\n
72
+ ```
73
+
74
+ Currently `rules` only supports `'all'` and `['list']`. Further specific fixes can be added when necessary.
@@ -0,0 +1,42 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import TurndownService from 'turndown';
5
+ /**
6
+ * Types
7
+ */
8
+ import type { Options, Rule } from 'turndown';
9
+
10
+ const defaultTurndownOptions: Options = { emDelimiter: '_', headingStyle: 'atx' };
11
+ const defaultTurndownRules: { [ key: string ]: Rule } = {
12
+ strikethrough: {
13
+ filter: [ 'del', 's' ],
14
+ replacement: function ( content: string ) {
15
+ return '~~' + content + '~~';
16
+ },
17
+ },
18
+ };
19
+
20
+ export default class HTMLToMarkdown {
21
+ turndownService: TurndownService;
22
+
23
+ constructor(
24
+ options: Options = defaultTurndownOptions,
25
+ rules: { [ key: string ]: Rule } = defaultTurndownRules
26
+ ) {
27
+ this.turndownService = new TurndownService( options );
28
+ for ( const rule in rules ) {
29
+ this.turndownService.addRule( rule, rules[ rule ] );
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Renders HTML from Markdown content with specified processing rules.
35
+ * @param {object} options - The options to use when rendering the Markdown content
36
+ * @param {string} options.content - The HTML content to render
37
+ * @returns {string} The rendered Markdown content
38
+ */
39
+ render( { content }: { content: string } ): string {
40
+ return this.turndownService.turndown( content );
41
+ }
42
+ }
@@ -0,0 +1,28 @@
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
+
11
+ const defaultMarkdownConverter = new MarkdownToHTML();
12
+ const defaultHTMLConverter = new HTMLToMarkdown();
13
+
14
+ const renderHTMLFromMarkdown = ( {
15
+ content,
16
+ rules = 'all',
17
+ }: {
18
+ content: string;
19
+ rules?: Array< HTMLFix > | 'all';
20
+ } ) => {
21
+ return defaultMarkdownConverter.render( { content, rules } );
22
+ };
23
+
24
+ const renderMarkdownFromHTML = ( { content }: { content: string } ) => {
25
+ return defaultHTMLConverter.render( { content } );
26
+ };
27
+
28
+ export { MarkdownToHTML, HTMLToMarkdown, renderHTMLFromMarkdown, renderMarkdownFromHTML };
@@ -0,0 +1,48 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import MarkdownIt from 'markdown-it';
5
+ /**
6
+ * Types
7
+ */
8
+ import type { Options } from 'markdown-it';
9
+
10
+ export type Fix = 'list';
11
+ type Fixes = {
12
+ [ key in Fix ]: ( content: string ) => string;
13
+ };
14
+
15
+ const fixes: Fixes = {
16
+ list: ( content: string ) => {
17
+ // Fix list indentation
18
+ return content.replace( /<li>\s+<p>/g, '<li>' ).replace( /<\/p>\s+<\/li>/g, '</li>' );
19
+ },
20
+ };
21
+
22
+ const defaultMarkdownItOptions: Options = {
23
+ breaks: true,
24
+ };
25
+
26
+ export default class MarkdownToHTML {
27
+ markdownConverter: MarkdownIt;
28
+
29
+ constructor( options: Options = defaultMarkdownItOptions ) {
30
+ this.markdownConverter = new MarkdownIt( options );
31
+ }
32
+
33
+ /**
34
+ * Renders HTML from Markdown content with specified processing rules.
35
+ * @param {object} options - The options to use when rendering the HTML content
36
+ * @param {string} options.content - The Markdown content to render
37
+ * @param {string} options.rules - The rules to apply to the rendered content
38
+ * @returns {string} The rendered HTML content
39
+ */
40
+ render( { content, rules = 'all' }: { content: string; rules: Array< Fix > | 'all' } ): string {
41
+ const rendered = this.markdownConverter.render( content );
42
+ const rulesToApply = rules === 'all' ? Object.keys( fixes ) : rules;
43
+
44
+ return rulesToApply.reduce( ( renderedContent, rule ) => {
45
+ return fixes[ rule ]( renderedContent );
46
+ }, rendered );
47
+ }
48
+ }
package/src/types.ts CHANGED
@@ -93,6 +93,17 @@ export type { RecordingState } from './hooks/use-media-recording/index.js';
93
93
  */
94
94
  export type CancelablePromise< T = void > = Promise< T > & { canceled?: boolean };
95
95
 
96
+ export type Block = {
97
+ attributes?: {
98
+ [ key: string ]: unknown;
99
+ };
100
+ clientId?: string;
101
+ innerBlocks?: Block[];
102
+ isValid?: boolean;
103
+ name?: string;
104
+ originalContent?: string;
105
+ };
106
+
96
107
  /*
97
108
  * Transcription types
98
109
  */
@@ -1,57 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- /**
3
- * External dependencies
4
- */
5
- import { ExternalLink, Button } from '@wordpress/components';
6
- import { createInterpolateElement } from '@wordpress/element';
7
- import { __, sprintf } from '@wordpress/i18n';
8
- import { Icon, warning, info, cancelCircleFilled as error, check as success, } from '@wordpress/icons';
9
- import './style.scss';
10
- export const MESSAGE_SEVERITY_WARNING = 'warning';
11
- export const MESSAGE_SEVERITY_ERROR = 'error';
12
- export const MESSAGE_SEVERITY_SUCCESS = 'success';
13
- export const MESSAGE_SEVERITY_INFO = 'info';
14
- const messageSeverityTypes = [
15
- MESSAGE_SEVERITY_WARNING,
16
- MESSAGE_SEVERITY_ERROR,
17
- MESSAGE_SEVERITY_SUCCESS,
18
- MESSAGE_SEVERITY_INFO,
19
- ];
20
- const messageIconsMap = {
21
- [MESSAGE_SEVERITY_WARNING]: warning,
22
- [MESSAGE_SEVERITY_ERROR]: error,
23
- [MESSAGE_SEVERITY_SUCCESS]: success,
24
- [MESSAGE_SEVERITY_INFO]: info,
25
- };
26
- /**
27
- * React component to render a block message.
28
- *
29
- * @param {MessageProps} props - Component props.
30
- * @returns {React.ReactElement } Banner component.
31
- */
32
- export default function Message({ severity = null, icon = null, children, }) {
33
- return (_jsxs("div", { className: "jetpack-ai-assistant__message", children: [(severity || icon) && _jsx(Icon, { icon: messageIconsMap[severity] || icon }), _jsx("div", { className: "jetpack-ai-assistant__message-content", children: children })] }));
34
- }
35
- /**
36
- * React component to render a guideline message.
37
- *
38
- * @returns {React.ReactElement } - Message component.
39
- */
40
- export function GuidelineMessage() {
41
- return (_jsx(Message, { severity: MESSAGE_SEVERITY_INFO, children: createInterpolateElement(__('AI-generated content could be inaccurate or biased. <link>Learn more</link>', 'jetpack-ai-client'), {
42
- link: _jsx(ExternalLink, { href: "https://automattic.com/ai-guidelines" }),
43
- }) }));
44
- }
45
- /**
46
- * React component to render a upgrade message.
47
- *
48
- * @param {number} requestsRemaining - Number of requests remaining.
49
- * @returns {React.ReactElement } - Message component.
50
- */
51
- export function UpgradeMessage({ requestsRemaining, onUpgradeClick, }) {
52
- return (_jsx(Message, { severity: MESSAGE_SEVERITY_INFO, children: createInterpolateElement(sprintf(
53
- // translators: %1$d: number of requests remaining
54
- __('You have %1$d free requests remaining. <link>Upgrade</link> and avoid interruptions', 'jetpack-ai-client'), requestsRemaining), {
55
- link: _jsx(Button, { variant: "link", onClick: onUpgradeClick }),
56
- }) }));
57
- }
@@ -1,118 +0,0 @@
1
- /**
2
- * External dependencies
3
- */
4
- import { ExternalLink, Button } from '@wordpress/components';
5
- import { createInterpolateElement } from '@wordpress/element';
6
- import { __, sprintf } from '@wordpress/i18n';
7
- import {
8
- Icon,
9
- warning,
10
- info,
11
- cancelCircleFilled as error,
12
- check as success,
13
- } from '@wordpress/icons';
14
- /**
15
- * Types
16
- */
17
- import type React from 'react';
18
-
19
- import './style.scss';
20
-
21
- export const MESSAGE_SEVERITY_WARNING = 'warning';
22
- export const MESSAGE_SEVERITY_ERROR = 'error';
23
- export const MESSAGE_SEVERITY_SUCCESS = 'success';
24
- export const MESSAGE_SEVERITY_INFO = 'info';
25
-
26
- const messageSeverityTypes = [
27
- MESSAGE_SEVERITY_WARNING,
28
- MESSAGE_SEVERITY_ERROR,
29
- MESSAGE_SEVERITY_SUCCESS,
30
- MESSAGE_SEVERITY_INFO,
31
- ] as const;
32
-
33
- export type MessageSeverityProp = ( typeof messageSeverityTypes )[ number ] | null;
34
-
35
- export type MessageProps = {
36
- icon?: React.ReactNode;
37
- children: React.ReactNode;
38
- severity: MessageSeverityProp;
39
- };
40
-
41
- const messageIconsMap = {
42
- [ MESSAGE_SEVERITY_WARNING ]: warning,
43
- [ MESSAGE_SEVERITY_ERROR ]: error,
44
- [ MESSAGE_SEVERITY_SUCCESS ]: success,
45
- [ MESSAGE_SEVERITY_INFO ]: info,
46
- };
47
-
48
- /**
49
- * React component to render a block message.
50
- *
51
- * @param {MessageProps} props - Component props.
52
- * @returns {React.ReactElement } Banner component.
53
- */
54
- export default function Message( {
55
- severity = null,
56
- icon = null,
57
- children,
58
- }: MessageProps ): React.ReactElement {
59
- return (
60
- <div className="jetpack-ai-assistant__message">
61
- { ( severity || icon ) && <Icon icon={ messageIconsMap[ severity ] || icon } /> }
62
- <div className="jetpack-ai-assistant__message-content">{ children }</div>
63
- </div>
64
- );
65
- }
66
-
67
- /**
68
- * React component to render a guideline message.
69
- *
70
- * @returns {React.ReactElement } - Message component.
71
- */
72
- export function GuidelineMessage(): React.ReactElement {
73
- return (
74
- <Message severity={ MESSAGE_SEVERITY_INFO }>
75
- { createInterpolateElement(
76
- __(
77
- 'AI-generated content could be inaccurate or biased. <link>Learn more</link>',
78
- 'jetpack-ai-client'
79
- ),
80
- {
81
- link: <ExternalLink href="https://automattic.com/ai-guidelines" />,
82
- }
83
- ) }
84
- </Message>
85
- );
86
- }
87
-
88
- /**
89
- * React component to render a upgrade message.
90
- *
91
- * @param {number} requestsRemaining - Number of requests remaining.
92
- * @returns {React.ReactElement } - Message component.
93
- */
94
- export function UpgradeMessage( {
95
- requestsRemaining,
96
- onUpgradeClick,
97
- }: {
98
- requestsRemaining: number;
99
- onUpgradeClick: () => void;
100
- } ): React.ReactElement {
101
- return (
102
- <Message severity={ MESSAGE_SEVERITY_INFO }>
103
- { createInterpolateElement(
104
- sprintf(
105
- // translators: %1$d: number of requests remaining
106
- __(
107
- 'You have %1$d free requests remaining. <link>Upgrade</link> and avoid interruptions',
108
- 'jetpack-ai-client'
109
- ),
110
- requestsRemaining
111
- ),
112
- {
113
- link: <Button variant="link" onClick={ onUpgradeClick } />,
114
- }
115
- ) }
116
- </Message>
117
- );
118
- }