diff --git a/src/components/image-editor/ImageCanvasBasicGenerationComposerView.tsx b/src/components/image-editor/ImageCanvasBasicGenerationComposerView.tsx
index 2036eeb09..925907f9e 100644
--- a/src/components/image-editor/ImageCanvasBasicGenerationComposerView.tsx
+++ b/src/components/image-editor/ImageCanvasBasicGenerationComposerView.tsx
@@ -16,14 +16,27 @@ import { PlatformTextField } from '../common/PlatformTextField';
import type {
CharacterReferenceImage,
GenerateDialogState,
+ UploadTarget,
} from './ImageCanvasEditorTypes';
import { ImageCanvasGenerationImageOptionsView } from './ImageCanvasGenerationImageOptionsView';
import { ImageCanvasReferenceSlot } from './ImageCanvasReferenceSlot';
-import {
- calculateEditorImageGenerationPrice,
-} from './ImageCanvasGenerationModel';
+import { calculateEditorImageGenerationPrice } from './ImageCanvasGenerationModel';
import { useImageCanvasFloatingOptionDismiss } from './useImageCanvasFloatingOptionDismiss';
+type ReferenceLabelFormatter = (
+ reference: CharacterReferenceImage,
+ index: number,
+) => string;
+
+type ReferenceTone =
+ | 'default'
+ | 'spec'
+ | 'icon'
+ | 'ui'
+ | 'quick-edit'
+ | 'video'
+ | 'audio';
+
type ImageCanvasBasicGenerationComposerViewProps = {
dialog: GenerateDialogState;
style: CSSProperties;
@@ -37,11 +50,41 @@ type ImageCanvasBasicGenerationComposerViewProps = {
anchor: HTMLElement | null,
placement: 'above' | 'below',
) => CSSProperties;
- onRequestUpload: (target: 'generation-reference') => void;
+ onRequestUpload: (target: UploadTarget) => void;
+ onPickReferenceFromCanvas?: () => void;
onToggleReferenceMenu?: () => void;
onRememberImageModel?: (model: string) => void;
onSubmit: (dialog: GenerateDialogState) => void;
+ dialogLabel?: string;
+ includeDimensions?: boolean;
+ includeModel?: boolean;
+ includeReferences?: boolean;
+ promptLabel?: string;
+ promptPlaceholder?: string;
+ optionLabelPrefix?: string;
+ dimensionRatioAriaLabelPrefix?: string;
+ dimensionSizeAriaLabelPrefix?: string;
+ referenceUploadTarget?: UploadTarget;
+ referenceButtonIcon?: ReactNode;
+ referenceButtonLabel?: string;
+ referenceButtonAriaLabel?: string;
+ referenceMenuLabel?: string;
+ referenceSlotTone?: ReferenceTone;
+ referenceSlotDisabled?: boolean;
+ referenceLabelFormatter?: ReferenceLabelFormatter;
+ referenceAriaLabelFormatter?: ReferenceLabelFormatter;
+ referenceRemoveLabelFormatter?: ReferenceLabelFormatter;
+ showReferenceAddButton?: boolean;
+ formClassName?: string;
+ footerClassName?: string;
+ promptClassName?: string;
+ referenceSlotClassName?: string;
+ submitButtonClassName?: string;
+ submitLabel?: string;
+ submitAriaLabel?: string;
+ submittingStatusLabel?: string;
};
+
function resetFailedDialogStatus(dialog: GenerateDialogState) {
return {
...dialog,
@@ -50,31 +93,6 @@ function resetFailedDialogStatus(dialog: GenerateDialogState) {
};
}
-function ReferenceChip({
- reference,
- index,
- onRemove,
-}: {
- reference: CharacterReferenceImage;
- index: number;
- onRemove: () => void;
-}) {
- const label = reference.label || `参考图${index + 1}`;
- return (
- }
- imageSrc={reference.src}
- objectKey={reference.objectKey}
- label={label}
- ariaLabel={label}
- title={reference.label}
- onRemove={onRemove}
- removeLabel={`删除${label}`}
- />
- );
-}
-
export function ImageCanvasBasicGenerationComposerView({
dialog,
style,
@@ -86,12 +104,60 @@ export function ImageCanvasBasicGenerationComposerView({
renderEditorPortal = (node) => node,
buildPortalMenuStyle = () => ({}),
onRequestUpload,
+ onPickReferenceFromCanvas,
onToggleReferenceMenu,
onRememberImageModel = () => {},
onSubmit,
+ dialogLabel,
+ includeDimensions = true,
+ includeModel = true,
+ includeReferences = true,
+ promptLabel,
+ promptPlaceholder,
+ optionLabelPrefix,
+ dimensionRatioAriaLabelPrefix,
+ dimensionSizeAriaLabelPrefix,
+ referenceUploadTarget = 'generation-reference',
+ referenceButtonIcon = ,
+ referenceButtonLabel = '参考图',
+ referenceButtonAriaLabel = '添加参考图',
+ referenceMenuLabel = '参考图来源',
+ referenceSlotTone = 'default',
+ referenceSlotDisabled = false,
+ referenceLabelFormatter,
+ referenceAriaLabelFormatter,
+ referenceRemoveLabelFormatter,
+ showReferenceAddButton = true,
+ formClassName,
+ footerClassName,
+ promptClassName = 'image-canvas-editor__generation-prompt',
+ referenceSlotClassName,
+ submitButtonClassName = 'image-canvas-editor__generation-submit',
+ submitLabel = '生成',
+ submitAriaLabel = '生成',
+ submittingStatusLabel = '生成中',
}: ImageCanvasBasicGenerationComposerViewProps) {
const references = dialog.generationReferences ?? [];
const isQuickEdit = dialog.mode === 'quick-edit';
+ const resolvedDialogLabel =
+ dialogLabel ?? optionLabelPrefix ?? (isQuickEdit ? '改造图片' : '生成图片');
+ const resolvedPromptLabel =
+ promptLabel ?? (isQuickEdit ? '改造提示词' : '生成提示词');
+ const resolvedPromptPlaceholder =
+ promptPlaceholder ??
+ (isQuickEdit ? '想怎么改造这张图?' : '今天想生成什么画面?');
+ const resolvedOptionLabelPrefix =
+ optionLabelPrefix ?? (isQuickEdit ? '改造图片' : '生成图片');
+ const resolvedReferenceButtonLabel = referenceButtonLabel;
+ const resolvedReferenceButtonAriaLabel =
+ referenceButtonAriaLabel ?? `添加${resolvedReferenceButtonLabel}`;
+ const hasReferenceMenu = includeReferences && onRequestUpload;
+ const finalFormClassName =
+ formClassName ??
+ 'image-canvas-editor__generation-composer image-canvas-editor__generation-composer--image';
+ const finalFooterClassName =
+ footerClassName ?? 'image-canvas-editor__generation-composer-footer';
+
useImageCanvasFloatingOptionDismiss({
isOpen: isGenerationReferenceMenuOpen,
boundaryRefs: [generationReferenceButtonRef],
@@ -101,10 +167,10 @@ export function ImageCanvasBasicGenerationComposerView({
return (
<>
- {isGenerationReferenceMenuOpen && generationReferenceButtonRef
+ {hasReferenceMenu &&
+ isGenerationReferenceMenuOpen &&
+ generationReferenceButtonRef
? renderEditorPortal(
{
setIsGenerationReferenceMenuOpen?.(false);
- setIsPickingGenerationReferenceFromCanvas?.(true);
+ if (onPickReferenceFromCanvas) {
+ onPickReferenceFromCanvas();
+ } else {
+ setIsPickingGenerationReferenceFromCanvas?.(true);
+ }
}}
>
从画布中选择
@@ -227,7 +328,7 @@ export function ImageCanvasBasicGenerationComposerView({
onClick={() => {
setIsGenerationReferenceMenuOpen?.(false);
setIsPickingGenerationReferenceFromCanvas?.(false);
- onRequestUpload('generation-reference');
+ onRequestUpload(referenceUploadTarget);
}}
>
上传图片
diff --git a/src/components/image-editor/ImageCanvasEditGenerationModalView.tsx b/src/components/image-editor/ImageCanvasEditGenerationModalView.tsx
index 78b2ce32b..de12533d6 100644
--- a/src/components/image-editor/ImageCanvasEditGenerationModalView.tsx
+++ b/src/components/image-editor/ImageCanvasEditGenerationModalView.tsx
@@ -1,13 +1,11 @@
import { type Dispatch, type SetStateAction } from 'react';
-import { PlatformActionButton } from '../common/PlatformActionButton';
-import { PlatformStatusMessage } from '../common/PlatformStatusMessage';
-import { PlatformTextField } from '../common/PlatformTextField';
import { UnifiedModal } from '../common/UnifiedModal';
import {
calculateEditorImageGenerationPrice,
IMAGE_MODEL_GPT_IMAGE_2,
} from './ImageCanvasGenerationModel';
+import { ImageCanvasBasicGenerationComposerView } from './ImageCanvasBasicGenerationComposerView';
import type { GenerateDialogState } from './ImageCanvasEditorTypes';
type ImageCanvasEditGenerationModalViewProps = {
@@ -40,70 +38,32 @@ export function ImageCanvasEditGenerationModalView({
bodyClassName="image-canvas-editor__generate-dialog-body"
>
{dialog?.mode === 'edit' ? (
-
+ style={{}}
+ setGenerateDialog={setGenerateDialog}
+ onRequestUpload={() => {}}
+ onSubmit={onSubmit}
+ dialogLabel="修改图片"
+ includeDimensions={false}
+ includeModel={false}
+ includeReferences={false}
+ promptPlaceholder="描述你想如何修改这张图片"
+ submitLabel="修改"
+ submitAriaLabel={`修改${editPrice}泥点`}
+ submittingStatusLabel="修改中"
+ formClassName="image-canvas-editor__generate-form"
+ footerClassName="image-canvas-editor__generate-body"
+ promptClassName="image-canvas-editor__generate-prompt"
+ submitButtonClassName="image-canvas-editor__generate-submit"
+ />
) : null}
);
diff --git a/src/components/image-editor/ImageCanvasGenerationImageOptionsView.tsx b/src/components/image-editor/ImageCanvasGenerationImageOptionsView.tsx
index cfddaad89..1a3c89c52 100644
--- a/src/components/image-editor/ImageCanvasGenerationImageOptionsView.tsx
+++ b/src/components/image-editor/ImageCanvasGenerationImageOptionsView.tsx
@@ -28,8 +28,11 @@ type ImageCanvasGenerationImageOptionsViewProps = {
dialog: GenerateDialogState;
setGenerateDialog: Dispatch>;
includeDimensions: boolean;
+ includeModel?: boolean;
onRememberImageModel: (model: string) => void;
optionLabelPrefix?: string;
+ dimensionRatioAriaLabelPrefix?: string;
+ dimensionSizeAriaLabelPrefix?: string;
cost?: number;
submitLabel?: string;
submitAriaLabel?: string;
@@ -87,11 +90,13 @@ function OptionChoice({
children,
selected,
className,
+ ariaLabel,
onClick,
}: {
children: ReactNode;
selected: boolean;
className?: string;
+ ariaLabel?: string;
onClick: () => void;
}) {
return (
@@ -100,6 +105,7 @@ function OptionChoice({
className={['image-canvas-editor__option-popover-choice', className]
.filter(Boolean)
.join(' ')}
+ aria-label={ariaLabel}
aria-pressed={selected}
onClick={onClick}
>
@@ -112,8 +118,11 @@ export function ImageCanvasGenerationImageOptionsView({
dialog,
setGenerateDialog,
includeDimensions,
+ includeModel = true,
onRememberImageModel,
optionLabelPrefix,
+ dimensionRatioAriaLabelPrefix,
+ dimensionSizeAriaLabelPrefix,
cost,
submitLabel = '生成',
submitAriaLabel = '生成',
@@ -138,10 +147,15 @@ export function ImageCanvasGenerationImageOptionsView({
imageSize: selection.imageSize,
});
const isGenerating = dialog.status === 'generating';
- const isModelLocked = Boolean(normalizedLockedModel);
+ const isModelLocked = Boolean(normalizedLockedModel) && includeModel;
const labelPrefix = optionLabelPrefix ?? '生成图片';
+ const ratioAriaLabelPrefix = dimensionRatioAriaLabelPrefix?.trim() ?? '';
+ const sizeAriaLabelPrefix = dimensionSizeAriaLabelPrefix?.trim() ?? '';
const dismissOpenPanel = useCallback(() => setOpenPanel(null), []);
+ const formatDimensionOptionLabel = (prefix: string, value: string) =>
+ prefix ? `${prefix} ${value}` : value;
+
useImageCanvasFloatingOptionDismiss({
isOpen: openPanel !== null,
boundaryRefs: [dimensionsButtonRef, modelButtonRef],
@@ -236,6 +250,10 @@ export function ImageCanvasGenerationImageOptionsView({
key={aspectRatio}
selected={selection.aspectRatio === aspectRatio}
className="image-canvas-editor__option-popover-choice--ratio"
+ ariaLabel={formatDimensionOptionLabel(
+ ratioAriaLabelPrefix,
+ aspectRatio,
+ )}
onClick={() => updateDialog({ aspectRatio })}
>
updateDialog({ imageSize })}
>
{imageSize}
@@ -270,80 +292,82 @@ export function ImageCanvasGenerationImageOptionsView({
: null}
) : null}
-
-
- }
- onClick={() => {
- if (!isModelLocked) {
- togglePanel('model');
- }
- }}
+ {includeModel ? (
+
-
-
-
-
- {selectedModelLabel}
-
-
- {!isModelLocked && openPanel === 'model'
- ? renderEditorPortal(
-
event.stopPropagation()}
+
+ }
+ onClick={() => {
+ if (!isModelLocked) {
+ togglePanel('model');
+ }
+ }}
+ >
+
+
-
- {EDITOR_IMAGE_MODEL_OPTIONS.map((option) => {
- const selected = selection.model === option.value;
- return (
-
updateImageModel(option.value)}
- >
-
+
+ {selectedModelLabel}
+
+
+ {!isModelLocked && openPanel === 'model'
+ ? renderEditorPortal(
+ event.stopPropagation()}
+ >
+
+ {EDITOR_IMAGE_MODEL_OPTIONS.map((option) => {
+ const selected = selection.model === option.value;
+ return (
+ updateImageModel(option.value)}
>
-
-
- {option.label}
-
-
- );
- })}
-
- ,
- )
- : null}
-
+
+
+
+ {option.label}
+
+
+ );
+ })}
+
+ ,
+ )
+ : null}
+
+ ) : null}
{typeof cost === 'number' ? (
CSSProperties;
- onRequestUpload?: (target: 'quick-edit-reference') => void;
+ onRequestUpload?: (target: UploadTarget) => void;
onRememberImageModel?: (model: string) => void;
onSubmit: () => void;
};
-type OpenPanel = 'dimensions' | 'model' | null;
-
-function resetFailedPanelStatus(
- panel: T,
-) {
+function resetFailedPanelStatus<
+ T extends { status: string; errorMessage?: string },
+>(panel: T) {
return {
...panel,
status: panel.status === 'failed' ? 'idle' : panel.status,
@@ -67,88 +45,44 @@ function resetFailedPanelStatus void;
-}) {
- const label = `图${index + 1}`;
- return (
- }
- imageSrc={reference.src}
- objectKey={reference.objectKey}
- label={label}
- ariaLabel={label}
- title={reference.label}
- onRemove={onRemove}
- removeLabel={`删除${label}`}
- />
- );
+function createQuickEditDialog(
+ panel: QuickEditPanelState,
+): GenerateDialogState {
+ return {
+ mode: panel.mode ?? 'quick-edit',
+ prompt: panel.prompt,
+ status: panel.status,
+ sourceLayerId: panel.sourceLayerId,
+ generationReferences: panel.quickEditReferences,
+ imageModel: panel.model,
+ aspectRatio: panel.aspectRatio,
+ imageSize: panel.imageSize,
+ };
}
-function getImageDimensionOptions(model: string | null | undefined) {
- return (
- EDITOR_IMAGE_DIMENSION_OPTIONS[
- (normalizeEditorImageModel(model) ??
- IMAGE_MODEL_NANOBANANA2) as keyof typeof EDITOR_IMAGE_DIMENSION_OPTIONS
- ] ?? EDITOR_IMAGE_DIMENSION_OPTIONS[IMAGE_MODEL_NANOBANANA2]
- );
-}
-
-function getPanelAspectRatio(panel: QuickEditPanelState) {
- const options = getImageDimensionOptions(panel.model);
- const aspectRatios = options.aspectRatios as readonly string[];
- return panel.aspectRatio && aspectRatios.includes(panel.aspectRatio)
- ? panel.aspectRatio
- : (options.aspectRatios[0] ?? '1:1');
-}
-
-function getPanelImageSize(panel: QuickEditPanelState) {
- const options = getImageDimensionOptions(panel.model);
- const imageSizes = options.imageSizes as readonly string[];
- return panel.imageSize && imageSizes.includes(panel.imageSize)
- ? panel.imageSize
- : (options.imageSizes.find((size) => size === '1K') ??
- options.imageSizes[0] ??
- '1K');
-}
-
-function QuickEditOptionChoice({
- children,
- selected,
- className,
- ariaLabel,
- onClick,
-}: {
- children: ReactNode;
- selected: boolean;
- className?: string;
- ariaLabel?: string;
- onClick: () => void;
-}) {
- return (
-
- );
+function syncPanelFromDialogUpdate(
+ panel: QuickEditPanelState,
+ dialog: GenerateDialogState,
+) {
+ const normalizedPanel = resetFailedPanelStatus(panel);
+ const normalizedDialog = resetFailedPanelStatus(dialog);
+ return {
+ ...normalizedPanel,
+ size: panel.size,
+ prompt: dialog.prompt,
+ aspectRatio:
+ normalizedDialog.aspectRatio ?? normalizedPanel.aspectRatio ?? '1:1',
+ imageSize: normalizedDialog.imageSize ?? normalizedPanel.imageSize ?? '1K',
+ model: normalizedDialog.imageModel ?? normalizedPanel.model,
+ quickEditReferences: normalizedDialog.generationReferences,
+ status: normalizedDialog.status,
+ errorMessage: normalizedDialog.errorMessage,
+ };
}
export function ImageCanvasQuickEditPanelView({
panel,
+ sourceLayer,
style,
referenceButtonRef,
isReferenceMenuOpen = false,
@@ -157,333 +91,82 @@ export function ImageCanvasQuickEditPanelView({
setQuickEditPanel,
renderEditorPortal = (node) => node,
buildPortalMenuStyle = () => ({}),
- onRequestUpload = () => {},
+ onRequestUpload,
onRememberImageModel = () => {},
onSubmit,
}: ImageCanvasQuickEditPanelViewProps) {
- const [openPanel, setOpenPanel] = useState(null);
- const dimensionsButtonRef = useRef(null);
- const modelButtonRef = useRef(null);
+ void sourceLayer;
+
const isRedraw = panel.mode === 'redraw';
- const isGenerating = panel.status === 'generating';
- const panelLabel = isRedraw ? '重绘图片' : '快速编辑图片';
- const promptLabel = isRedraw ? '重绘提示词' : '快速编辑提示词';
- const references = panel.quickEditReferences ?? [];
- const selectedModel = normalizeEditorImageModel(panel.model);
- const selectedModelLabel = getEditorImageModelDisplayName(selectedModel);
- const dimensionOptions = getImageDimensionOptions(selectedModel);
- const selectedAspectRatio = getPanelAspectRatio(panel);
- const selectedImageSize = getPanelImageSize(panel);
- const dimensionLabel = resolveEditorImageSizeLabel({
- aspectRatio: selectedAspectRatio,
- imageSize: selectedImageSize,
- });
+ const referenceCount = panel.quickEditReferences?.length ?? 0;
const canAddReferences =
- !isRedraw && !isGenerating && references.length < QUICK_EDIT_REFERENCE_LIMIT;
- const dismissOpenPanel = useCallback(() => setOpenPanel(null), []);
-
- useImageCanvasFloatingOptionDismiss({
- isOpen: openPanel !== null,
- boundaryRefs: [dimensionsButtonRef, modelButtonRef],
- onDismiss: dismissOpenPanel,
- });
-
- const updatePanel = (patch: Partial) => {
- setQuickEditPanel((currentPanel) =>
- currentPanel
- ? {
- ...resetFailedPanelStatus(currentPanel),
- ...patch,
- }
- : currentPanel,
- );
- };
-
- const updateModel = (model: string) => {
- const nextOptions = getImageDimensionOptions(model);
- const nextAspectRatios = nextOptions.aspectRatios as readonly string[];
- const nextImageSizes = nextOptions.imageSizes as readonly string[];
- onRememberImageModel(model);
- setQuickEditPanel((currentPanel) => {
- if (!currentPanel) {
- return currentPanel;
- }
- return {
- ...resetFailedPanelStatus(currentPanel),
- model,
- aspectRatio:
- currentPanel.aspectRatio &&
- nextAspectRatios.includes(currentPanel.aspectRatio)
- ? currentPanel.aspectRatio
- : (nextOptions.aspectRatios[0] ?? '1:1'),
- imageSize:
- currentPanel.imageSize && nextImageSizes.includes(currentPanel.imageSize)
- ? currentPanel.imageSize
- : (nextOptions.imageSizes.find((size) => size === '1K') ??
- nextOptions.imageSizes[0]),
- };
- });
- };
-
- const togglePanel = (nextPanel: Exclude) => {
- setOpenPanel((currentPanel) =>
- currentPanel === nextPanel ? null : nextPanel,
- );
- };
+ !isRedraw && referenceCount < QUICK_EDIT_REFERENCE_LIMIT;
+ const quickEditDialog = createQuickEditDialog(panel);
return (
- <>
-
- {!isRedraw && isReferenceMenuOpen && referenceButtonRef
- ? renderEditorPortal(
-
- {
- setIsReferenceMenuOpen?.(false);
- setIsPickingQuickEditReferenceFromCanvas?.(true);
- }}
- >
- 从画布中选择
-
- {
- setIsReferenceMenuOpen?.(false);
- setIsPickingQuickEditReferenceFromCanvas?.(false);
- onRequestUpload('quick-edit-reference');
- }}
- >
- 上传图片
-
- ,
- )
- : null}
- >
+ const currentDialog = createQuickEditDialog(currentPanel);
+ const nextDialog =
+ typeof valueOrUpdater === 'function'
+ ? valueOrUpdater(currentDialog)
+ : valueOrUpdater;
+ if (!nextDialog) {
+ return currentPanel;
+ }
+ return syncPanelFromDialogUpdate(currentPanel, nextDialog);
+ });
+ }}
+ generationReferenceButtonRef={referenceButtonRef}
+ isGenerationReferenceMenuOpen={isReferenceMenuOpen}
+ setIsGenerationReferenceMenuOpen={setIsReferenceMenuOpen}
+ setIsPickingGenerationReferenceFromCanvas={
+ setIsPickingQuickEditReferenceFromCanvas
+ }
+ onRequestUpload={onRequestUpload ?? (() => {})}
+ onPickReferenceFromCanvas={() =>
+ setIsPickingQuickEditReferenceFromCanvas?.(true)
+ }
+ onToggleReferenceMenu={() => setIsReferenceMenuOpen?.((open) => !open)}
+ onRememberImageModel={onRememberImageModel}
+ onSubmit={onSubmit}
+ dialogLabel={isRedraw ? '重绘图片' : '改造图片'}
+ includeDimensions={true}
+ includeModel={true}
+ includeReferences={!isRedraw}
+ promptLabel={isRedraw ? '重绘提示词' : '快速编辑提示词'}
+ promptPlaceholder={
+ isRedraw ? '把画面重绘成什么样?' : '想怎么改造这张图?'
+ }
+ optionLabelPrefix={isRedraw ? '重绘' : '快速编辑'}
+ dimensionRatioAriaLabelPrefix="比例"
+ dimensionSizeAriaLabelPrefix="尺寸"
+ referenceUploadTarget="quick-edit-reference"
+ referenceButtonLabel={isRedraw ? '' : '添加快速编辑参考图'}
+ referenceButtonAriaLabel={isRedraw ? undefined : '添加快速编辑参考图'}
+ referenceMenuLabel={isRedraw ? '' : '快速编辑参考图来源'}
+ referenceSlotTone="quick-edit"
+ referenceSlotDisabled={!canAddReferences}
+ showReferenceAddButton={!isRedraw}
+ referenceLabelFormatter={(_, index) => `图${index + 1}`}
+ referenceAriaLabelFormatter={(_, index) => `图${index + 1}`}
+ referenceRemoveLabelFormatter={(_, index) => `删除图${index + 1}`}
+ formClassName="image-canvas-editor__quick-edit-panel image-canvas-editor__generation-composer image-canvas-editor__generation-composer--image image-canvas-editor__generation-composer--quick-edit"
+ footerClassName="image-canvas-editor__generation-composer-footer image-canvas-editor__quick-edit-footer"
+ promptClassName="image-canvas-editor__generation-prompt image-canvas-editor__quick-edit-prompt"
+ referenceSlotClassName="image-canvas-editor__quick-edit-reference"
+ submitButtonClassName="image-canvas-editor__generation-submit image-canvas-editor__quick-edit-submit"
+ submitLabel="生成"
+ submitAriaLabel="生成"
+ submittingStatusLabel="生成中"
+ renderEditorPortal={renderEditorPortal}
+ buildPortalMenuStyle={buildPortalMenuStyle}
+ />
);
}