diff --git a/packages/editor/src/components/StructureTree/ComponentNode.tsx b/packages/editor/src/components/StructureTree/ComponentNode.tsx
index 2cc8e558..d6baa797 100644
--- a/packages/editor/src/components/StructureTree/ComponentNode.tsx
+++ b/packages/editor/src/components/StructureTree/ComponentNode.tsx
@@ -8,6 +8,7 @@ import {
MenuItem,
MenuList,
IconButton,
+ useToast,
} from '@chakra-ui/react';
import { isEqual, xor } from 'lodash';
import { ComponentItemView } from './ComponentItemView';
@@ -21,6 +22,7 @@ import { RootId } from '../../constants';
import { RelationshipModal } from '../RelationshipModal';
import { ExplorerMenuTabs } from '../../constants/enum';
import { ExtractModuleModal } from '../ExtractModuleModal';
+import { copyToClipboard } from '../../utils/copy';
const IndextWidth = 24;
@@ -51,7 +53,8 @@ const ComponentNodeImpl = (props: Props) => {
onDragEnd,
prefix,
} = props;
- const { registry, eventBus, appModelManager, editorStore } = services;
+ const toast = useToast();
+ const { registry, eventBus, appModelManager, editorStore, stateManager } = services;
const [isShowRelationshipModal, setIsShowRelationshipModal] = useState(false);
const [isShowExtractModuleModal, setIsShowExtractModuleModal] = useState(false);
const slots = Object.keys(registry.getComponentByType(component.type).spec.slots);
@@ -103,6 +106,34 @@ const ComponentNodeImpl = (props: Props) => {
},
[component.id, editorStore]
);
+ const onClickCopyState = useCallback(
+ (e: React.MouseEvent) => {
+ e.stopPropagation();
+
+ const componentState = stateManager.store[component.id];
+
+ if (componentState) {
+ const success = copyToClipboard(JSON.stringify(componentState, null, 2));
+
+ if (success) {
+ toast({
+ title: 'Copy state to clipboard successfully.',
+ status: 'success',
+ position: 'top',
+ duration: 1500,
+ });
+ } else {
+ toast({
+ title: 'Copy state to clipboard failed.',
+ status: 'warning',
+ position: 'top',
+ duration: 1500,
+ });
+ }
+ }
+ },
+ [component.id, stateManager, toast]
+ );
const onClickExtractToModule = useCallback((e: React.MouseEvent) => {
e.stopPropagation();
setIsShowExtractModuleModal(true);
@@ -189,6 +220,9 @@ const ComponentNodeImpl = (props: Props) => {
} onClick={onClickShowState}>
Show State
+ } onClick={onClickCopyState}>
+ Copy State
+
} onClick={onClickExtractToModule}>
Extract to Module
diff --git a/packages/editor/src/utils/copy.ts b/packages/editor/src/utils/copy.ts
new file mode 100644
index 00000000..931cb86c
--- /dev/null
+++ b/packages/editor/src/utils/copy.ts
@@ -0,0 +1,16 @@
+export function copyToClipboard(text: string) {
+ const textarea = document.createElement('textarea');
+
+ textarea.textContent = text;
+ textarea.style.position = 'fixed';
+ document.body.appendChild(textarea);
+ textarea.select();
+
+ try {
+ return document.execCommand('copy');
+ } catch (ex) {
+ return false;
+ } finally {
+ document.body.removeChild(textarea);
+ }
+}