@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
package/CHANGELOG.md CHANGED
@@ -5,6 +5,14 @@ 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.12.3] - 2024-04-25
9
+ ### Changed
10
+ - AI Client: Separate AIControl UI from block logic. [#36967]
11
+
12
+ ## [0.12.2] - 2024-04-22
13
+ ### Added
14
+ - AI Client: Add Markdown and HTML conversions. [#36906]
15
+
8
16
  ## [0.12.1] - 2024-04-15
9
17
  ### Added
10
18
  - AI Client: Add callbacks, initial requesting state and change error handling. [#36869]
@@ -286,6 +294,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
286
294
  - Updated package dependencies. [#31659]
287
295
  - Updated package dependencies. [#31785]
288
296
 
297
+ [0.12.3]: https://github.com/Automattic/jetpack-ai-client/compare/v0.12.2...v0.12.3
298
+ [0.12.2]: https://github.com/Automattic/jetpack-ai-client/compare/v0.12.1...v0.12.2
289
299
  [0.12.1]: https://github.com/Automattic/jetpack-ai-client/compare/v0.12.0...v0.12.1
290
300
  [0.12.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.11.0...v0.12.0
291
301
  [0.11.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.10.1...v0.11.0
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import './style.scss';
3
+ /**
4
+ * Types
5
+ */
6
+ import type { RequestingStateProp } from '../../types.js';
7
+ import type { ReactElement } from 'react';
8
+ type AIControlProps = {
9
+ disabled?: boolean;
10
+ value: string;
11
+ placeholder?: string;
12
+ isTransparent?: boolean;
13
+ state?: RequestingStateProp;
14
+ onChange?: (newValue: string) => void;
15
+ banner?: ReactElement;
16
+ error?: ReactElement;
17
+ actions?: ReactElement;
18
+ message?: ReactElement;
19
+ promptUserInputRef?: React.MutableRefObject<HTMLInputElement>;
20
+ };
21
+ /**
22
+ * Base AIControl component. Contains the main structure of the control component and slots for banner, error, actions and message.
23
+ *
24
+ * @param {AIControlProps} props - Component props
25
+ * @returns {ReactElement} Rendered component
26
+ */
27
+ export default function AIControl({ disabled, value, placeholder, isTransparent, state, onChange, banner, error, actions, message, promptUserInputRef, }: AIControlProps): ReactElement;
28
+ export {};
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * External dependencies
4
+ */
5
+ import { PlainText } from '@wordpress/block-editor';
6
+ import classNames from 'classnames';
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import AiStatusIndicator from '../ai-status-indicator/index.js';
11
+ import './style.scss';
12
+ /**
13
+ * Base AIControl component. Contains the main structure of the control component and slots for banner, error, actions and message.
14
+ *
15
+ * @param {AIControlProps} props - Component props
16
+ * @returns {ReactElement} Rendered component
17
+ */
18
+ export default function AIControl({ disabled = false, value = '', placeholder = '', isTransparent = false, state = 'init', onChange, banner = null, error = null, actions = null, message = null, promptUserInputRef = null, }) {
19
+ return (_jsxs("div", { className: "jetpack-components-ai-control__container-wrapper", children: [error, _jsxs("div", { className: "jetpack-components-ai-control__container", children: [banner, _jsxs("div", { className: classNames('jetpack-components-ai-control__wrapper', {
20
+ 'is-transparent': isTransparent,
21
+ }), children: [_jsx(AiStatusIndicator, { state: state }), _jsx("div", { className: "jetpack-components-ai-control__input-wrapper", children: _jsx(PlainText, { value: value, onChange: onChange, placeholder: placeholder, className: "jetpack-components-ai-control__input", disabled: disabled, ref: promptUserInputRef }) }), actions] }), message] })] }));
22
+ }
@@ -0,0 +1,37 @@
1
+ import React from 'react';
2
+ import './style.scss';
3
+ /**
4
+ * Types
5
+ */
6
+ import type { RequestingStateProp } from '../../types.js';
7
+ import type { ReactElement } from 'react';
8
+ type BlockAIControlProps = {
9
+ disabled?: boolean;
10
+ value: string;
11
+ placeholder?: string;
12
+ showAccept?: boolean;
13
+ acceptLabel?: string;
14
+ showButtonLabels?: boolean;
15
+ isTransparent?: boolean;
16
+ state?: RequestingStateProp;
17
+ showGuideLine?: boolean;
18
+ customFooter?: ReactElement;
19
+ onChange?: (newValue: string) => void;
20
+ onSend?: (currentValue: string) => void;
21
+ onStop?: () => void;
22
+ onAccept?: () => void;
23
+ onDiscard?: () => void;
24
+ showRemove?: boolean;
25
+ banner?: ReactElement;
26
+ error?: ReactElement;
27
+ };
28
+ /**
29
+ * BlockAIControl component. Used by the AI Assistant block, adding logic and components to the base AIControl component.
30
+ *
31
+ * @param {BlockAIControlProps} props - Component props
32
+ * @param {React.MutableRefObject} ref - Ref to the component
33
+ * @returns {ReactElement} Rendered component
34
+ */
35
+ export declare function BlockAIControl({ disabled, value, placeholder, showAccept, acceptLabel, showButtonLabels, isTransparent, state, showGuideLine, customFooter, onChange, onSend, onStop, onAccept, onDiscard, showRemove, banner, error, }: BlockAIControlProps, ref: React.MutableRefObject<HTMLInputElement>): ReactElement;
36
+ declare const _default: React.ForwardRefExoticComponent<BlockAIControlProps & React.RefAttributes<HTMLInputElement>>;
37
+ export default _default;
@@ -0,0 +1,82 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * External dependencies
4
+ */
5
+ import { Button, ButtonGroup } from '@wordpress/components';
6
+ import { useKeyboardShortcut } from '@wordpress/compose';
7
+ import { useImperativeHandle, useRef, useEffect, useCallback, useState } from '@wordpress/element';
8
+ import { __ } from '@wordpress/i18n';
9
+ import { Icon, closeSmall, check, arrowUp, trash, reusableBlock as regenerate, } from '@wordpress/icons';
10
+ import debugFactory from 'debug';
11
+ import { forwardRef } from 'react';
12
+ /**
13
+ * Internal dependencies
14
+ */
15
+ import { GuidelineMessage } from '../message/index.js';
16
+ import AIControl from './ai-control.js';
17
+ import './style.scss';
18
+ const debug = debugFactory('jetpack-ai-client:block-ai-control');
19
+ /**
20
+ * BlockAIControl component. Used by the AI Assistant block, adding logic and components to the base AIControl component.
21
+ *
22
+ * @param {BlockAIControlProps} props - Component props
23
+ * @param {React.MutableRefObject} ref - Ref to the component
24
+ * @returns {ReactElement} Rendered component
25
+ */
26
+ export function BlockAIControl({ disabled = false, value = '', placeholder = '', showAccept = false, acceptLabel = __('Accept', 'jetpack-ai-client'), showButtonLabels = true, isTransparent = false, state = 'init', showGuideLine = false, customFooter = null, onChange, onSend, onStop, onAccept, onDiscard, showRemove = false, banner = null, error = null, }, ref) {
27
+ const loading = state === 'requesting' || state === 'suggesting';
28
+ const [editRequest, setEditRequest] = useState(false);
29
+ const [lastValue, setLastValue] = useState(value || null);
30
+ const promptUserInputRef = useRef(null);
31
+ // Pass the ref to forwardRef.
32
+ useImperativeHandle(ref, () => promptUserInputRef.current);
33
+ useEffect(() => {
34
+ if (editRequest) {
35
+ promptUserInputRef?.current?.focus();
36
+ }
37
+ }, [editRequest]);
38
+ const sendHandler = useCallback(() => {
39
+ setLastValue(value);
40
+ setEditRequest(false);
41
+ onSend?.(value);
42
+ }, [value]);
43
+ const changeHandler = useCallback((newValue) => {
44
+ onChange?.(newValue);
45
+ if (state === 'init') {
46
+ return;
47
+ }
48
+ if (!lastValue) {
49
+ // here we're coming from a one-click action
50
+ setEditRequest(newValue.length > 0);
51
+ }
52
+ else {
53
+ // here we're coming from an edit action
54
+ setEditRequest(newValue !== lastValue);
55
+ }
56
+ }, [lastValue, state]);
57
+ const discardHandler = useCallback(() => {
58
+ onDiscard?.();
59
+ }, []);
60
+ const cancelEdit = useCallback(() => {
61
+ debug('cancelEdit, revert to last value', lastValue);
62
+ onChange?.(lastValue || '');
63
+ setEditRequest(false);
64
+ }, [lastValue]);
65
+ useKeyboardShortcut('mod+enter', () => {
66
+ if (showAccept) {
67
+ onAccept?.();
68
+ }
69
+ }, {
70
+ target: promptUserInputRef,
71
+ });
72
+ useKeyboardShortcut('enter', e => {
73
+ e.preventDefault();
74
+ sendHandler();
75
+ }, {
76
+ target: promptUserInputRef,
77
+ });
78
+ const actions = (_jsxs(_Fragment, { children: [(!showAccept || editRequest) && (_jsx("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: !loading ? (_jsxs(_Fragment, { children: [editRequest && (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: cancelEdit, variant: "secondary", label: __('Cancel', 'jetpack-ai-client'), children: showButtonLabels ? (__('Cancel', 'jetpack-ai-client')) : (_jsx(Icon, { icon: closeSmall })) })), showRemove && !editRequest && !value?.length && onDiscard && (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: discardHandler, variant: "secondary", label: __('Cancel', 'jetpack-ai-client'), children: showButtonLabels ? (__('Cancel', 'jetpack-ai-client')) : (_jsx(Icon, { icon: closeSmall })) })), value?.length > 0 && (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: sendHandler, variant: "primary", disabled: !value?.length || disabled, label: __('Send request', 'jetpack-ai-client'), children: showButtonLabels ? (__('Generate', 'jetpack-ai-client')) : (_jsx(Icon, { icon: arrowUp })) }))] })) : (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: onStop, variant: "secondary", label: __('Stop request', 'jetpack-ai-client'), children: showButtonLabels ? (__('Stop', 'jetpack-ai-client')) : (_jsx(Icon, { icon: closeSmall })) })) })), showAccept && !editRequest && (_jsxs("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: [(value?.length > 0 || lastValue === null) && (_jsxs(ButtonGroup, { children: [_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Discard', 'jetpack-ai-client'), onClick: discardHandler, tooltipPosition: "top", children: _jsx(Icon, { icon: trash }) }), _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Regenerate', 'jetpack-ai-client'), onClick: () => onSend?.(value), tooltipPosition: "top", disabled: !value?.length || value === null || disabled, children: _jsx(Icon, { icon: regenerate }) })] })), _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: onAccept, variant: "primary", label: acceptLabel, children: showButtonLabels ? acceptLabel : _jsx(Icon, { icon: check }) })] }))] }));
79
+ const message = showGuideLine && !loading && !editRequest && (customFooter || _jsx(GuidelineMessage, {}));
80
+ return (_jsx(AIControl, { disabled: disabled || loading, value: value, placeholder: placeholder, isTransparent: isTransparent, state: state, onChange: changeHandler, banner: banner, error: error, actions: actions, message: message, promptUserInputRef: promptUserInputRef }));
81
+ }
82
+ export default forwardRef(BlockAIControl);
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import './style.scss';
3
+ /**
4
+ * Types
5
+ */
6
+ import type { RequestingStateProp } from '../../types.js';
7
+ import type { ReactElement } from 'react';
8
+ type ExtensionAIControlProps = {
9
+ disabled?: boolean;
10
+ value: string;
11
+ placeholder?: string;
12
+ showButtonLabels?: boolean;
13
+ isTransparent?: boolean;
14
+ state?: RequestingStateProp;
15
+ showGuideLine?: boolean;
16
+ error?: string;
17
+ requestsRemaining?: number;
18
+ showUpgradeMessage?: boolean;
19
+ onChange?: (newValue: string) => void;
20
+ onSend?: (currentValue: string) => void;
21
+ onStop?: () => void;
22
+ onClose?: () => void;
23
+ onUndo?: () => void;
24
+ onUpgrade?: () => void;
25
+ };
26
+ /**
27
+ * ExtensionAIControl component. Used by the AI Assistant inline extensions, adding logic and components to the base AIControl component.
28
+ *
29
+ * @param {ExtensionAIControlProps} props - Component props
30
+ * @param {React.MutableRefObject} ref - Ref to the component
31
+ * @returns {ReactElement} Rendered component
32
+ */
33
+ export declare function ExtensionAIControl({ disabled, value, placeholder, showButtonLabels, isTransparent, state, showGuideLine, error, requestsRemaining, showUpgradeMessage, onChange, onSend, onStop, onClose, onUndo, onUpgrade, }: ExtensionAIControlProps, ref: React.MutableRefObject<HTMLInputElement>): ReactElement;
34
+ declare const _default: React.ForwardRefExoticComponent<ExtensionAIControlProps & React.RefAttributes<HTMLInputElement>>;
35
+ export default _default;
@@ -0,0 +1,86 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /**
3
+ * External dependencies
4
+ */
5
+ import { Button, ButtonGroup } from '@wordpress/components';
6
+ import { useKeyboardShortcut } from '@wordpress/compose';
7
+ import { useImperativeHandle, useRef, useEffect, useCallback, useState } from '@wordpress/element';
8
+ import { __ } from '@wordpress/i18n';
9
+ import { Icon, closeSmall, arrowUp, undo } from '@wordpress/icons';
10
+ import { forwardRef } from 'react';
11
+ /**
12
+ * Internal dependencies
13
+ */
14
+ import { GuidelineMessage, ErrorMessage, UpgradeMessage } from '../message/index.js';
15
+ import AIControl from './ai-control.js';
16
+ import './style.scss';
17
+ /**
18
+ * ExtensionAIControl component. Used by the AI Assistant inline extensions, adding logic and components to the base AIControl component.
19
+ *
20
+ * @param {ExtensionAIControlProps} props - Component props
21
+ * @param {React.MutableRefObject} ref - Ref to the component
22
+ * @returns {ReactElement} Rendered component
23
+ */
24
+ export function ExtensionAIControl({ disabled = false, value = '', placeholder = '', showButtonLabels = true, isTransparent = false, state = 'init', showGuideLine = false, error, requestsRemaining, showUpgradeMessage = false, onChange, onSend, onStop, onClose, onUndo, onUpgrade, }, ref) {
25
+ const loading = state === 'requesting' || state === 'suggesting';
26
+ const [editRequest, setEditRequest] = useState(false);
27
+ const [lastValue, setLastValue] = useState(value || null);
28
+ const promptUserInputRef = useRef(null);
29
+ // Pass the ref to forwardRef.
30
+ useImperativeHandle(ref, () => promptUserInputRef.current);
31
+ useEffect(() => {
32
+ if (editRequest) {
33
+ promptUserInputRef?.current?.focus();
34
+ }
35
+ }, [editRequest]);
36
+ const sendHandler = useCallback(() => {
37
+ setLastValue(value);
38
+ setEditRequest(false);
39
+ onSend?.(value);
40
+ }, [onSend, value]);
41
+ const changeHandler = useCallback((newValue) => {
42
+ onChange?.(newValue);
43
+ if (state === 'init') {
44
+ return;
45
+ }
46
+ if (!lastValue) {
47
+ // here we're coming from a one-click action
48
+ setEditRequest(newValue.length > 0);
49
+ }
50
+ else {
51
+ // here we're coming from an edit action
52
+ setEditRequest(newValue !== lastValue);
53
+ }
54
+ }, [onChange, lastValue, state]);
55
+ const stopHandler = useCallback(() => {
56
+ onStop?.();
57
+ }, [onStop]);
58
+ const closeHandler = useCallback(() => {
59
+ onClose?.();
60
+ }, [onClose]);
61
+ const undoHandler = useCallback(() => {
62
+ onUndo?.();
63
+ }, [onUndo]);
64
+ const upgradeHandler = useCallback(() => {
65
+ onUpgrade?.();
66
+ }, [onUpgrade]);
67
+ useKeyboardShortcut('enter', e => {
68
+ e.preventDefault();
69
+ sendHandler();
70
+ }, {
71
+ target: promptUserInputRef,
72
+ });
73
+ const actions = (_jsx(_Fragment, { children: loading ? (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: stopHandler, variant: "secondary", label: __('Stop request', 'jetpack-ai-client'), children: showButtonLabels ? __('Stop', 'jetpack-ai-client') : _jsx(Icon, { icon: closeSmall }) })) : (_jsxs(_Fragment, { children: [value?.length > 0 && (_jsx("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: sendHandler, variant: "primary", disabled: !value?.length || disabled, label: __('Send request', 'jetpack-ai-client'), children: showButtonLabels ? (__('Generate', 'jetpack-ai-client')) : (_jsx(Icon, { icon: arrowUp })) }) })), value?.length <= 0 && state === 'done' && (_jsx("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: _jsxs(ButtonGroup, { children: [_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Undo', 'jetpack-ai-client'), onClick: undoHandler, tooltipPosition: "top", children: _jsx(Icon, { icon: undo }) }), _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Close', 'jetpack-ai-client'), onClick: closeHandler, variant: "tertiary", children: __('Close', 'jetpack-ai-client') })] }) }))] })) }));
74
+ let message = null;
75
+ if (error) {
76
+ message = _jsx(ErrorMessage, { error: error, onTryAgainClick: sendHandler });
77
+ }
78
+ else if (showUpgradeMessage) {
79
+ message = (_jsx(UpgradeMessage, { requestsRemaining: requestsRemaining, onUpgradeClick: upgradeHandler }));
80
+ }
81
+ else if (showGuideLine) {
82
+ message = _jsx(GuidelineMessage, {});
83
+ }
84
+ return (_jsx(AIControl, { disabled: disabled || loading, value: value, placeholder: placeholder, isTransparent: isTransparent, state: state, onChange: changeHandler, actions: actions, message: message, promptUserInputRef: promptUserInputRef }));
85
+ }
86
+ export default forwardRef(ExtensionAIControl);
@@ -1,40 +1,3 @@
1
- import React from 'react';
2
- /**
3
- * Internal dependencies
4
- */
5
- import './style.scss';
6
- /**
7
- * Types
8
- */
9
- import type { RequestingStateProp } from '../../types.js';
10
- import type { ReactElement } from 'react';
11
- type AiControlProps = {
12
- disabled?: boolean;
13
- value: string;
14
- placeholder?: string;
15
- showAccept?: boolean;
16
- acceptLabel?: string;
17
- showButtonLabels?: boolean;
18
- isTransparent?: boolean;
19
- state?: RequestingStateProp;
20
- showGuideLine?: boolean;
21
- customFooter?: ReactElement;
22
- onChange?: (newValue: string) => void;
23
- onSend?: (currentValue: string) => void;
24
- onStop?: () => void;
25
- onAccept?: () => void;
26
- onDiscard?: () => void;
27
- showRemove?: boolean;
28
- bannerComponent?: ReactElement;
29
- errorComponent?: ReactElement;
30
- };
31
- /**
32
- * AI Control component.
33
- *
34
- * @param {AiControlProps} props - Component props.
35
- * @param {React.MutableRefObject} ref - Ref to the component.
36
- * @returns {ReactElement} Rendered component.
37
- */
38
- export declare function AIControl({ disabled, value, placeholder, showAccept, acceptLabel, showButtonLabels, isTransparent, state, showGuideLine, customFooter, onChange, onSend, onStop, onAccept, onDiscard, showRemove, bannerComponent, errorComponent, }: AiControlProps, ref: React.MutableRefObject<HTMLInputElement>): ReactElement;
39
- declare const _default: React.ForwardRefExoticComponent<AiControlProps & React.RefAttributes<HTMLInputElement>>;
40
- export default _default;
1
+ export { default as AIControl } from './ai-control.js';
2
+ export { default as BlockAIControl } from './block-ai-control.js';
3
+ export { default as ExtensionAIControl } from './extension-ai-control.js';
@@ -1,86 +1,3 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- /**
3
- * External dependencies
4
- */
5
- import { PlainText } from '@wordpress/block-editor';
6
- import { Button, ButtonGroup } from '@wordpress/components';
7
- import { useKeyboardShortcut } from '@wordpress/compose';
8
- import { useImperativeHandle, useRef, useEffect, useCallback } from '@wordpress/element';
9
- import { __ } from '@wordpress/i18n';
10
- import { Icon, closeSmall, check, arrowUp, trash, reusableBlock } from '@wordpress/icons';
11
- import classNames from 'classnames';
12
- import debugFactory from 'debug';
13
- import React, { forwardRef } from 'react';
14
- /**
15
- * Internal dependencies
16
- */
17
- import './style.scss';
18
- import AiStatusIndicator from '../ai-status-indicator/index.js';
19
- import { GuidelineMessage } from './message.js';
20
- // eslint-disable-next-line @typescript-eslint/no-empty-function
21
- const noop = () => { };
22
- const debug = debugFactory('jetpack-ai-client:ai-control');
23
- /**
24
- * AI Control component.
25
- *
26
- * @param {AiControlProps} props - Component props.
27
- * @param {React.MutableRefObject} ref - Ref to the component.
28
- * @returns {ReactElement} Rendered component.
29
- */
30
- export function AIControl({ disabled = false, value = '', placeholder = '', showAccept = false, acceptLabel = __('Accept', 'jetpack-ai-client'), showButtonLabels = true, isTransparent = false, state = 'init', showGuideLine = false, customFooter = null, onChange = noop, onSend = noop, onStop = noop, onAccept = noop, onDiscard = null, showRemove = false, bannerComponent = null, errorComponent = null, }, ref) {
31
- const promptUserInputRef = useRef(null);
32
- const loading = state === 'requesting' || state === 'suggesting';
33
- const [editRequest, setEditRequest] = React.useState(false);
34
- const [lastValue, setLastValue] = React.useState(value || null);
35
- useEffect(() => {
36
- if (editRequest) {
37
- promptUserInputRef?.current?.focus();
38
- }
39
- }, [editRequest]);
40
- const sendRequest = useCallback(() => {
41
- setLastValue(value);
42
- setEditRequest(false);
43
- onSend?.(value);
44
- }, [value]);
45
- const changeHandler = useCallback((newValue) => {
46
- onChange?.(newValue);
47
- if (state === 'init') {
48
- return;
49
- }
50
- if (!lastValue) {
51
- // here we're coming from a one-click action
52
- setEditRequest(newValue.length > 0);
53
- }
54
- else {
55
- // here we're coming from an edit action
56
- setEditRequest(newValue !== lastValue);
57
- }
58
- }, [lastValue, state]);
59
- const discardHandler = useCallback(() => {
60
- onDiscard?.();
61
- }, []);
62
- const cancelEdit = useCallback(() => {
63
- debug('cancelEdit, revert to last value', lastValue);
64
- onChange(lastValue || '');
65
- setEditRequest(false);
66
- }, [lastValue]);
67
- // Pass the ref to forwardRef.
68
- useImperativeHandle(ref, () => promptUserInputRef.current);
69
- useKeyboardShortcut('mod+enter', () => {
70
- if (showAccept) {
71
- onAccept?.();
72
- }
73
- }, {
74
- target: promptUserInputRef,
75
- });
76
- useKeyboardShortcut('enter', e => {
77
- e.preventDefault();
78
- sendRequest();
79
- }, {
80
- target: promptUserInputRef,
81
- });
82
- return (_jsxs("div", { className: "jetpack-components-ai-control__container-wrapper", children: [errorComponent, _jsxs("div", { className: "jetpack-components-ai-control__container", children: [bannerComponent, _jsxs("div", { className: classNames('jetpack-components-ai-control__wrapper', {
83
- 'is-transparent': isTransparent,
84
- }), children: [_jsx(AiStatusIndicator, { state: state }), _jsx("div", { className: "jetpack-components-ai-control__input-wrapper", children: _jsx(PlainText, { value: value, onChange: changeHandler, placeholder: placeholder, className: "jetpack-components-ai-control__input", disabled: loading || disabled, ref: promptUserInputRef }) }), (!showAccept || editRequest) && (_jsx("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: !loading ? (_jsxs(_Fragment, { children: [editRequest && (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: cancelEdit, variant: "secondary", label: __('Cancel', 'jetpack-ai-client'), children: showButtonLabels ? (__('Cancel', 'jetpack-ai-client')) : (_jsx(Icon, { icon: closeSmall })) })), showRemove && !editRequest && !value?.length && onDiscard && (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: discardHandler, variant: "secondary", label: __('Cancel', 'jetpack-ai-client'), children: showButtonLabels ? (__('Cancel', 'jetpack-ai-client')) : (_jsx(Icon, { icon: closeSmall })) })), value?.length > 0 && (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: sendRequest, variant: "primary", disabled: !value?.length || disabled, label: __('Send request', 'jetpack-ai-client'), children: showButtonLabels ? (__('Generate', 'jetpack-ai-client')) : (_jsx(Icon, { icon: arrowUp })) }))] })) : (_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: onStop, variant: "secondary", label: __('Stop request', 'jetpack-ai-client'), children: showButtonLabels ? (__('Stop', 'jetpack-ai-client')) : (_jsx(Icon, { icon: closeSmall })) })) })), showAccept && !editRequest && (_jsxs("div", { className: "jetpack-components-ai-control__controls-prompt_button_wrapper", children: [(value?.length > 0 || lastValue === null) && (_jsxs(ButtonGroup, { children: [_jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Discard', 'jetpack-ai-client'), onClick: discardHandler, tooltipPosition: "top", children: _jsx(Icon, { icon: trash }) }), _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", label: __('Regenerate', 'jetpack-ai-client'), onClick: () => onSend?.(value), tooltipPosition: "top", disabled: !value?.length || value === null || disabled, children: _jsx(Icon, { icon: reusableBlock }) })] })), _jsx(Button, { className: "jetpack-components-ai-control__controls-prompt_button", onClick: onAccept, variant: "primary", label: acceptLabel, children: showButtonLabels ? acceptLabel : _jsx(Icon, { icon: check }) })] }))] }), showGuideLine && !loading && !editRequest && (customFooter || _jsx(GuidelineMessage, {}))] })] }));
85
- }
86
- export default forwardRef(AIControl);
1
+ export { default as AIControl } from './ai-control.js';
2
+ export { default as BlockAIControl } from './block-ai-control.js';
3
+ export { default as ExtensionAIControl } from './extension-ai-control.js';
@@ -1,4 +1,4 @@
1
- export { default as AIControl } from './ai-control/index.js';
1
+ export { AIControl, BlockAIControl } from './ai-control/index.js';
2
2
  export { default as AiStatusIndicator } from './ai-status-indicator/index.js';
3
3
  export { default as AudioDurationDisplay } from './audio-duration-display/index.js';
4
- export { GuidelineMessage, UpgradeMessage, default as FooterMessage, } from './ai-control/message.js';
4
+ export { GuidelineMessage, UpgradeMessage, ErrorMessage, default as FooterMessage, } from './message/index.js';
@@ -1,4 +1,4 @@
1
- export { default as AIControl } from './ai-control/index.js';
1
+ export { AIControl, BlockAIControl } from './ai-control/index.js';
2
2
  export { default as AiStatusIndicator } from './ai-status-indicator/index.js';
3
3
  export { default as AudioDurationDisplay } from './audio-duration-display/index.js';
4
- export { GuidelineMessage, UpgradeMessage, default as FooterMessage, } from './ai-control/message.js';
4
+ export { GuidelineMessage, UpgradeMessage, ErrorMessage, default as FooterMessage, } from './message/index.js';
@@ -1,8 +1,11 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import './style.scss';
1
5
  /**
2
6
  * Types
3
7
  */
4
8
  import type React from 'react';
5
- import './style.scss';
6
9
  export declare const MESSAGE_SEVERITY_WARNING = "warning";
7
10
  export declare const MESSAGE_SEVERITY_ERROR = "error";
8
11
  export declare const MESSAGE_SEVERITY_SUCCESS = "success";
@@ -11,8 +14,18 @@ declare const messageSeverityTypes: readonly ["warning", "error", "success", "in
11
14
  export type MessageSeverityProp = (typeof messageSeverityTypes)[number] | null;
12
15
  export type MessageProps = {
13
16
  icon?: React.ReactNode;
17
+ severity?: MessageSeverityProp;
18
+ showSidebarIcon?: boolean;
19
+ onSidebarIconClick?: () => void;
14
20
  children: React.ReactNode;
15
- severity: MessageSeverityProp;
21
+ };
22
+ export type UpgradeMessageProps = {
23
+ requestsRemaining: number;
24
+ onUpgradeClick: () => void;
25
+ };
26
+ export type ErrorMessageProps = {
27
+ error?: string;
28
+ onTryAgainClick: () => void;
16
29
  };
17
30
  /**
18
31
  * React component to render a block message.
@@ -20,7 +33,7 @@ export type MessageProps = {
20
33
  * @param {MessageProps} props - Component props.
21
34
  * @returns {React.ReactElement } Banner component.
22
35
  */
23
- export default function Message({ severity, icon, children, }: MessageProps): React.ReactElement;
36
+ export default function Message({ severity, icon, showSidebarIcon, onSidebarIconClick, children, }: MessageProps): React.ReactElement;
24
37
  /**
25
38
  * React component to render a guideline message.
26
39
  *
@@ -28,13 +41,17 @@ export default function Message({ severity, icon, children, }: MessageProps): Re
28
41
  */
29
42
  export declare function GuidelineMessage(): React.ReactElement;
30
43
  /**
31
- * React component to render a upgrade message.
44
+ * React component to render an upgrade message for free tier users
32
45
  *
33
46
  * @param {number} requestsRemaining - Number of requests remaining.
34
47
  * @returns {React.ReactElement } - Message component.
35
48
  */
36
- export declare function UpgradeMessage({ requestsRemaining, onUpgradeClick, }: {
37
- requestsRemaining: number;
38
- onUpgradeClick: () => void;
39
- }): React.ReactElement;
49
+ export declare function UpgradeMessage({ requestsRemaining, onUpgradeClick, }: UpgradeMessageProps): React.ReactElement;
50
+ /**
51
+ * React component to render an error message
52
+ *
53
+ * @param {number} requestsRemaining - Number of requests remaining.
54
+ * @returns {React.ReactElement } - Message component.
55
+ */
56
+ export declare function ErrorMessage({ error, onTryAgainClick }: ErrorMessageProps): React.ReactElement;
40
57
  export {};
@@ -0,0 +1,69 @@
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 { __, sprintf } from '@wordpress/i18n';
7
+ import { Icon, check, arrowRight } from '@wordpress/icons';
8
+ import classNames from 'classnames';
9
+ /**
10
+ * Internal dependencies
11
+ */
12
+ import './style.scss';
13
+ import errorExclamation from '../../icons/error-exclamation.js';
14
+ export const MESSAGE_SEVERITY_WARNING = 'warning';
15
+ export const MESSAGE_SEVERITY_ERROR = 'error';
16
+ export const MESSAGE_SEVERITY_SUCCESS = 'success';
17
+ export const MESSAGE_SEVERITY_INFO = 'info';
18
+ const messageSeverityTypes = [
19
+ MESSAGE_SEVERITY_WARNING,
20
+ MESSAGE_SEVERITY_ERROR,
21
+ MESSAGE_SEVERITY_SUCCESS,
22
+ MESSAGE_SEVERITY_INFO,
23
+ ];
24
+ const messageIconsMap = {
25
+ [MESSAGE_SEVERITY_INFO]: null,
26
+ [MESSAGE_SEVERITY_WARNING]: null,
27
+ [MESSAGE_SEVERITY_ERROR]: errorExclamation,
28
+ [MESSAGE_SEVERITY_SUCCESS]: check,
29
+ };
30
+ /**
31
+ * React component to render a block message.
32
+ *
33
+ * @param {MessageProps} props - Component props.
34
+ * @returns {React.ReactElement } Banner component.
35
+ */
36
+ export default function Message({ severity = MESSAGE_SEVERITY_INFO, icon = null, showSidebarIcon = false, onSidebarIconClick = () => { }, children, }) {
37
+ return (_jsxs("div", { className: classNames('jetpack-ai-assistant__message', `jetpack-ai-assistant__message-severity-${severity}`), children: [(messageIconsMap[severity] || icon) && (_jsx(Icon, { icon: messageIconsMap[severity] || icon })), _jsx("div", { className: "jetpack-ai-assistant__message-content", children: children }), showSidebarIcon && (_jsx(Button, { className: "jetpack-ai-assistant__message-sidebar", onClick: onSidebarIconClick, children: _jsx(Icon, { size: 20, icon: arrowRight }) }))] }));
38
+ }
39
+ /**
40
+ * React component to render a guideline message.
41
+ *
42
+ * @returns {React.ReactElement } - Message component.
43
+ */
44
+ export function GuidelineMessage() {
45
+ return (_jsxs(Message, { children: [_jsx("span", { children: __('AI-generated content could be inaccurate or biased.', 'jetpack-ai-client') }), _jsx(ExternalLink, { href: "https://automattic.com/ai-guidelines", children: __('Learn more', 'jetpack-ai-client') })] }));
46
+ }
47
+ /**
48
+ * React component to render an upgrade message for free tier users
49
+ *
50
+ * @param {number} requestsRemaining - Number of requests remaining.
51
+ * @returns {React.ReactElement } - Message component.
52
+ */
53
+ export function UpgradeMessage({ requestsRemaining, onUpgradeClick, }) {
54
+ return (_jsxs(Message, { severity: MESSAGE_SEVERITY_WARNING, children: [_jsx("span", { children: sprintf(
55
+ // translators: %1$d: number of requests remaining
56
+ __('You have %1$d free requests remaining.', 'jetpack-ai-client'), requestsRemaining) }), _jsx(Button, { variant: "link", onClick: onUpgradeClick, children: __('Upgrade now', 'jetpack-ai-client') })] }));
57
+ }
58
+ /**
59
+ * React component to render an error message
60
+ *
61
+ * @param {number} requestsRemaining - Number of requests remaining.
62
+ * @returns {React.ReactElement } - Message component.
63
+ */
64
+ export function ErrorMessage({ error, onTryAgainClick }) {
65
+ const errorMessage = error || __('Something went wrong', 'jetpack-ai-client');
66
+ return (_jsxs(Message, { severity: MESSAGE_SEVERITY_ERROR, children: [_jsx("span", { children: sprintf(
67
+ // translators: %1$d: A dynamic error message
68
+ __('Error: %1$s.', 'jetpack-ai-client'), errorMessage) }), _jsx(Button, { variant: "link", onClick: onTryAgainClick, children: __('Try Again', 'jetpack-ai-client') })] }));
69
+ }
@@ -0,0 +1,2 @@
1
+ declare const errorExclamation: import("react/jsx-runtime").JSX.Element;
2
+ export default errorExclamation;
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * External dependencies
4
+ */
5
+ import { SVG, Path } from '@wordpress/components';
6
+ const errorExclamation = (_jsxs(SVG, { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [_jsx(Path, { fillRule: "evenodd", clipRule: "evenodd", 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" }), _jsx(Path, { d: "M10.8333 5.83333H9.16667V10.8333H10.8333V5.83333Z" }), _jsx(Path, { d: "M10.8333 12.5H9.16667V14.1667H10.8333V12.5Z" })] }));
7
+ export default errorExclamation;
package/build/index.d.ts CHANGED
@@ -12,3 +12,4 @@ export * from './icons/index.js';
12
12
  export * from './components/index.js';
13
13
  export * from './data-flow/index.js';
14
14
  export * from './types.js';
15
+ export * from './libs/index.js';
package/build/index.js CHANGED
@@ -30,3 +30,7 @@ export * from './data-flow/index.js';
30
30
  * Types
31
31
  */
32
32
  export * from './types.js';
33
+ /*
34
+ * Libs
35
+ */
36
+ export * from './libs/index.js';
@@ -0,0 +1 @@
1
+ export { MarkdownToHTML, HTMLToMarkdown, renderHTMLFromMarkdown, renderMarkdownFromHTML, } from './markdown/index.js';
@@ -0,0 +1 @@
1
+ export { MarkdownToHTML, HTMLToMarkdown, renderHTMLFromMarkdown, renderMarkdownFromHTML, } from './markdown/index.js';