From a18342b5b56720eff1d8508cf4bcaed8c2387bcc Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Sat, 18 Apr 2020 01:54:19 +0530 Subject: [PATCH] Refactor LayerUI (#1434) * chore(gitignore): add .idea to gitignore * refactor(layerui): pass named function to react.memo so that in dev tools the name shows up This makes debugging easier as well * refactor(layerui): break the functional component into multiple render methods --- .gitignore | 1 + src/components/App.tsx | 2 +- src/components/LayerUI.tsx | 417 +++++++++++++++++++------------------ 3 files changed, 221 insertions(+), 199 deletions(-) diff --git a/.gitignore b/.gitignore index bf453146..22011448 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ static yarn-debug.log* yarn-error.log* yarn.lock +.idea diff --git a/src/components/App.tsx b/src/components/App.tsx index dd2ebd4e..6d392f75 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -114,7 +114,7 @@ import { TAP_TWICE_TIMEOUT, } from "../time_constants"; -import { LayerUI } from "./LayerUI"; +import LayerUI from "./LayerUI"; import { ScrollBars, SceneState } from "../scene/types"; import { generateCollaborationLink, getCollaborationLinkData } from "../data"; import { mutateElement, newElementWith } from "../element/mutateElement"; diff --git a/src/components/LayerUI.tsx b/src/components/LayerUI.tsx index 64c18b30..38787ed8 100644 --- a/src/components/LayerUI.tsx +++ b/src/components/LayerUI.tsx @@ -40,212 +40,233 @@ interface LayerUIProps { onLockToggle: () => void; } -export const LayerUI = React.memo( - ({ - actionManager, - appState, - setAppState, - canvas, - elements, - onRoomCreate, - onUsernameChange, - onRoomDestroy, - onLockToggle, - }: LayerUIProps) => { - const isMobile = useIsMobile(); +const LayerUI = ({ + actionManager, + appState, + setAppState, + canvas, + elements, + onRoomCreate, + onUsernameChange, + onRoomDestroy, + onLockToggle, +}: LayerUIProps) => { + const isMobile = useIsMobile(); - function renderExportDialog() { - const createExporter = (type: ExportType): ExportCB => ( - exportedElements, - scale, - ) => { - if (canvas) { - exportCanvas(type, exportedElements, appState, canvas, { - exportBackground: appState.exportBackground, - name: appState.name, - viewBackgroundColor: appState.viewBackgroundColor, - scale, - }); - } - }; - return ( - { - if (canvas) { - exportCanvas( - "backend", - exportedElements, - { - ...appState, - selectedElementIds: {}, - }, - canvas, - appState, - ); - } - }} - /> - ); - } - - return isMobile ? ( - { + const createExporter = (type: ExportType): ExportCB => ( + exportedElements, + scale, + ) => { + if (canvas) { + exportCanvas(type, exportedElements, appState, canvas, { + exportBackground: appState.exportBackground, + name: appState.name, + viewBackgroundColor: appState.viewBackgroundColor, + scale, + }); + } + }; + return ( + { + if (canvas) { + exportCanvas( + "backend", + exportedElements, + { + ...appState, + selectedElementIds: {}, + }, + canvas, + appState, + ); + } + }} /> - ) : ( - <> - {appState.isLoading && } - {appState.errorMessage && ( - setAppState({ errorMessage: null })} - /> - )} - {appState.showShortcutsDialog && ( - setAppState({ showShortcutsDialog: null })} - /> - )} - - -
- -
- {/* the zIndex ensures this menu has higher stacking order, - see https://github.com/excalidraw/excalidraw/pull/1445 */} - - - - {actionManager.renderAction("loadScene")} - {actionManager.renderAction("saveScene")} - {renderExportDialog()} - {actionManager.renderAction("clearCanvas")} - ( +
+ {/* the zIndex ensures this menu has higher stacking order, + see https://github.com/excalidraw/excalidraw/pull/1445 */} + + + + {actionManager.renderAction("loadScene")} + {actionManager.renderAction("saveScene")} + {renderExportDialog()} + {actionManager.renderAction("clearCanvas")} + + + {actionManager.renderAction("changeViewBackgroundColor")} + + +
+ ); + + const renderSelectedShapeActions = () => ( +
+ + + +
+ ); + + const renderFixedSideContainer = () => { + const shouldRenderSelectedShapeActions = showSelectedShapeActions( + appState, + elements, + ); + return ( + + +
+ + {renderCanvasActions()} + {shouldRenderSelectedShapeActions && renderSelectedShapeActions()} + +
+ {(heading) => ( + + + + {heading} + + - {actionManager.renderAction("changeViewBackgroundColor")} - - -
- {showSelectedShapeActions(appState, elements) && ( -
- - -
- )} - -
- {(heading) => ( - - - - {heading} - - - - - - - - )} -
-
-
-
- -
- - - -
-
-
- - -
- { - setLanguage(lng); - setAppState({}); - }} - languages={languages} - floating - /> - {actionManager.renderAction("toggleShortcuts")} - {appState.scrolledOutside && ( - - )} -
- + + + )} +
+
+
+
+ +
+ + + +
+
+
+ ); - }, - (prev, next) => { - const getNecessaryObj = (appState: AppState): Partial => { - const { - draggingElement, - resizingElement, - multiElement, - editingElement, - isResizing, - cursorX, - cursorY, - ...ret - } = appState; - return ret; - }; - const prevAppState = getNecessaryObj(prev.appState); - const nextAppState = getNecessaryObj(next.appState); + }; - const keys = Object.keys(prevAppState) as (keyof Partial)[]; + const renderFooter = () => ( +
+ { + setLanguage(lng); + setAppState({}); + }} + languages={languages} + floating + /> + {actionManager.renderAction("toggleShortcuts")} + {appState.scrolledOutside && ( + + )} +
+ ); - return ( - prev.elements === next.elements && - keys.every((key) => prevAppState[key] === nextAppState[key]) - ); - }, -); + return isMobile ? ( + + ) : ( + <> + {appState.isLoading && } + {appState.errorMessage && ( + setAppState({ errorMessage: null })} + /> + )} + {appState.showShortcutsDialog && ( + setAppState({ showShortcutsDialog: null })} + /> + )} + {renderFixedSideContainer()} + + {renderFooter()} + + ); +}; + +const areEqual = (prev: LayerUIProps, next: LayerUIProps) => { + const getNecessaryObj = (appState: AppState): Partial => { + const { + draggingElement, + resizingElement, + multiElement, + editingElement, + isResizing, + cursorX, + cursorY, + ...ret + } = appState; + return ret; + }; + const prevAppState = getNecessaryObj(prev.appState); + const nextAppState = getNecessaryObj(next.appState); + + const keys = Object.keys(prevAppState) as (keyof Partial)[]; + + return ( + prev.elements === next.elements && + keys.every((key) => prevAppState[key] === nextAppState[key]) + ); +}; + +export default React.memo(LayerUI, areEqual);