Skip to content

Commit

Permalink
Add undo/redo
Browse files Browse the repository at this point in the history
  • Loading branch information
amir9480 committed Aug 13, 2024
1 parent 3689ad1 commit 2da7e39
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 5 deletions.
33 changes: 33 additions & 0 deletions packages/editor-sample/src/App/TemplatePanel/Redo/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { useEffect } from 'react';

import { RedoOutlined as RedoIcon } from '@mui/icons-material';
import { IconButton, Tooltip } from '@mui/material';

import { redo, useCanRedo } from '../../../documents/editor/EditorContext';

export default function Redo() {
const canRedo = useCanRedo();
useEffect(() => {
function handle(event: KeyboardEvent) {
if (event.ctrlKey && event.key.toLowerCase() === 'y') {
event.preventDefault();
redo();
}
}

document.addEventListener('keydown', handle);
return () => document.removeEventListener('keydown', handle);
}, []);

return (
<>
<Tooltip title="Redo (Ctrl + Y)">
<span>
<IconButton onClick={redo} disabled={canRedo === false}>
<RedoIcon fontSize="small" />
</IconButton>
</span>
</Tooltip>
</>
);
}
33 changes: 33 additions & 0 deletions packages/editor-sample/src/App/TemplatePanel/Undo/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { useEffect } from 'react';

import { UndoOutlined as UndoIcon } from '@mui/icons-material';
import { IconButton, Tooltip } from '@mui/material';

import { undo, useCanUndo } from '../../../documents/editor/EditorContext';

export default function Undo() {
const canUndo = useCanUndo();
useEffect(() => {
function handle(event: KeyboardEvent) {
if (event.ctrlKey && event.key.toLowerCase() === 'z') {
event.preventDefault();
undo();
}
}

document.addEventListener('keydown', handle);
return () => document.removeEventListener('keydown', handle);
}, []);

return (
<>
<Tooltip title="Undo (Ctrl + Z)">
<span>
<IconButton onClick={undo} disabled={canUndo === false}>
<UndoIcon fontSize="small" />
</IconButton>
</span>
</Tooltip>
</>
);
}
4 changes: 4 additions & 0 deletions packages/editor-sample/src/App/TemplatePanel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import ImportJson from './ImportJson';
import JsonPanel from './JsonPanel';
import MainTabsGroup from './MainTabsGroup';
import ShareButton from './ShareButton';
import Undo from './Undo';
import Redo from './Redo';

export default function TemplatePanel() {
const document = useDocument();
Expand Down Expand Up @@ -97,6 +99,8 @@ export default function TemplatePanel() {
<Stack direction="row" spacing={2}>
<DownloadJson />
<ImportJson />
<Undo />
<Redo />
<ToggleButtonGroup value={selectedScreenSize} exclusive size="small" onChange={handleScreenSizeChange}>
<ToggleButton value="desktop">
<Tooltip title="Desktop view">
Expand Down
69 changes: 64 additions & 5 deletions packages/editor-sample/src/documents/editor/EditorContext.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { create } from 'zustand';

Check failure on line 1 in packages/editor-sample/src/documents/editor/EditorContext.tsx

View workflow job for this annotation

GitHub Actions / build

Run autofix to sort these imports!

import debounce from '@mui/material/utils/debounce';
import getConfiguration from '../../getConfiguration';

import { TEditorConfiguration } from './core';

type TValue = {
document: TEditorConfiguration;

documentHistory: Array<TEditorConfiguration>,
documentHistoryIndex: number,

selectedBlockId: string | null;
selectedSidebarTab: 'block-configuration' | 'styles';
selectedMainTab: 'editor' | 'preview' | 'json' | 'html';
Expand All @@ -18,6 +21,8 @@ type TValue = {

const editorStateStore = create<TValue>(() => ({
document: getConfiguration(window.location.hash),
documentHistory: [],
documentHistoryIndex: 0,
selectedBlockId: null,
selectedSidebarTab: 'styles',
selectedMainTab: 'editor',
Expand Down Expand Up @@ -76,7 +81,25 @@ export function setSidebarTab(selectedSidebarTab: TValue['selectedSidebarTab'])
return editorStateStore.setState({ selectedSidebarTab });
}

const addDocumentToHistory = debounce(function (document: TValue['document']) {
let documentHistory = editorStateStore.getState().documentHistory;
const currentIndex = editorStateStore.getState().documentHistoryIndex;
if (currentIndex < documentHistory.length - 1) {
documentHistory = documentHistory.slice(0, currentIndex + 1);
}
documentHistory.push(document);
if (documentHistory.length > 254) {
documentHistory = documentHistory.slice(1);
}

editorStateStore.setState({
documentHistory,
documentHistoryIndex: documentHistory.length - 1,
});
}, 500);

export function resetDocument(document: TValue['document']) {
addDocumentToHistory(document);
return editorStateStore.setState({
document,
selectedSidebarTab: 'styles',
Expand All @@ -86,11 +109,47 @@ export function resetDocument(document: TValue['document']) {

export function setDocument(document: TValue['document']) {
const originalDocument = editorStateStore.getState().document;
const mergedDocument = {
...originalDocument,
...document,
};
addDocumentToHistory(mergedDocument);
return editorStateStore.setState({
document: {
...originalDocument,
...document,
},
document: mergedDocument,
});
}

export function useCanUndo() {
return editorStateStore(s => s.documentHistory.length > 0 && s.documentHistoryIndex > 0);
}

export function useCanRedo() {
return editorStateStore(s => s.documentHistory.length > 0 && s.documentHistoryIndex < s.documentHistory.length - 1);
}

export function undo() {
const documentHistory = editorStateStore.getState().documentHistory;
const currentIndex = editorStateStore.getState().documentHistoryIndex;
if (documentHistory.length <= 0 || currentIndex <= 0) {
return;
}
const changeToIndex = currentIndex - 1;
editorStateStore.setState({
document: documentHistory[changeToIndex],
documentHistoryIndex: changeToIndex,
});
}

export function redo() {
const documentHistory = editorStateStore.getState().documentHistory;
const currentIndex = editorStateStore.getState().documentHistoryIndex;
if (documentHistory.length <= 0 || currentIndex >= documentHistory.length - 1) {
return;
}
const changeToIndex = currentIndex + 1;
editorStateStore.setState({
document: documentHistory[changeToIndex],
documentHistoryIndex: changeToIndex,
});
}

Expand Down

0 comments on commit 2da7e39

Please sign in to comment.