diff --git a/packages/editor/src/components/StructureTree/ComponentNode.tsx b/packages/editor/src/components/StructureTree/ComponentNode.tsx index 2cc8e5581..d6baa797e 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 000000000..931cb86ce --- /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); + } +}