@automattic/jetpack-ai-client 0.24.3 → 0.25.1
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 +15 -0
- package/build/ai-client/src/components/ai-modal-footer/index.d.ts +20 -0
- package/build/ai-client/src/components/ai-modal-footer/index.js +27 -0
- package/build/ai-client/src/components/index.d.ts +1 -0
- package/build/ai-client/src/components/index.js +1 -0
- package/build/ai-client/src/components/message/index.d.ts +6 -8
- package/build/ai-client/src/components/message/index.js +14 -12
- package/build/ai-client/src/data-flow/context.d.ts +1 -2
- package/build/ai-client/src/hooks/use-ai-suggestions/index.d.ts +1 -2
- package/build/ai-client/src/logo-generator/components/generator-modal.js +2 -3
- package/build/ai-client/src/logo-generator/components/logo-presenter.js +0 -1
- package/build/ai-client/src/logo-generator/components/prompt.d.ts +2 -2
- package/build/ai-client/src/logo-generator/components/prompt.js +4 -5
- package/build/ai-client/src/logo-generator/lib/logo-storage.js +1 -1
- package/package.json +13 -13
- package/src/api-fetch/index.ts +1 -1
- package/src/ask-question/index.ts +1 -1
- package/src/components/ai-modal-footer/index.tsx +71 -0
- package/src/components/ai-modal-footer/style.scss +15 -0
- package/src/components/index.ts +1 -0
- package/src/components/message/index.tsx +25 -16
- package/src/data-flow/context.tsx +1 -2
- package/src/hooks/use-ai-suggestions/index.ts +1 -2
- package/src/logo-generator/components/generator-modal.scss +1 -24
- package/src/logo-generator/components/generator-modal.tsx +2 -12
- package/src/logo-generator/components/logo-presenter.scss +14 -0
- package/src/logo-generator/components/logo-presenter.tsx +0 -1
- package/src/logo-generator/components/prompt.scss +19 -1
- package/src/logo-generator/components/prompt.tsx +7 -9
- package/src/logo-generator/lib/logo-storage.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,19 @@ 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.25.1] - 2024-12-09
|
|
9
|
+
### Changed
|
|
10
|
+
- AI Assistant: Add disclaimer to image generation modals [#40397]
|
|
11
|
+
- Updated package dependencies. [#40363]
|
|
12
|
+
|
|
13
|
+
## [0.25.0] - 2024-11-25
|
|
14
|
+
### Added
|
|
15
|
+
- AI Client: split disabled prop to allow disabling input and action button separately [#40210]
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- AI Client: fix prompt cursor to text when editable [#40247]
|
|
19
|
+
- Updated package dependencies. [#40288]
|
|
20
|
+
|
|
8
21
|
## [0.24.3] - 2024-11-18
|
|
9
22
|
### Changed
|
|
10
23
|
- AI Client: add effect on AiModalInputPrompt to update/set prompt on prop update [#40113]
|
|
@@ -463,6 +476,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
463
476
|
- AI Client: stop using smart document visibility handling on the fetchEventSource library, so it does not restart the completion when changing tabs. [#32004]
|
|
464
477
|
- Updated package dependencies. [#31468] [#31659] [#31785]
|
|
465
478
|
|
|
479
|
+
[0.25.1]: https://github.com/Automattic/jetpack-ai-client/compare/v0.25.0...v0.25.1
|
|
480
|
+
[0.25.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.24.3...v0.25.0
|
|
466
481
|
[0.24.3]: https://github.com/Automattic/jetpack-ai-client/compare/v0.24.2...v0.24.3
|
|
467
482
|
[0.24.2]: https://github.com/Automattic/jetpack-ai-client/compare/v0.24.1...v0.24.2
|
|
468
483
|
[0.24.1]: https://github.com/Automattic/jetpack-ai-client/compare/v0.24.0...v0.24.1
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal dependencies
|
|
3
|
+
*/
|
|
4
|
+
import './style.scss';
|
|
5
|
+
/**
|
|
6
|
+
* Types
|
|
7
|
+
*/
|
|
8
|
+
import type React from 'react';
|
|
9
|
+
type AiModalFooterProps = {
|
|
10
|
+
onGuidelinesClick?: () => void;
|
|
11
|
+
onFeedbackClick?: () => void;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* AiModalFooter component.
|
|
15
|
+
*
|
|
16
|
+
* @param {AiModalFooterProps} props - component props.
|
|
17
|
+
* @return {React.ReactElement} - rendered component.
|
|
18
|
+
*/
|
|
19
|
+
export default function AiModalFooter({ onGuidelinesClick, onFeedbackClick, }: AiModalFooterProps): React.ReactElement;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* External dependencies
|
|
4
|
+
*/
|
|
5
|
+
import { Button } from '@wordpress/components';
|
|
6
|
+
import { useCallback } from '@wordpress/element';
|
|
7
|
+
import { __ } from '@wordpress/i18n';
|
|
8
|
+
import { Icon, info } from '@wordpress/icons';
|
|
9
|
+
/**
|
|
10
|
+
* Internal dependencies
|
|
11
|
+
*/
|
|
12
|
+
import './style.scss';
|
|
13
|
+
/**
|
|
14
|
+
* AiModalFooter component.
|
|
15
|
+
*
|
|
16
|
+
* @param {AiModalFooterProps} props - component props.
|
|
17
|
+
* @return {React.ReactElement} - rendered component.
|
|
18
|
+
*/
|
|
19
|
+
export default function AiModalFooter({ onGuidelinesClick, onFeedbackClick, }) {
|
|
20
|
+
const handleGuidelinesClick = useCallback(() => {
|
|
21
|
+
onGuidelinesClick?.();
|
|
22
|
+
}, [onGuidelinesClick]);
|
|
23
|
+
const handleFeedbackClick = useCallback(() => {
|
|
24
|
+
onFeedbackClick?.();
|
|
25
|
+
}, [onFeedbackClick]);
|
|
26
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "ai-image-modal__footer-disclaimer", children: [_jsx(Icon, { icon: info }), _jsx("span", { children: __('Generated images could be inaccurate, biased or include text.', 'jetpack-ai-client') }), _jsx(Button, { variant: "link", className: "ai-image-modal__guidelines-button", href: "https://jetpack.com/redirect/?source=ai-guidelines", target: "_blank", onClick: handleGuidelinesClick, children: _jsxs("span", { children: [__('Guidelines', 'jetpack-ai-client'), " \u2197"] }) })] }), _jsx(Button, { variant: "link", className: "ai-image-modal__feedback-button", href: "https://jetpack.com/redirect/?source=jetpack-ai-feedback", target: "_blank", onClick: handleFeedbackClick, children: _jsxs("span", { children: [__('Give feedback', 'jetpack-ai-client'), " \u2197"] }) })] }));
|
|
27
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { AIControl, BlockAIControl, ExtensionAIControl } 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 { default as AiModalFooter } from './ai-modal-footer/index.js';
|
|
4
5
|
export { GuidelineMessage, UpgradeMessage, ErrorMessage, default as FooterMessage, } from './message/index.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { AIControl, BlockAIControl, ExtensionAIControl } 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 { default as AiModalFooter } from './ai-modal-footer/index.js';
|
|
4
5
|
export { GuidelineMessage, UpgradeMessage, ErrorMessage, default as FooterMessage, } from './message/index.js';
|
|
@@ -11,8 +11,7 @@ export declare const MESSAGE_SEVERITY_WARNING = "warning";
|
|
|
11
11
|
export declare const MESSAGE_SEVERITY_ERROR = "error";
|
|
12
12
|
export declare const MESSAGE_SEVERITY_SUCCESS = "success";
|
|
13
13
|
export declare const MESSAGE_SEVERITY_INFO = "info";
|
|
14
|
-
|
|
15
|
-
export type MessageSeverityProp = (typeof messageSeverityTypes)[number] | null;
|
|
14
|
+
export type MessageSeverityProp = typeof MESSAGE_SEVERITY_WARNING | typeof MESSAGE_SEVERITY_ERROR | typeof MESSAGE_SEVERITY_SUCCESS | typeof MESSAGE_SEVERITY_INFO | null;
|
|
16
15
|
export type MessageProps = {
|
|
17
16
|
icon?: React.ReactNode;
|
|
18
17
|
severity?: MessageSeverityProp;
|
|
@@ -38,33 +37,32 @@ export type ErrorMessageProps = {
|
|
|
38
37
|
* React component to render a block message.
|
|
39
38
|
*
|
|
40
39
|
* @param {MessageProps} props - Component props.
|
|
41
|
-
* @return {React.ReactElement
|
|
40
|
+
* @return {React.ReactElement} Banner component.
|
|
42
41
|
*/
|
|
43
42
|
export default function Message({ severity, icon, showSidebarIcon, onSidebarIconClick, children, }: MessageProps): React.ReactElement;
|
|
44
43
|
/**
|
|
45
44
|
* React component to render a guideline message.
|
|
46
45
|
*
|
|
47
|
-
* @return {React.ReactElement
|
|
46
|
+
* @return {React.ReactElement} - Message component.
|
|
48
47
|
*/
|
|
49
48
|
export declare function GuidelineMessage(): React.ReactElement;
|
|
50
49
|
/**
|
|
51
50
|
* React component to render a fair usage limit message.
|
|
52
51
|
*
|
|
53
|
-
* @return {React.ReactElement
|
|
52
|
+
* @return {React.ReactElement} - Message component.
|
|
54
53
|
*/
|
|
55
54
|
export declare function FairUsageLimitMessage(): React.ReactElement;
|
|
56
55
|
/**
|
|
57
56
|
* React component to render an upgrade message for free tier users
|
|
58
57
|
*
|
|
59
58
|
* @param {number} requestsRemaining - Number of requests remaining.
|
|
60
|
-
* @return {React.ReactElement
|
|
59
|
+
* @return {React.ReactElement} - Message component.
|
|
61
60
|
*/
|
|
62
61
|
export declare function UpgradeMessage({ requestsRemaining, severity, onUpgradeClick, upgradeUrl, }: UpgradeMessageProps): React.ReactElement;
|
|
63
62
|
/**
|
|
64
63
|
* React component to render an error message
|
|
65
64
|
*
|
|
66
65
|
* @param {number} requestsRemaining - Number of requests remaining.
|
|
67
|
-
* @return {React.ReactElement
|
|
66
|
+
* @return {React.ReactElement} - Message component.
|
|
68
67
|
*/
|
|
69
68
|
export declare function ErrorMessage({ error, code, onTryAgainClick, onUpgradeClick, upgradeUrl, }: ErrorMessageProps): React.ReactElement;
|
|
70
|
-
export {};
|
|
@@ -17,12 +17,6 @@ export const MESSAGE_SEVERITY_WARNING = 'warning';
|
|
|
17
17
|
export const MESSAGE_SEVERITY_ERROR = 'error';
|
|
18
18
|
export const MESSAGE_SEVERITY_SUCCESS = 'success';
|
|
19
19
|
export const MESSAGE_SEVERITY_INFO = 'info';
|
|
20
|
-
const messageSeverityTypes = [
|
|
21
|
-
MESSAGE_SEVERITY_WARNING,
|
|
22
|
-
MESSAGE_SEVERITY_ERROR,
|
|
23
|
-
MESSAGE_SEVERITY_SUCCESS,
|
|
24
|
-
MESSAGE_SEVERITY_INFO,
|
|
25
|
-
];
|
|
26
20
|
const messageIconsMap = {
|
|
27
21
|
[MESSAGE_SEVERITY_INFO]: null,
|
|
28
22
|
[MESSAGE_SEVERITY_WARNING]: null,
|
|
@@ -33,23 +27,31 @@ const messageIconsMap = {
|
|
|
33
27
|
* React component to render a block message.
|
|
34
28
|
*
|
|
35
29
|
* @param {MessageProps} props - Component props.
|
|
36
|
-
* @return {React.ReactElement
|
|
30
|
+
* @return {React.ReactElement} Banner component.
|
|
37
31
|
*/
|
|
38
32
|
export default function Message({ severity = MESSAGE_SEVERITY_INFO, icon = null, showSidebarIcon = false, onSidebarIconClick = () => { }, children, }) {
|
|
39
33
|
return (_jsxs("div", { className: clsx('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 }) }))] }));
|
|
40
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* React component to render a learn more link.
|
|
37
|
+
*
|
|
38
|
+
* @return {React.ReactElement} - Learn more link component.
|
|
39
|
+
*/
|
|
40
|
+
function LearnMoreLink() {
|
|
41
|
+
return (_jsx(ExternalLink, { href: "https://jetpack.com/redirect/?source=ai-guidelines", children: __('Learn more', 'jetpack-ai-client') }));
|
|
42
|
+
}
|
|
41
43
|
/**
|
|
42
44
|
* React component to render a guideline message.
|
|
43
45
|
*
|
|
44
|
-
* @return {React.ReactElement
|
|
46
|
+
* @return {React.ReactElement} - Message component.
|
|
45
47
|
*/
|
|
46
48
|
export function GuidelineMessage() {
|
|
47
|
-
return (_jsxs(Message, { children: [_jsx("span", { children: __('AI-generated content could be inaccurate or biased.', 'jetpack-ai-client') }), _jsx(
|
|
49
|
+
return (_jsxs(Message, { children: [_jsx("span", { children: __('AI-generated content could be inaccurate or biased.', 'jetpack-ai-client') }), _jsx(LearnMoreLink, {})] }));
|
|
48
50
|
}
|
|
49
51
|
/**
|
|
50
52
|
* React component to render a fair usage limit message.
|
|
51
53
|
*
|
|
52
|
-
* @return {React.ReactElement
|
|
54
|
+
* @return {React.ReactElement} - Message component.
|
|
53
55
|
*/
|
|
54
56
|
export function FairUsageLimitMessage() {
|
|
55
57
|
const message = __("You've reached this month's request limit, per our <link>fair usage policy</link>", 'jetpack-ai-client');
|
|
@@ -62,7 +64,7 @@ export function FairUsageLimitMessage() {
|
|
|
62
64
|
* React component to render an upgrade message for free tier users
|
|
63
65
|
*
|
|
64
66
|
* @param {number} requestsRemaining - Number of requests remaining.
|
|
65
|
-
* @return {React.ReactElement
|
|
67
|
+
* @return {React.ReactElement} - Message component.
|
|
66
68
|
*/
|
|
67
69
|
export function UpgradeMessage({ requestsRemaining, severity, onUpgradeClick, upgradeUrl, }) {
|
|
68
70
|
let messageSeverity = severity;
|
|
@@ -77,7 +79,7 @@ export function UpgradeMessage({ requestsRemaining, severity, onUpgradeClick, up
|
|
|
77
79
|
* React component to render an error message
|
|
78
80
|
*
|
|
79
81
|
* @param {number} requestsRemaining - Number of requests remaining.
|
|
80
|
-
* @return {React.ReactElement
|
|
82
|
+
* @return {React.ReactElement} - Message component.
|
|
81
83
|
*/
|
|
82
84
|
export function ErrorMessage({ error, code, onTryAgainClick, onUpgradeClick, upgradeUrl, }) {
|
|
83
85
|
const errorMessage = error || __('Something went wrong', 'jetpack-ai-client');
|
|
@@ -8,8 +8,7 @@ import React from 'react';
|
|
|
8
8
|
import SuggestionsEventSource from '../suggestions-event-source/index.js';
|
|
9
9
|
import type { AskQuestionOptionsArgProps } from '../ask-question/index.js';
|
|
10
10
|
import type { RequestingErrorProps } from '../hooks/use-ai-suggestions/index.js';
|
|
11
|
-
import type { PromptProp } from '../types.js';
|
|
12
|
-
import type { RequestingStateProp } from '../types.js';
|
|
11
|
+
import type { PromptProp, RequestingStateProp } from '../types.js';
|
|
13
12
|
export type AiDataContextProps = {
|
|
14
13
|
suggestion: string;
|
|
15
14
|
requestingError: RequestingErrorProps;
|
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { AskQuestionOptionsArgProps } from '../../ask-question/index.js';
|
|
5
5
|
import type SuggestionsEventSource from '../../suggestions-event-source/index.js';
|
|
6
|
-
import type { PromptProp, SuggestionErrorCode } from '../../types.js';
|
|
7
|
-
import type { RequestingStateProp } from '../../types.js';
|
|
6
|
+
import type { PromptProp, SuggestionErrorCode, RequestingStateProp } from '../../types.js';
|
|
8
7
|
export type RequestingErrorProps = {
|
|
9
8
|
code: SuggestionErrorCode;
|
|
10
9
|
message: string;
|
|
@@ -6,20 +6,19 @@ import { useAnalytics } from '@automattic/jetpack-shared-extension-utils';
|
|
|
6
6
|
import { Modal, Button } from '@wordpress/components';
|
|
7
7
|
import { useDispatch, select } from '@wordpress/data';
|
|
8
8
|
import { __ } from '@wordpress/i18n';
|
|
9
|
-
import { external, Icon } from '@wordpress/icons';
|
|
10
9
|
import clsx from 'clsx';
|
|
11
10
|
import debugFactory from 'debug';
|
|
12
11
|
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
13
12
|
/**
|
|
14
13
|
* Internal dependencies
|
|
15
14
|
*/
|
|
15
|
+
import AiModalFooter from '../../components/ai-modal-footer/index.js';
|
|
16
16
|
import { DEFAULT_LOGO_COST, EVENT_MODAL_OPEN, EVENT_FEEDBACK, EVENT_MODAL_CLOSE, EVENT_GENERATE, } from '../constants.js';
|
|
17
17
|
import { useCheckout } from '../hooks/use-checkout.js';
|
|
18
18
|
import useLogoGenerator from '../hooks/use-logo-generator.js';
|
|
19
19
|
import useRequestErrors from '../hooks/use-request-errors.js';
|
|
20
20
|
import { isLogoHistoryEmpty, clearDeletedMedia } from '../lib/logo-storage.js';
|
|
21
21
|
import { STORE_NAME } from '../store/index.js';
|
|
22
|
-
// import { FairUsageNotice } from './fair-usage-notice.js';
|
|
23
22
|
import { FeatureFetchFailureScreen } from './feature-fetch-failure-screen.js';
|
|
24
23
|
import { FirstLoadScreen } from './first-load-screen.js';
|
|
25
24
|
import { HistoryCarousel } from './history-carousel.js';
|
|
@@ -213,7 +212,7 @@ export const GeneratorModal = ({ isOpen, onClose, onApplyLogo, onReload = null,
|
|
|
213
212
|
body = (_jsx(UpgradeScreen, { onCancel: closeModal, upgradeURL: upgradeURL, reason: needsFeature ? 'feature' : 'requests' }));
|
|
214
213
|
}
|
|
215
214
|
else {
|
|
216
|
-
body = (_jsxs(_Fragment, { children: [!logoAccepted && _jsx(Prompt, { initialPrompt: initialPrompt }), _jsx(LogoPresenter, { logo: selectedLogo, onApplyLogo: handleApplyLogo, logoAccepted: logoAccepted, siteId: String(siteId) }), logoAccepted ? (_jsxs("div", { className: "jetpack-ai-logo-generator__accept", children: [_jsx(VisitSiteBanner, {}), _jsx("div", { className: "jetpack-ai-logo-generator__accept-actions", children: _jsx(Button, { variant: "primary", onClick: closeModal, children: __('Close', 'jetpack-ai-client') }) })] })) : (_jsxs(_Fragment, { children: [_jsx(HistoryCarousel, {}), _jsx("div", { className: "jetpack-ai-logo-generator__footer", children:
|
|
215
|
+
body = (_jsxs(_Fragment, { children: [!logoAccepted && _jsx(Prompt, { initialPrompt: initialPrompt }), _jsx(LogoPresenter, { logo: selectedLogo, onApplyLogo: handleApplyLogo, logoAccepted: logoAccepted, siteId: String(siteId) }), logoAccepted ? (_jsxs("div", { className: "jetpack-ai-logo-generator__accept", children: [_jsx(VisitSiteBanner, {}), _jsx("div", { className: "jetpack-ai-logo-generator__accept-actions", children: _jsx(Button, { variant: "primary", onClick: closeModal, children: __('Close', 'jetpack-ai-client') }) })] })) : (_jsxs(_Fragment, { children: [_jsx(HistoryCarousel, {}), _jsx("div", { className: "jetpack-ai-logo-generator__footer", children: _jsx(AiModalFooter, { onFeedbackClick: handleFeedbackClick }) })] }))] }));
|
|
217
216
|
}
|
|
218
217
|
return (_jsx(_Fragment, { children: isOpen && (_jsx(Modal, { className: "jetpack-ai-logo-generator-modal", onRequestClose: closeModal, shouldCloseOnClickOutside: false, shouldCloseOnEsc: false, title: __('Jetpack AI Logo Generator', 'jetpack-ai-client'), children: _jsx("div", { className: clsx('jetpack-ai-logo-generator-modal__body', {
|
|
219
218
|
'notice-modal': needsFeature || needsMoreRequests || featureFetchError || firstLogoPromptFetchError,
|
|
@@ -87,7 +87,6 @@ const LogoUpdated = ({ logo }) => {
|
|
|
87
87
|
return (_jsxs(_Fragment, { children: [_jsx("img", { src: logo.url, alt: logo.description, className: "jetpack-ai-logo-generator-modal-presenter__logo" }), _jsxs("div", { className: "jetpack-ai-logo-generator-modal-presenter__success-wrapper", children: [_jsx(Icon, { icon: _jsx(CheckIcon, {}) }), _jsx("span", { children: __('Your new logo was set to the block!', 'jetpack-ai-client') })] })] }));
|
|
88
88
|
};
|
|
89
89
|
export const LogoPresenter = ({ logo = null, loading = false, onApplyLogo, logoAccepted = false, siteId, }) => {
|
|
90
|
-
// eslint-disable-next-line @wordpress/no-unused-vars-before-return -- @todo Start extending jetpack-js-tools/eslintrc/react in eslintrc, then we can remove this disable comment.
|
|
91
90
|
const { isRequestingImage } = useLogoGenerator();
|
|
92
91
|
const { saveToLibraryError, logoUpdateError } = useRequestErrors();
|
|
93
92
|
let logoContent;
|
|
@@ -3,14 +3,14 @@ import './prompt.scss';
|
|
|
3
3
|
type PromptProps = {
|
|
4
4
|
initialPrompt?: string;
|
|
5
5
|
};
|
|
6
|
-
export declare const AiModalPromptInput: ({ prompt, setPrompt, disabled, generateHandler, placeholder, buttonLabel,
|
|
6
|
+
export declare const AiModalPromptInput: ({ prompt, setPrompt, disabled, actionDisabled, generateHandler, placeholder, buttonLabel, }: {
|
|
7
7
|
prompt: string;
|
|
8
8
|
setPrompt: Dispatch<SetStateAction<string>>;
|
|
9
9
|
disabled: boolean;
|
|
10
|
+
actionDisabled: boolean;
|
|
10
11
|
generateHandler: () => void;
|
|
11
12
|
placeholder?: string;
|
|
12
13
|
buttonLabel?: string;
|
|
13
|
-
minPromptLength?: number;
|
|
14
14
|
}) => import("react/jsx-runtime").JSX.Element;
|
|
15
15
|
export declare const Prompt: ({ initialPrompt }: PromptProps) => import("react/jsx-runtime").JSX.Element;
|
|
16
16
|
export {};
|
|
@@ -21,9 +21,8 @@ import { FairUsageNotice } from './fair-usage-notice.js';
|
|
|
21
21
|
import { UpgradeNudge } from './upgrade-nudge.js';
|
|
22
22
|
import './prompt.scss';
|
|
23
23
|
const debug = debugFactory('jetpack-ai-calypso:prompt-box');
|
|
24
|
-
export const AiModalPromptInput = ({ prompt = '', setPrompt = () => { }, disabled = false, generateHandler = () => { }, placeholder = '', buttonLabel = '',
|
|
24
|
+
export const AiModalPromptInput = ({ prompt = '', setPrompt = () => { }, disabled = false, actionDisabled = false, generateHandler = () => { }, placeholder = '', buttonLabel = '', }) => {
|
|
25
25
|
const inputRef = useRef(null);
|
|
26
|
-
const hasPrompt = prompt?.length >= (minPromptLength === null ? MINIMUM_PROMPT_LENGTH : minPromptLength);
|
|
27
26
|
const onPromptInput = (event) => {
|
|
28
27
|
setPrompt(event.target.textContent || '');
|
|
29
28
|
};
|
|
@@ -61,9 +60,9 @@ export const AiModalPromptInput = ({ prompt = '', setPrompt = () => { }, disable
|
|
|
61
60
|
inputRef.current.innerHTML = '';
|
|
62
61
|
}
|
|
63
62
|
};
|
|
64
|
-
return (_jsxs("div", { className: "jetpack-ai-
|
|
63
|
+
return (_jsxs("div", { className: "jetpack-ai-image-generator__prompt-query", children: [_jsx("div", { role: "textbox", tabIndex: 0, ref: inputRef, contentEditable: !disabled,
|
|
65
64
|
// The content editable div is expected to be updated by the enhance prompt, so warnings are suppressed
|
|
66
|
-
suppressContentEditableWarning: true, className: "prompt-query__input", onInput: onPromptInput, onPaste: onPromptPaste, onKeyDown: onKeyDown, onKeyUp: onKeyUp, "data-placeholder": placeholder }), _jsx(Button, { variant: "primary", className: "jetpack-ai-
|
|
65
|
+
suppressContentEditableWarning: true, className: "prompt-query__input", onInput: onPromptInput, onPaste: onPromptPaste, onKeyDown: onKeyDown, onKeyUp: onKeyUp, "data-placeholder": placeholder }), _jsx(Button, { variant: "primary", className: "jetpack-ai-image-generator__prompt-submit", onClick: generateHandler, disabled: actionDisabled, children: buttonLabel || __('Generate', 'jetpack-ai-client') })] }));
|
|
67
66
|
};
|
|
68
67
|
export const Prompt = ({ initialPrompt = '' }) => {
|
|
69
68
|
const { tracks } = useAnalytics();
|
|
@@ -155,7 +154,7 @@ export const Prompt = ({ initialPrompt = '' }) => {
|
|
|
155
154
|
setStyle(imageStyle);
|
|
156
155
|
recordTracksEvent(EVENT_SWITCH_STYLE, { context, style: imageStyle });
|
|
157
156
|
}, [context, setStyle, recordTracksEvent]);
|
|
158
|
-
return (_jsxs("div", { className: "jetpack-ai-logo-generator__prompt", children: [_jsxs("div", { className: "jetpack-ai-logo-generator__prompt-header", children: [_jsx("div", { className: "jetpack-ai-logo-generator__prompt-label", children: __('Describe your site:', 'jetpack-ai-client') }), _jsx("div", { className: "jetpack-ai-logo-generator__prompt-actions", children: _jsxs(Button, { variant: "link", disabled: isBusy || requireUpgrade || !hasPrompt, onClick: onEnhance, children: [_jsx(AiIcon, {}), enhanceButtonLabel] }) }), showStyleSelector && (_jsx(SelectControl, { __nextHasNoMarginBottom: true, value: style, options: styles, onChange: updateStyle, disabled: isBusy || requireUpgrade }))] }), _jsx(AiModalPromptInput, { prompt: prompt, setPrompt: setPrompt, generateHandler: onGenerate, disabled: isBusy || requireUpgrade, placeholder: __('Describe your site or simply ask for a logo specifying some details about it', 'jetpack-ai-client') }), _jsxs("div", { className: "jetpack-ai-logo-generator__prompt-footer", children: [!isUnlimited && !requireUpgrade && (_jsxs("div", { className: "jetpack-ai-logo-generator__prompt-requests", children: [_jsx("div", { children: sprintf(
|
|
157
|
+
return (_jsxs("div", { className: "jetpack-ai-logo-generator__prompt", children: [_jsxs("div", { className: "jetpack-ai-logo-generator__prompt-header", children: [_jsx("div", { className: "jetpack-ai-logo-generator__prompt-label", children: __('Describe your site:', 'jetpack-ai-client') }), _jsx("div", { className: "jetpack-ai-logo-generator__prompt-actions", children: _jsxs(Button, { variant: "link", disabled: isBusy || requireUpgrade || !hasPrompt, onClick: onEnhance, children: [_jsx(AiIcon, {}), enhanceButtonLabel] }) }), showStyleSelector && (_jsx(SelectControl, { __nextHasNoMarginBottom: true, value: style, options: styles, onChange: updateStyle, disabled: isBusy || requireUpgrade }))] }), _jsx(AiModalPromptInput, { prompt: prompt, setPrompt: setPrompt, generateHandler: onGenerate, disabled: isBusy || requireUpgrade, actionDisabled: isBusy || requireUpgrade || !hasPrompt, placeholder: __('Describe your site or simply ask for a logo specifying some details about it', 'jetpack-ai-client') }), _jsxs("div", { className: "jetpack-ai-logo-generator__prompt-footer", children: [!isUnlimited && !requireUpgrade && (_jsxs("div", { className: "jetpack-ai-logo-generator__prompt-requests", children: [_jsx("div", { children: sprintf(
|
|
159
158
|
// translators: %u is the number of requests
|
|
160
159
|
__('%u requests remaining.', 'jetpack-ai-client'), requestsRemaining) }), hasNextTier && (_jsxs(_Fragment, { children: ["\u00A0", _jsx(Button, { variant: "link", href: checkoutUrl, target: "_blank", onClick: onUpgradeClick, children: __('Upgrade', 'jetpack-ai-client') })] })), "\u00A0", _jsx(Tooltip, { text: __('Logo generation costs 10 requests; prompt enhancement costs 1 request each', 'jetpack-ai-client'), placement: "bottom", children: _jsx(Icon, { className: "prompt-footer__icon", icon: info }) })] })), requireUpgrade && tierPlansEnabled && _jsx(UpgradeNudge, {}), requireUpgrade && !tierPlansEnabled && _jsx(FairUsageNotice, {}), enhancePromptFetchError && (_jsx("div", { className: "jetpack-ai-logo-generator__prompt-error", children: __('Error enhancing prompt. Please try again.', 'jetpack-ai-client') })), logoFetchError && (_jsx("div", { className: "jetpack-ai-logo-generator__prompt-error", children: __('Error generating logo. Please try again.', 'jetpack-ai-client') }))] })] }));
|
|
161
160
|
};
|
|
@@ -119,7 +119,7 @@ export async function clearDeletedMedia(siteId) {
|
|
|
119
119
|
.filter(({ exists }) => !exists)
|
|
120
120
|
.forEach(({ mediaId }) => removeLogo({ siteId, mediaId }));
|
|
121
121
|
}
|
|
122
|
-
catch
|
|
122
|
+
catch {
|
|
123
123
|
// Assume that the media exists if there was a network error and do nothing to avoid data loss.
|
|
124
124
|
}
|
|
125
125
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"private": false,
|
|
3
3
|
"name": "@automattic/jetpack-ai-client",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.25.1",
|
|
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": {
|
|
@@ -44,21 +44,21 @@
|
|
|
44
44
|
"main": "./build/index.js",
|
|
45
45
|
"types": "./build/index.d.ts",
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@automattic/jetpack-base-styles": "^0.6.
|
|
48
|
-
"@automattic/jetpack-connection": "^0.
|
|
49
|
-
"@automattic/jetpack-shared-extension-utils": "^0.
|
|
47
|
+
"@automattic/jetpack-base-styles": "^0.6.38",
|
|
48
|
+
"@automattic/jetpack-connection": "^0.36.1",
|
|
49
|
+
"@automattic/jetpack-shared-extension-utils": "^0.16.1",
|
|
50
50
|
"@microsoft/fetch-event-source": "2.0.1",
|
|
51
51
|
"@types/react": "18.3.12",
|
|
52
52
|
"@types/wordpress__block-editor": "11.5.15",
|
|
53
|
-
"@wordpress/api-fetch": "7.
|
|
54
|
-
"@wordpress/blob": "4.
|
|
55
|
-
"@wordpress/block-editor": "14.
|
|
56
|
-
"@wordpress/components": "28.
|
|
57
|
-
"@wordpress/compose": "7.
|
|
58
|
-
"@wordpress/data": "10.
|
|
59
|
-
"@wordpress/element": "6.
|
|
60
|
-
"@wordpress/i18n": "5.
|
|
61
|
-
"@wordpress/icons": "10.
|
|
53
|
+
"@wordpress/api-fetch": "7.13.0",
|
|
54
|
+
"@wordpress/blob": "4.13.0",
|
|
55
|
+
"@wordpress/block-editor": "14.8.0",
|
|
56
|
+
"@wordpress/components": "28.13.0",
|
|
57
|
+
"@wordpress/compose": "7.13.0",
|
|
58
|
+
"@wordpress/data": "10.13.0",
|
|
59
|
+
"@wordpress/element": "6.13.0",
|
|
60
|
+
"@wordpress/i18n": "5.13.0",
|
|
61
|
+
"@wordpress/icons": "10.13.0",
|
|
62
62
|
"clsx": "2.1.1",
|
|
63
63
|
"debug": "4.3.4",
|
|
64
64
|
"markdown-it": "14.0.0",
|
package/src/api-fetch/index.ts
CHANGED
|
@@ -8,7 +8,7 @@ import apiFetchMod from '@wordpress/api-fetch';
|
|
|
8
8
|
// See https://arethetypeswrong.github.io/?p=@wordpress/api-fetch@6.47.0
|
|
9
9
|
// This is a helper to simplify the usage of the api-fetch module on the ai-client package.
|
|
10
10
|
const apiFetch = 'default' in apiFetchMod ? apiFetchMod.default : apiFetchMod;
|
|
11
|
-
// eslint-disable-next-line @typescript-eslint/
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
12
12
|
type ApiFetchType = typeof apiFetch extends Function ? typeof apiFetch : typeof apiFetchMod;
|
|
13
13
|
|
|
14
14
|
export default apiFetch as ApiFetchType;
|
|
@@ -35,7 +35,7 @@ export type AskQuestionOptionsArgProps = {
|
|
|
35
35
|
functions?: Array< {
|
|
36
36
|
name?: string;
|
|
37
37
|
arguments?: string;
|
|
38
|
-
// eslint-disable-next-line @typescript-eslint/
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
39
39
|
implementation?: Function;
|
|
40
40
|
} >;
|
|
41
41
|
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { Button } from '@wordpress/components';
|
|
5
|
+
import { useCallback } from '@wordpress/element';
|
|
6
|
+
import { __ } from '@wordpress/i18n';
|
|
7
|
+
import { Icon, info } from '@wordpress/icons';
|
|
8
|
+
/**
|
|
9
|
+
* Internal dependencies
|
|
10
|
+
*/
|
|
11
|
+
import './style.scss';
|
|
12
|
+
/**
|
|
13
|
+
* Types
|
|
14
|
+
*/
|
|
15
|
+
import type React from 'react';
|
|
16
|
+
|
|
17
|
+
type AiModalFooterProps = {
|
|
18
|
+
onGuidelinesClick?: () => void;
|
|
19
|
+
onFeedbackClick?: () => void;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* AiModalFooter component.
|
|
24
|
+
*
|
|
25
|
+
* @param {AiModalFooterProps} props - component props.
|
|
26
|
+
* @return {React.ReactElement} - rendered component.
|
|
27
|
+
*/
|
|
28
|
+
export default function AiModalFooter( {
|
|
29
|
+
onGuidelinesClick,
|
|
30
|
+
onFeedbackClick,
|
|
31
|
+
}: AiModalFooterProps ): React.ReactElement {
|
|
32
|
+
const handleGuidelinesClick = useCallback( () => {
|
|
33
|
+
onGuidelinesClick?.();
|
|
34
|
+
}, [ onGuidelinesClick ] );
|
|
35
|
+
|
|
36
|
+
const handleFeedbackClick = useCallback( () => {
|
|
37
|
+
onFeedbackClick?.();
|
|
38
|
+
}, [ onFeedbackClick ] );
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<>
|
|
42
|
+
<div className="ai-image-modal__footer-disclaimer">
|
|
43
|
+
<Icon icon={ info } />
|
|
44
|
+
<span>
|
|
45
|
+
{ __(
|
|
46
|
+
'Generated images could be inaccurate, biased or include text.',
|
|
47
|
+
'jetpack-ai-client'
|
|
48
|
+
) }
|
|
49
|
+
</span>
|
|
50
|
+
<Button
|
|
51
|
+
variant="link"
|
|
52
|
+
className="ai-image-modal__guidelines-button"
|
|
53
|
+
href="https://jetpack.com/redirect/?source=ai-guidelines"
|
|
54
|
+
target="_blank"
|
|
55
|
+
onClick={ handleGuidelinesClick }
|
|
56
|
+
>
|
|
57
|
+
<span>{ __( 'Guidelines', 'jetpack-ai-client' ) } ↗</span>
|
|
58
|
+
</Button>
|
|
59
|
+
</div>
|
|
60
|
+
<Button
|
|
61
|
+
variant="link"
|
|
62
|
+
className="ai-image-modal__feedback-button"
|
|
63
|
+
href="https://jetpack.com/redirect/?source=jetpack-ai-feedback"
|
|
64
|
+
target="_blank"
|
|
65
|
+
onClick={ handleFeedbackClick }
|
|
66
|
+
>
|
|
67
|
+
<span>{ __( 'Give feedback', 'jetpack-ai-client' ) } ↗</span>
|
|
68
|
+
</Button>
|
|
69
|
+
</>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
.ai-image-modal__footer-disclaimer {
|
|
2
|
+
display: flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
gap: 4px;
|
|
5
|
+
color: var( --jp-gray-50 );
|
|
6
|
+
fill: var( --jp-gray-50 );
|
|
7
|
+
|
|
8
|
+
.components-button.is-link {
|
|
9
|
+
color: var( --jp-gray-50 );
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.ai-image-modal__feedback-button.components-button.is-link {
|
|
14
|
+
text-decoration: none;
|
|
15
|
+
}
|
package/src/components/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { AIControl, BlockAIControl, ExtensionAIControl } 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 { default as AiModalFooter } from './ai-modal-footer/index.js';
|
|
4
5
|
export {
|
|
5
6
|
GuidelineMessage,
|
|
6
7
|
UpgradeMessage,
|
|
@@ -23,14 +23,12 @@ export const MESSAGE_SEVERITY_ERROR = 'error';
|
|
|
23
23
|
export const MESSAGE_SEVERITY_SUCCESS = 'success';
|
|
24
24
|
export const MESSAGE_SEVERITY_INFO = 'info';
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
MESSAGE_SEVERITY_WARNING
|
|
28
|
-
MESSAGE_SEVERITY_ERROR
|
|
29
|
-
MESSAGE_SEVERITY_SUCCESS
|
|
30
|
-
MESSAGE_SEVERITY_INFO
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
export type MessageSeverityProp = ( typeof messageSeverityTypes )[ number ] | null;
|
|
26
|
+
export type MessageSeverityProp =
|
|
27
|
+
| typeof MESSAGE_SEVERITY_WARNING
|
|
28
|
+
| typeof MESSAGE_SEVERITY_ERROR
|
|
29
|
+
| typeof MESSAGE_SEVERITY_SUCCESS
|
|
30
|
+
| typeof MESSAGE_SEVERITY_INFO
|
|
31
|
+
| null;
|
|
34
32
|
|
|
35
33
|
export type MessageProps = {
|
|
36
34
|
icon?: React.ReactNode;
|
|
@@ -68,7 +66,7 @@ const messageIconsMap = {
|
|
|
68
66
|
* React component to render a block message.
|
|
69
67
|
*
|
|
70
68
|
* @param {MessageProps} props - Component props.
|
|
71
|
-
* @return {React.ReactElement
|
|
69
|
+
* @return {React.ReactElement} Banner component.
|
|
72
70
|
*/
|
|
73
71
|
export default function Message( {
|
|
74
72
|
severity = MESSAGE_SEVERITY_INFO,
|
|
@@ -97,10 +95,23 @@ export default function Message( {
|
|
|
97
95
|
);
|
|
98
96
|
}
|
|
99
97
|
|
|
98
|
+
/**
|
|
99
|
+
* React component to render a learn more link.
|
|
100
|
+
*
|
|
101
|
+
* @return {React.ReactElement} - Learn more link component.
|
|
102
|
+
*/
|
|
103
|
+
function LearnMoreLink(): React.ReactElement {
|
|
104
|
+
return (
|
|
105
|
+
<ExternalLink href="https://jetpack.com/redirect/?source=ai-guidelines">
|
|
106
|
+
{ __( 'Learn more', 'jetpack-ai-client' ) }
|
|
107
|
+
</ExternalLink>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
100
111
|
/**
|
|
101
112
|
* React component to render a guideline message.
|
|
102
113
|
*
|
|
103
|
-
* @return {React.ReactElement
|
|
114
|
+
* @return {React.ReactElement} - Message component.
|
|
104
115
|
*/
|
|
105
116
|
export function GuidelineMessage(): React.ReactElement {
|
|
106
117
|
return (
|
|
@@ -108,9 +119,7 @@ export function GuidelineMessage(): React.ReactElement {
|
|
|
108
119
|
<span>
|
|
109
120
|
{ __( 'AI-generated content could be inaccurate or biased.', 'jetpack-ai-client' ) }
|
|
110
121
|
</span>
|
|
111
|
-
<
|
|
112
|
-
{ __( 'Learn more', 'jetpack-ai-client' ) }
|
|
113
|
-
</ExternalLink>
|
|
122
|
+
<LearnMoreLink />
|
|
114
123
|
</Message>
|
|
115
124
|
);
|
|
116
125
|
}
|
|
@@ -118,7 +127,7 @@ export function GuidelineMessage(): React.ReactElement {
|
|
|
118
127
|
/**
|
|
119
128
|
* React component to render a fair usage limit message.
|
|
120
129
|
*
|
|
121
|
-
* @return {React.ReactElement
|
|
130
|
+
* @return {React.ReactElement} - Message component.
|
|
122
131
|
*/
|
|
123
132
|
export function FairUsageLimitMessage(): React.ReactElement {
|
|
124
133
|
const message = __(
|
|
@@ -138,7 +147,7 @@ export function FairUsageLimitMessage(): React.ReactElement {
|
|
|
138
147
|
* React component to render an upgrade message for free tier users
|
|
139
148
|
*
|
|
140
149
|
* @param {number} requestsRemaining - Number of requests remaining.
|
|
141
|
-
* @return {React.ReactElement
|
|
150
|
+
* @return {React.ReactElement} - Message component.
|
|
142
151
|
*/
|
|
143
152
|
export function UpgradeMessage( {
|
|
144
153
|
requestsRemaining,
|
|
@@ -177,7 +186,7 @@ export function UpgradeMessage( {
|
|
|
177
186
|
* React component to render an error message
|
|
178
187
|
*
|
|
179
188
|
* @param {number} requestsRemaining - Number of requests remaining.
|
|
180
|
-
* @return {React.ReactElement
|
|
189
|
+
* @return {React.ReactElement} - Message component.
|
|
181
190
|
*/
|
|
182
191
|
export function ErrorMessage( {
|
|
183
192
|
error,
|
|
@@ -8,8 +8,7 @@ import React, { createContext } from 'react';
|
|
|
8
8
|
import SuggestionsEventSource from '../suggestions-event-source/index.js';
|
|
9
9
|
import type { AskQuestionOptionsArgProps } from '../ask-question/index.js';
|
|
10
10
|
import type { RequestingErrorProps } from '../hooks/use-ai-suggestions/index.js';
|
|
11
|
-
import type { PromptProp } from '../types.js';
|
|
12
|
-
import type { RequestingStateProp } from '../types.js';
|
|
11
|
+
import type { PromptProp, RequestingStateProp } from '../types.js';
|
|
13
12
|
|
|
14
13
|
export type AiDataContextProps = {
|
|
15
14
|
/*
|
|
@@ -21,8 +21,7 @@ import {
|
|
|
21
21
|
*/
|
|
22
22
|
import type { AskQuestionOptionsArgProps } from '../../ask-question/index.js';
|
|
23
23
|
import type SuggestionsEventSource from '../../suggestions-event-source/index.js';
|
|
24
|
-
import type { PromptProp, SuggestionErrorCode } from '../../types.js';
|
|
25
|
-
import type { RequestingStateProp } from '../../types.js';
|
|
24
|
+
import type { PromptProp, SuggestionErrorCode, RequestingStateProp } from '../../types.js';
|
|
26
25
|
|
|
27
26
|
export type RequestingErrorProps = {
|
|
28
27
|
/*
|
|
@@ -18,19 +18,6 @@
|
|
|
18
18
|
height: 100%;
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
-
|
|
22
|
-
.components-button {
|
|
23
|
-
&:focus:not(:disabled):not(.is-primary) {
|
|
24
|
-
box-shadow: 0 0 0 2px var(--color-link, #3858e9);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
&.is-link {
|
|
28
|
-
text-decoration: none;
|
|
29
|
-
&:not(:disabled) {
|
|
30
|
-
color: var(--color-link, #3858e9);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
21
|
}
|
|
35
22
|
|
|
36
23
|
.jetpack-ai-logo-generator-modal__body {
|
|
@@ -52,17 +39,7 @@
|
|
|
52
39
|
|
|
53
40
|
.jetpack-ai-logo-generator__footer {
|
|
54
41
|
display: flex;
|
|
55
|
-
|
|
56
|
-
.jetpack-ai-logo-generator__feedback-button {
|
|
57
|
-
display: flex;
|
|
58
|
-
gap: 4px;
|
|
59
|
-
align-items: center;
|
|
60
|
-
margin-top: 8px;
|
|
61
|
-
|
|
62
|
-
.icon {
|
|
63
|
-
color: var(--studio-gray-20);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
42
|
+
justify-content: space-between;
|
|
66
43
|
}
|
|
67
44
|
|
|
68
45
|
.jetpack-ai-logo-generator-modal__notice-message-wrapper {
|
|
@@ -5,13 +5,13 @@ import { useAnalytics } from '@automattic/jetpack-shared-extension-utils';
|
|
|
5
5
|
import { Modal, Button } from '@wordpress/components';
|
|
6
6
|
import { useDispatch, select } from '@wordpress/data';
|
|
7
7
|
import { __ } from '@wordpress/i18n';
|
|
8
|
-
import { external, Icon } from '@wordpress/icons';
|
|
9
8
|
import clsx from 'clsx';
|
|
10
9
|
import debugFactory from 'debug';
|
|
11
10
|
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
12
11
|
/**
|
|
13
12
|
* Internal dependencies
|
|
14
13
|
*/
|
|
14
|
+
import AiModalFooter from '../../components/ai-modal-footer/index.js';
|
|
15
15
|
import {
|
|
16
16
|
DEFAULT_LOGO_COST,
|
|
17
17
|
EVENT_MODAL_OPEN,
|
|
@@ -24,7 +24,6 @@ import useLogoGenerator from '../hooks/use-logo-generator.js';
|
|
|
24
24
|
import useRequestErrors from '../hooks/use-request-errors.js';
|
|
25
25
|
import { isLogoHistoryEmpty, clearDeletedMedia } from '../lib/logo-storage.js';
|
|
26
26
|
import { STORE_NAME } from '../store/index.js';
|
|
27
|
-
// import { FairUsageNotice } from './fair-usage-notice.js';
|
|
28
27
|
import { FeatureFetchFailureScreen } from './feature-fetch-failure-screen.js';
|
|
29
28
|
import { FirstLoadScreen } from './first-load-screen.js';
|
|
30
29
|
import { HistoryCarousel } from './history-carousel.js';
|
|
@@ -303,16 +302,7 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
|
|
|
303
302
|
<>
|
|
304
303
|
<HistoryCarousel />
|
|
305
304
|
<div className="jetpack-ai-logo-generator__footer">
|
|
306
|
-
<
|
|
307
|
-
variant="link"
|
|
308
|
-
className="jetpack-ai-logo-generator__feedback-button"
|
|
309
|
-
href="https://jetpack.com/redirect/?source=jetpack-ai-feedback"
|
|
310
|
-
target="_blank"
|
|
311
|
-
onClick={ handleFeedbackClick }
|
|
312
|
-
>
|
|
313
|
-
<span>{ __( 'Provide feedback', 'jetpack-ai-client' ) }</span>
|
|
314
|
-
<Icon icon={ external } className="icon" />
|
|
315
|
-
</Button>
|
|
305
|
+
<AiModalFooter onFeedbackClick={ handleFeedbackClick } />
|
|
316
306
|
</div>
|
|
317
307
|
</>
|
|
318
308
|
) }
|
|
@@ -4,6 +4,20 @@
|
|
|
4
4
|
display: flex;
|
|
5
5
|
flex-direction: column;
|
|
6
6
|
gap: 8px;
|
|
7
|
+
|
|
8
|
+
.components-button {
|
|
9
|
+
&:focus:not(:disabled):not(.is-primary) {
|
|
10
|
+
box-shadow: 0 0 0 2px var(--color-link, #3858e9);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
&.is-link {
|
|
14
|
+
text-decoration: none;
|
|
15
|
+
|
|
16
|
+
&:not(:disabled) {
|
|
17
|
+
color: var(--color-link, #3858e9);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
7
21
|
}
|
|
8
22
|
|
|
9
23
|
.jetpack-ai-logo-generator-modal-presenter {
|
|
@@ -200,7 +200,6 @@ export const LogoPresenter: React.FC< LogoPresenterProps > = ( {
|
|
|
200
200
|
logoAccepted = false,
|
|
201
201
|
siteId,
|
|
202
202
|
} ) => {
|
|
203
|
-
// eslint-disable-next-line @wordpress/no-unused-vars-before-return -- @todo Start extending jetpack-js-tools/eslintrc/react in eslintrc, then we can remove this disable comment.
|
|
204
203
|
const { isRequestingImage } = useLogoGenerator();
|
|
205
204
|
const { saveToLibraryError, logoUpdateError } = useRequestErrors();
|
|
206
205
|
|
|
@@ -5,6 +5,20 @@
|
|
|
5
5
|
flex-direction: column;
|
|
6
6
|
gap: 8px;
|
|
7
7
|
font-size: var(--font-body-small);
|
|
8
|
+
|
|
9
|
+
.components-button {
|
|
10
|
+
&:focus:not(:disabled):not(.is-primary) {
|
|
11
|
+
box-shadow: 0 0 0 2px var(--color-link, #3858e9);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
&.is-link {
|
|
15
|
+
text-decoration: none;
|
|
16
|
+
|
|
17
|
+
&:not(:disabled) {
|
|
18
|
+
color: var(--color-link, #3858e9);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
8
22
|
}
|
|
9
23
|
|
|
10
24
|
.jetpack-ai-logo-generator__prompt-header {
|
|
@@ -30,7 +44,7 @@
|
|
|
30
44
|
}
|
|
31
45
|
}
|
|
32
46
|
|
|
33
|
-
.jetpack-ai-
|
|
47
|
+
.jetpack-ai-image-generator__prompt-query {
|
|
34
48
|
display: flex;
|
|
35
49
|
padding: 8px 8px 8px var(--grid-unit-15, 16px);
|
|
36
50
|
justify-content: space-between;
|
|
@@ -64,6 +78,10 @@
|
|
|
64
78
|
color: var(--studio-gray-50, #646970);
|
|
65
79
|
}
|
|
66
80
|
|
|
81
|
+
&:not([contentEditable="false"]) {
|
|
82
|
+
cursor: text;
|
|
83
|
+
}
|
|
84
|
+
|
|
67
85
|
&[data-placeholder]:empty::before {
|
|
68
86
|
content: attr(data-placeholder);
|
|
69
87
|
color: var(--studio-gray-50, #646970);
|
|
@@ -6,8 +6,7 @@ import { Button, Tooltip, SelectControl } from '@wordpress/components';
|
|
|
6
6
|
import { __, sprintf } from '@wordpress/i18n';
|
|
7
7
|
import { Icon, info } from '@wordpress/icons';
|
|
8
8
|
import debugFactory from 'debug';
|
|
9
|
-
import { useCallback, useEffect, useState, useRef } from 'react';
|
|
10
|
-
import { Dispatch, SetStateAction } from 'react';
|
|
9
|
+
import { useCallback, useEffect, useState, useRef, Dispatch, SetStateAction } from 'react';
|
|
11
10
|
/**
|
|
12
11
|
* Internal dependencies
|
|
13
12
|
*/
|
|
@@ -42,22 +41,20 @@ export const AiModalPromptInput = ( {
|
|
|
42
41
|
prompt = '',
|
|
43
42
|
setPrompt = () => {},
|
|
44
43
|
disabled = false,
|
|
44
|
+
actionDisabled = false,
|
|
45
45
|
generateHandler = () => {},
|
|
46
46
|
placeholder = '',
|
|
47
47
|
buttonLabel = '',
|
|
48
|
-
minPromptLength = null,
|
|
49
48
|
}: {
|
|
50
49
|
prompt: string;
|
|
51
50
|
setPrompt: Dispatch< SetStateAction< string > >;
|
|
52
51
|
disabled: boolean;
|
|
52
|
+
actionDisabled: boolean;
|
|
53
53
|
generateHandler: () => void;
|
|
54
54
|
placeholder?: string;
|
|
55
55
|
buttonLabel?: string;
|
|
56
|
-
minPromptLength?: number;
|
|
57
56
|
} ) => {
|
|
58
57
|
const inputRef = useRef< HTMLDivElement | null >( null );
|
|
59
|
-
const hasPrompt =
|
|
60
|
-
prompt?.length >= ( minPromptLength === null ? MINIMUM_PROMPT_LENGTH : minPromptLength );
|
|
61
58
|
|
|
62
59
|
const onPromptInput = ( event: React.ChangeEvent< HTMLInputElement > ) => {
|
|
63
60
|
setPrompt( event.target.textContent || '' );
|
|
@@ -106,7 +103,7 @@ export const AiModalPromptInput = ( {
|
|
|
106
103
|
};
|
|
107
104
|
|
|
108
105
|
return (
|
|
109
|
-
<div className="jetpack-ai-
|
|
106
|
+
<div className="jetpack-ai-image-generator__prompt-query">
|
|
110
107
|
<div
|
|
111
108
|
role="textbox"
|
|
112
109
|
tabIndex={ 0 }
|
|
@@ -123,9 +120,9 @@ export const AiModalPromptInput = ( {
|
|
|
123
120
|
></div>
|
|
124
121
|
<Button
|
|
125
122
|
variant="primary"
|
|
126
|
-
className="jetpack-ai-
|
|
123
|
+
className="jetpack-ai-image-generator__prompt-submit"
|
|
127
124
|
onClick={ generateHandler }
|
|
128
|
-
disabled={
|
|
125
|
+
disabled={ actionDisabled }
|
|
129
126
|
>
|
|
130
127
|
{ buttonLabel || __( 'Generate', 'jetpack-ai-client' ) }
|
|
131
128
|
</Button>
|
|
@@ -283,6 +280,7 @@ export const Prompt = ( { initialPrompt = '' }: PromptProps ) => {
|
|
|
283
280
|
setPrompt={ setPrompt }
|
|
284
281
|
generateHandler={ onGenerate }
|
|
285
282
|
disabled={ isBusy || requireUpgrade }
|
|
283
|
+
actionDisabled={ isBusy || requireUpgrade || ! hasPrompt }
|
|
286
284
|
placeholder={ __(
|
|
287
285
|
'Describe your site or simply ask for a logo specifying some details about it',
|
|
288
286
|
'jetpack-ai-client'
|
|
@@ -162,7 +162,7 @@ export async function clearDeletedMedia( siteId: string ) {
|
|
|
162
162
|
responses
|
|
163
163
|
.filter( ( { exists } ) => ! exists )
|
|
164
164
|
.forEach( ( { mediaId } ) => removeLogo( { siteId, mediaId } ) );
|
|
165
|
-
} catch
|
|
165
|
+
} catch {
|
|
166
166
|
// Assume that the media exists if there was a network error and do nothing to avoid data loss.
|
|
167
167
|
}
|
|
168
168
|
}
|