mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-22 16:48:23 +01:00
react.memo (#79)
This commit is contained in:
parent
f036459dd5
commit
4f627a0342
@ -174,7 +174,7 @@ interface FramelessBlockHeaderProps {
|
|||||||
dragHandleRef?: React.RefObject<HTMLDivElement>;
|
dragHandleRef?: React.RefObject<HTMLDivElement>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FramelessBlockHeader = ({ blockId, onClose, dragHandleRef }: FramelessBlockHeaderProps) => {
|
const FramelessBlockHeader = React.memo(({ blockId, onClose, dragHandleRef }: FramelessBlockHeaderProps) => {
|
||||||
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
|
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
|
||||||
const settingsConfig = jotai.useAtomValue(atoms.settingsConfigAtom);
|
const settingsConfig = jotai.useAtomValue(atoms.settingsConfigAtom);
|
||||||
|
|
||||||
@ -193,7 +193,7 @@ const FramelessBlockHeader = ({ blockId, onClose, dragHandleRef }: FramelessBloc
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
const hoverStateOff = "off";
|
const hoverStateOff = "off";
|
||||||
const hoverStatePending = "pending";
|
const hoverStatePending = "pending";
|
||||||
@ -209,15 +209,8 @@ interface BlockFrameProps {
|
|||||||
dragHandleRef?: React.RefObject<HTMLDivElement>;
|
dragHandleRef?: React.RefObject<HTMLDivElement>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BlockFrame_Tech = ({
|
const BlockFrame_Tech = React.memo(
|
||||||
blockId,
|
({ blockId, onClose, onClick, preview, blockRef, dragHandleRef, children }: BlockFrameProps) => {
|
||||||
onClose,
|
|
||||||
onClick,
|
|
||||||
preview,
|
|
||||||
blockRef,
|
|
||||||
dragHandleRef,
|
|
||||||
children,
|
|
||||||
}: BlockFrameProps) => {
|
|
||||||
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
|
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
|
||||||
const settingsConfig = jotai.useAtomValue(atoms.settingsConfigAtom);
|
const settingsConfig = jotai.useAtomValue(atoms.settingsConfigAtom);
|
||||||
const isFocusedAtom = useBlockAtom<boolean>(blockId, "isFocused", () => {
|
const isFocusedAtom = useBlockAtom<boolean>(blockId, "isFocused", () => {
|
||||||
@ -264,7 +257,8 @@ const BlockFrame_Tech = ({
|
|||||||
{preview ? <div className="block-frame-preview" /> : children}
|
{preview ? <div className="block-frame-preview" /> : children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const BlockFrame_Frameless = ({
|
const BlockFrame_Frameless = ({
|
||||||
blockId,
|
blockId,
|
||||||
@ -340,7 +334,7 @@ const BlockFrame_Frameless = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const BlockFrame = (props: BlockFrameProps) => {
|
const BlockFrame = React.memo((props: BlockFrameProps) => {
|
||||||
const blockId = props.blockId;
|
const blockId = props.blockId;
|
||||||
const [blockData, blockDataLoading] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
|
const [blockData, blockDataLoading] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
|
||||||
const tabData = jotai.useAtomValue(atoms.tabAtom);
|
const tabData = jotai.useAtomValue(atoms.tabAtom);
|
||||||
@ -360,7 +354,7 @@ const BlockFrame = (props: BlockFrameProps) => {
|
|||||||
FrameElem = BlockFrame_Frameless;
|
FrameElem = BlockFrame_Frameless;
|
||||||
}
|
}
|
||||||
return <FrameElem {...props} />;
|
return <FrameElem {...props} />;
|
||||||
};
|
});
|
||||||
|
|
||||||
function blockViewToIcon(view: string): string {
|
function blockViewToIcon(view: string): string {
|
||||||
console.log("blockViewToIcon", view);
|
console.log("blockViewToIcon", view);
|
||||||
@ -398,7 +392,16 @@ function useBlockIcon(blockId: string): string {
|
|||||||
return blockIcon;
|
return blockIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Block = ({ blockId, onClose, dragHandleRef }: BlockProps) => {
|
const wm = new WeakMap();
|
||||||
|
let wmCounter = 0;
|
||||||
|
function getObjectId(obj: any): number {
|
||||||
|
if (!wm.has(obj)) {
|
||||||
|
wm.set(obj, wmCounter++);
|
||||||
|
}
|
||||||
|
return wm.get(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Block = React.memo(({ blockId, onClose, dragHandleRef }: BlockProps) => {
|
||||||
let blockElem: JSX.Element = null;
|
let blockElem: JSX.Element = null;
|
||||||
const focusElemRef = React.useRef<HTMLInputElement>(null);
|
const focusElemRef = React.useRef<HTMLInputElement>(null);
|
||||||
const blockRef = React.useRef<HTMLDivElement>(null);
|
const blockRef = React.useRef<HTMLDivElement>(null);
|
||||||
@ -417,24 +420,29 @@ const Block = ({ blockId, onClose, dragHandleRef }: BlockProps) => {
|
|||||||
setBlockFocus(blockId);
|
setBlockFocus(blockId);
|
||||||
}, [blockClicked]);
|
}, [blockClicked]);
|
||||||
|
|
||||||
|
const setBlockClickedTrue = React.useCallback(() => {
|
||||||
|
setBlockClicked(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
if (!blockId || !blockData) return null;
|
if (!blockId || !blockData) return null;
|
||||||
if (blockDataLoading) {
|
if (blockDataLoading) {
|
||||||
blockElem = <CenteredDiv>Loading...</CenteredDiv>;
|
blockElem = <CenteredDiv>Loading...</CenteredDiv>;
|
||||||
} else if (blockData.view === "term") {
|
} else if (blockData.view === "term") {
|
||||||
blockElem = <TerminalView blockId={blockId} />;
|
blockElem = <TerminalView key={blockId} blockId={blockId} />;
|
||||||
} else if (blockData.view === "preview") {
|
} else if (blockData.view === "preview") {
|
||||||
blockElem = <PreviewView blockId={blockId} />;
|
blockElem = <PreviewView key={blockId} blockId={blockId} />;
|
||||||
} else if (blockData.view === "plot") {
|
} else if (blockData.view === "plot") {
|
||||||
blockElem = <PlotView />;
|
blockElem = <PlotView key={blockId} />;
|
||||||
} else if (blockData.view === "codeedit") {
|
} else if (blockData.view === "codeedit") {
|
||||||
blockElem = <CodeEdit text={null} filename={null} />;
|
blockElem = <CodeEdit key={blockId} text={null} filename={null} />;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<BlockFrame
|
<BlockFrame
|
||||||
|
key={blockId}
|
||||||
blockId={blockId}
|
blockId={blockId}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
preview={false}
|
preview={false}
|
||||||
onClick={() => setBlockClicked(true)}
|
onClick={setBlockClickedTrue}
|
||||||
blockRef={blockRef}
|
blockRef={blockRef}
|
||||||
dragHandleRef={dragHandleRef}
|
dragHandleRef={dragHandleRef}
|
||||||
>
|
>
|
||||||
@ -448,6 +456,6 @@ const Block = ({ blockId, onClose, dragHandleRef }: BlockProps) => {
|
|||||||
</div>
|
</div>
|
||||||
</BlockFrame>
|
</BlockFrame>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
export { Block, BlockFrame };
|
export { Block, BlockFrame };
|
||||||
|
@ -6,7 +6,7 @@ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Button: React.FC<ButtonProps> = ({ className = "primary", children, disabled, ...props }) => {
|
const Button: React.FC<ButtonProps> = React.memo(({ className = "primary", children, disabled, ...props }) => {
|
||||||
const hasIcon = React.Children.toArray(children).some(
|
const hasIcon = React.Children.toArray(children).some(
|
||||||
(child) => React.isValidElement(child) && (child as React.ReactElement).type === "svg"
|
(child) => React.isValidElement(child) && (child as React.ReactElement).type === "svg"
|
||||||
);
|
);
|
||||||
@ -23,6 +23,6 @@ const Button: React.FC<ButtonProps> = ({ className = "primary", children, disabl
|
|||||||
{children}
|
{children}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
export { Button };
|
export { Button };
|
||||||
|
@ -6,6 +6,7 @@ import { ContextMenuModel } from "@/store/contextmenu";
|
|||||||
import * as services from "@/store/services";
|
import * as services from "@/store/services";
|
||||||
import * as WOS from "@/store/wos";
|
import * as WOS from "@/store/wos";
|
||||||
import { clsx } from "clsx";
|
import { clsx } from "clsx";
|
||||||
|
import * as React from "react";
|
||||||
import { forwardRef, useEffect, useRef, useState } from "react";
|
import { forwardRef, useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
import "./tab.less";
|
import "./tab.less";
|
||||||
@ -22,7 +23,8 @@ interface TabProps {
|
|||||||
onLoaded: () => void;
|
onLoaded: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Tab = forwardRef<HTMLDivElement, TabProps>(
|
const Tab = React.memo(
|
||||||
|
forwardRef<HTMLDivElement, TabProps>(
|
||||||
({ id, active, isFirst, isBeforeActive, isDragging, onLoaded, onSelect, onClose, onDragStart }, ref) => {
|
({ id, active, isFirst, isBeforeActive, isDragging, onLoaded, onSelect, onClose, onDragStart }, ref) => {
|
||||||
const [tabData, tabLoading] = WOS.useWaveObjectValue<Tab>(WOS.makeORef("tab", id));
|
const [tabData, tabLoading] = WOS.useWaveObjectValue<Tab>(WOS.makeORef("tab", id));
|
||||||
const [originalName, setOriginalName] = useState("");
|
const [originalName, setOriginalName] = useState("");
|
||||||
@ -145,6 +147,7 @@ const Tab = forwardRef<HTMLDivElement, TabProps>(
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
export { Tab };
|
export { Tab };
|
||||||
|
@ -37,7 +37,7 @@ interface TabBarProps {
|
|||||||
workspace: Workspace;
|
workspace: Workspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TabBar = ({ workspace }: TabBarProps) => {
|
const TabBar = React.memo(({ workspace }: TabBarProps) => {
|
||||||
const [tabIds, setTabIds] = useState<string[]>([]);
|
const [tabIds, setTabIds] = useState<string[]>([]);
|
||||||
const [dragStartPositions, setDragStartPositions] = useState<number[]>([]);
|
const [dragStartPositions, setDragStartPositions] = useState<number[]>([]);
|
||||||
const [draggingTab, setDraggingTab] = useState<string>();
|
const [draggingTab, setDraggingTab] = useState<string>();
|
||||||
@ -497,6 +497,6 @@ const TabBar = ({ workspace }: TabBarProps) => {
|
|||||||
<WindowDrag ref={draggerRightRef} className="right" />
|
<WindowDrag ref={draggerRightRef} className="right" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
export { TabBar };
|
export { TabBar };
|
||||||
|
@ -4,16 +4,17 @@
|
|||||||
import { Block, BlockFrame } from "@/app/block/block";
|
import { Block, BlockFrame } from "@/app/block/block";
|
||||||
import * as services from "@/store/services";
|
import * as services from "@/store/services";
|
||||||
import * as WOS from "@/store/wos";
|
import * as WOS from "@/store/wos";
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
import { CenteredDiv, CenteredLoadingDiv } from "@/element/quickelems";
|
import { CenteredDiv, CenteredLoadingDiv } from "@/element/quickelems";
|
||||||
import { TileLayout } from "@/faraday/index";
|
import { TileLayout } from "@/faraday/index";
|
||||||
import { getLayoutStateAtomForTab } from "@/faraday/lib/layoutAtom";
|
import { getLayoutStateAtomForTab } from "@/faraday/lib/layoutAtom";
|
||||||
import { useAtomValue } from "jotai";
|
import { useAtomValue } from "jotai";
|
||||||
import { useCallback, useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { getApi } from "../store/global";
|
import { getApi } from "../store/global";
|
||||||
import "./tabcontent.less";
|
import "./tabcontent.less";
|
||||||
|
|
||||||
const TabContent = ({ tabId }: { tabId: string }) => {
|
const TabContent = React.memo(({ tabId }: { tabId: string }) => {
|
||||||
const oref = useMemo(() => WOS.makeORef("tab", tabId), [tabId]);
|
const oref = useMemo(() => WOS.makeORef("tab", tabId), [tabId]);
|
||||||
const loadingAtom = useMemo(() => WOS.getWaveObjectLoadingAtom(oref), [oref]);
|
const loadingAtom = useMemo(() => WOS.getWaveObjectLoadingAtom(oref), [oref]);
|
||||||
const tabLoading = useAtomValue(loadingAtom);
|
const tabLoading = useAtomValue(loadingAtom);
|
||||||
@ -21,31 +22,40 @@ const TabContent = ({ tabId }: { tabId: string }) => {
|
|||||||
const layoutStateAtom = useMemo(() => getLayoutStateAtomForTab(tabId, tabAtom), [tabAtom, tabId]);
|
const layoutStateAtom = useMemo(() => getLayoutStateAtomForTab(tabId, tabAtom), [tabAtom, tabId]);
|
||||||
const tabData = useAtomValue(tabAtom);
|
const tabData = useAtomValue(tabAtom);
|
||||||
|
|
||||||
const renderBlock = useCallback(
|
const tileLayoutContents = useMemo(() => {
|
||||||
(
|
function renderBlock(
|
||||||
tabData: TabLayoutData,
|
tabData: TabLayoutData,
|
||||||
ready: boolean,
|
ready: boolean,
|
||||||
onClose: () => void,
|
onClose: () => void,
|
||||||
dragHandleRef: React.RefObject<HTMLDivElement>
|
dragHandleRef: React.RefObject<HTMLDivElement>
|
||||||
) => {
|
) {
|
||||||
if (!tabData.blockId || !ready) {
|
if (!tabData.blockId || !ready) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return <Block blockId={tabData.blockId} onClose={onClose} dragHandleRef={dragHandleRef} />;
|
return (
|
||||||
},
|
<Block
|
||||||
[]
|
key={tabData.blockId}
|
||||||
|
blockId={tabData.blockId}
|
||||||
|
onClose={onClose}
|
||||||
|
dragHandleRef={dragHandleRef}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const renderPreview = useCallback((tabData: TabLayoutData) => {
|
function renderPreview(tabData: TabLayoutData) {
|
||||||
return <BlockFrame blockId={tabData.blockId} preview={true} />;
|
return <BlockFrame key={tabData.blockId} blockId={tabData.blockId} preview={true} />;
|
||||||
}, []);
|
}
|
||||||
|
|
||||||
const onNodeDelete = useCallback((data: TabLayoutData) => {
|
function onNodeDelete(data: TabLayoutData) {
|
||||||
return services.ObjectService.DeleteBlock(data.blockId);
|
return services.ObjectService.DeleteBlock(data.blockId);
|
||||||
}, []);
|
}
|
||||||
|
|
||||||
const getCursorPoint = useCallback(() => {
|
return {
|
||||||
return getApi().getCursorPoint();
|
renderContent: renderBlock,
|
||||||
|
renderPreview: renderPreview,
|
||||||
|
tabId: tabId,
|
||||||
|
onNodeDelete: onNodeDelete,
|
||||||
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (tabLoading) {
|
if (tabLoading) {
|
||||||
@ -68,15 +78,12 @@ const TabContent = ({ tabId }: { tabId: string }) => {
|
|||||||
<div className="tabcontent">
|
<div className="tabcontent">
|
||||||
<TileLayout
|
<TileLayout
|
||||||
key={tabId}
|
key={tabId}
|
||||||
tabId={tabId}
|
contents={tileLayoutContents}
|
||||||
renderContent={renderBlock}
|
|
||||||
renderPreview={renderPreview}
|
|
||||||
layoutTreeStateAtom={layoutStateAtom}
|
layoutTreeStateAtom={layoutStateAtom}
|
||||||
onNodeDelete={onNodeDelete}
|
getCursorPoint={getApi().getCursorPoint}
|
||||||
getCursorPoint={getCursorPoint}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
export { TabContent };
|
export { TabContent };
|
||||||
|
@ -67,6 +67,13 @@
|
|||||||
&.col-size {
|
&.col-size {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dir-table-lastmod,
|
||||||
|
.dir-table-modestr,
|
||||||
|
.dir-table-size,
|
||||||
|
.dir-table-type {
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,37 +158,40 @@ function DirectoryTable({ data, cwd, setFileName }: DirectoryTableProps) {
|
|||||||
() => [
|
() => [
|
||||||
columnHelper.accessor("mimetype", {
|
columnHelper.accessor("mimetype", {
|
||||||
cell: (info) => <i className={getIconFromMimeType(info.getValue() ?? "")}></i>,
|
cell: (info) => <i className={getIconFromMimeType(info.getValue() ?? "")}></i>,
|
||||||
header: () => <span></span>,
|
header: () => <span>Type</span>,
|
||||||
id: "logo",
|
id: "logo",
|
||||||
size: 25,
|
size: 25,
|
||||||
enableSorting: false,
|
enableSorting: false,
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("path", {
|
columnHelper.accessor("path", {
|
||||||
cell: (info) => info.getValue(),
|
cell: (info) => <span className="dir-table-path">{info.getValue()}</span>,
|
||||||
header: () => <span>Name</span>,
|
header: () => <span>Name</span>,
|
||||||
sortingFn: "alphanumeric",
|
sortingFn: "alphanumeric",
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("modestr", {
|
columnHelper.accessor("modestr", {
|
||||||
cell: (info) => info.getValue(),
|
cell: (info) => <span className="dir-table-modestr">{info.getValue()}</span>,
|
||||||
header: () => <span>Permissions</span>,
|
header: () => <span>Permissions</span>,
|
||||||
size: 91,
|
size: 91,
|
||||||
sortingFn: "alphanumeric",
|
sortingFn: "alphanumeric",
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("modtime", {
|
columnHelper.accessor("modtime", {
|
||||||
cell: (info) =>
|
cell: (info) => (
|
||||||
getLastModifiedTime(info.getValue(), settings.datetime.locale, settings.datetime.format),
|
<span className="dir-table-lastmod">
|
||||||
|
{getLastModifiedTime(info.getValue(), settings.datetime.locale, settings.datetime.format)}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
header: () => <span>Last Modified</span>,
|
header: () => <span>Last Modified</span>,
|
||||||
size: 185,
|
size: 185,
|
||||||
sortingFn: "datetime",
|
sortingFn: "datetime",
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("size", {
|
columnHelper.accessor("size", {
|
||||||
cell: (info) => getBestUnit(info.getValue()),
|
cell: (info) => <span className="dir-table-size">{getBestUnit(info.getValue())}</span>,
|
||||||
header: () => <span>Size</span>,
|
header: () => <span>Size</span>,
|
||||||
size: 55,
|
size: 55,
|
||||||
sortingFn: "auto",
|
sortingFn: "auto",
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("mimetype", {
|
columnHelper.accessor("mimetype", {
|
||||||
cell: (info) => info.getValue(),
|
cell: (info) => <span className="dir-table-type">{info.getValue()}</span>,
|
||||||
header: () => <span>Type</span>,
|
header: () => <span>Type</span>,
|
||||||
sortingFn: "alphanumeric",
|
sortingFn: "alphanumeric",
|
||||||
}),
|
}),
|
||||||
|
@ -14,7 +14,7 @@ import "./workspace.less";
|
|||||||
|
|
||||||
const iconRegex = /^[a-z0-9-]+$/;
|
const iconRegex = /^[a-z0-9-]+$/;
|
||||||
|
|
||||||
function Widgets() {
|
const Widgets = React.memo(() => {
|
||||||
const settingsConfig = jotai.useAtomValue(atoms.settingsConfigAtom);
|
const settingsConfig = jotai.useAtomValue(atoms.settingsConfigAtom);
|
||||||
const newWidgetModalVisible = React.useState(false);
|
const newWidgetModalVisible = React.useState(false);
|
||||||
async function clickTerminal() {
|
async function clickTerminal() {
|
||||||
@ -92,27 +92,27 @@ function Widgets() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
function WorkspaceElem() {
|
const WorkspaceElem = React.memo(() => {
|
||||||
const windowData = jotai.useAtomValue(atoms.waveWindow);
|
const windowData = jotai.useAtomValue(atoms.waveWindow);
|
||||||
const activeTabId = windowData?.activetabid;
|
const activeTabId = windowData?.activetabid;
|
||||||
const ws = jotai.useAtomValue(atoms.workspace);
|
const ws = jotai.useAtomValue(atoms.workspace);
|
||||||
return (
|
return (
|
||||||
<div className="workspace">
|
<div className="workspace">
|
||||||
<TabBar workspace={ws} />
|
<TabBar key={ws.oid} workspace={ws} />
|
||||||
<div className="workspace-tabcontent">
|
<div className="workspace-tabcontent">
|
||||||
{activeTabId == "" ? (
|
{activeTabId == "" ? (
|
||||||
<CenteredDiv>No Active Tab</CenteredDiv>
|
<CenteredDiv>No Active Tab</CenteredDiv>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<TabContent key={windowData.workspaceid} tabId={activeTabId} />
|
<TabContent key={activeTabId} tabId={activeTabId} />
|
||||||
<Widgets />
|
<Widgets />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
export { WorkspaceElem as Workspace };
|
export { WorkspaceElem as Workspace };
|
||||||
|
@ -37,11 +37,11 @@ import {
|
|||||||
import "./tilelayout.less";
|
import "./tilelayout.less";
|
||||||
import { Dimensions, FlexDirection, setTransform as createTransform, determineDropDirection } from "./utils";
|
import { Dimensions, FlexDirection, setTransform as createTransform, determineDropDirection } from "./utils";
|
||||||
|
|
||||||
export interface TileLayoutProps<T> {
|
|
||||||
/**
|
/**
|
||||||
* The atom containing the layout tree state.
|
* contains callbacks and information about the contents (or styling) of of the TileLayout
|
||||||
|
* nothing in here is specific to the TileLayout itself
|
||||||
*/
|
*/
|
||||||
layoutTreeStateAtom: WritableLayoutTreeStateAtom<T>;
|
export interface TileLayoutContents<T> {
|
||||||
/**
|
/**
|
||||||
* A callback that accepts the data from the leaf node and displays the leaf contents to the user.
|
* A callback that accepts the data from the leaf node and displays the leaf contents to the user.
|
||||||
*/
|
*/
|
||||||
@ -64,6 +64,18 @@ export interface TileLayoutProps<T> {
|
|||||||
* tabId this TileLayout is associated with
|
* tabId this TileLayout is associated with
|
||||||
*/
|
*/
|
||||||
tabId: string;
|
tabId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TileLayoutProps<T> {
|
||||||
|
/**
|
||||||
|
* The atom containing the layout tree state.
|
||||||
|
*/
|
||||||
|
layoutTreeStateAtom: WritableLayoutTreeStateAtom<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* callbacks and information about the contents (or styling) of the TileLayout or contents
|
||||||
|
*/
|
||||||
|
contents: TileLayoutContents<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A callback for getting the cursor point in reference to the current window. This removes Electron as a runtime dependency, allowing for better integration with Storybook.
|
* A callback for getting the cursor point in reference to the current window. This removes Electron as a runtime dependency, allowing for better integration with Storybook.
|
||||||
@ -75,15 +87,7 @@ export interface TileLayoutProps<T> {
|
|||||||
const DragPreviewWidth = 300;
|
const DragPreviewWidth = 300;
|
||||||
const DragPreviewHeight = 300;
|
const DragPreviewHeight = 300;
|
||||||
|
|
||||||
export const TileLayout = <T,>({
|
export const TileLayout = React.memo(<T,>({ layoutTreeStateAtom, contents, getCursorPoint }: TileLayoutProps<T>) => {
|
||||||
layoutTreeStateAtom,
|
|
||||||
tabId,
|
|
||||||
className,
|
|
||||||
renderContent,
|
|
||||||
renderPreview,
|
|
||||||
onNodeDelete,
|
|
||||||
getCursorPoint,
|
|
||||||
}: TileLayoutProps<T>) => {
|
|
||||||
const overlayContainerRef = useRef<HTMLDivElement>(null);
|
const overlayContainerRef = useRef<HTMLDivElement>(null);
|
||||||
const displayContainerRef = useRef<HTMLDivElement>(null);
|
const displayContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@ -126,7 +130,7 @@ export const TileLayout = <T,>({
|
|||||||
const [layoutLeafTransforms, setLayoutLeafTransformsRaw] = useState<Record<string, CSSProperties>>({});
|
const [layoutLeafTransforms, setLayoutLeafTransformsRaw] = useState<Record<string, CSSProperties>>({});
|
||||||
|
|
||||||
const setLayoutLeafTransforms = (transforms: Record<string, CSSProperties>) => {
|
const setLayoutLeafTransforms = (transforms: Record<string, CSSProperties>) => {
|
||||||
globalLayoutTransformsMap.set(tabId, transforms);
|
globalLayoutTransformsMap.set(contents.tabId, transforms);
|
||||||
setLayoutLeafTransformsRaw(transforms);
|
setLayoutLeafTransformsRaw(transforms);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -247,30 +251,23 @@ export const TileLayout = <T,>({
|
|||||||
// console.log("calling dispatch", deleteAction);
|
// console.log("calling dispatch", deleteAction);
|
||||||
dispatch(deleteAction);
|
dispatch(deleteAction);
|
||||||
// console.log("calling onNodeDelete", node);
|
// console.log("calling onNodeDelete", node);
|
||||||
await onNodeDelete?.(node.data);
|
await contents.onNodeDelete?.(node.data);
|
||||||
// console.log("node deleted");
|
// console.log("node deleted");
|
||||||
},
|
},
|
||||||
[onNodeDelete, dispatch]
|
[contents.onNodeDelete, dispatch]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<div className={clsx("tile-layout", className, { animate })} onPointerOut={onPointerLeave}>
|
<div className={clsx("tile-layout", contents.className, { animate })} onPointerOut={onPointerLeave}>
|
||||||
<div key="display" ref={displayContainerRef} className="display-container">
|
<div key="display" ref={displayContainerRef} className="display-container">
|
||||||
{layoutLeafTransforms &&
|
<DisplayNodesWrapper
|
||||||
layoutTreeState.leafs.map((leaf) => {
|
contents={contents}
|
||||||
return (
|
|
||||||
<DisplayNode
|
|
||||||
key={leaf.id}
|
|
||||||
layoutNode={leaf}
|
|
||||||
renderContent={renderContent}
|
|
||||||
renderPreview={renderPreview}
|
|
||||||
transform={layoutLeafTransforms[leaf.id]}
|
|
||||||
onLeafClose={onLeafClose}
|
|
||||||
ready={animate}
|
ready={animate}
|
||||||
|
onLeafClose={onLeafClose}
|
||||||
|
layoutTreeState={layoutTreeState}
|
||||||
|
layoutLeafTransforms={layoutLeafTransforms}
|
||||||
/>
|
/>
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
<Placeholder
|
<Placeholder
|
||||||
key="placeholder"
|
key="placeholder"
|
||||||
@ -296,21 +293,63 @@ export const TileLayout = <T,>({
|
|||||||
</div>
|
</div>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
|
interface DisplayNodesWrapperProps<T> {
|
||||||
|
/**
|
||||||
|
* The layout tree state.
|
||||||
|
*/
|
||||||
|
layoutTreeState: LayoutTreeState<T>;
|
||||||
|
/**
|
||||||
|
* contains callbacks and information about the contents (or styling) of of the TileLayout
|
||||||
|
*/
|
||||||
|
contents: TileLayoutContents<T>;
|
||||||
|
/**
|
||||||
|
* A callback that is called when a leaf node gets closed.
|
||||||
|
* @param node The node that is closed.
|
||||||
|
*/
|
||||||
|
onLeafClose: (node: LayoutNode<T>) => void;
|
||||||
|
/**
|
||||||
|
* A series of CSS properties used to display a leaf node with the correct dimensions and position, as determined from its corresponding OverlayNode.
|
||||||
|
*/
|
||||||
|
layoutLeafTransforms: Record<string, CSSProperties>;
|
||||||
|
/**
|
||||||
|
* Determines whether the leaf nodes are ready to be displayed to the user.
|
||||||
|
*/
|
||||||
|
ready: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DisplayNodesWrapper = React.memo(
|
||||||
|
<T,>({ layoutTreeState, contents, onLeafClose, layoutLeafTransforms, ready }: DisplayNodesWrapperProps<T>) => {
|
||||||
|
if (!layoutLeafTransforms) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return layoutTreeState.leafs.map((leaf) => {
|
||||||
|
return (
|
||||||
|
<DisplayNode
|
||||||
|
key={leaf.id}
|
||||||
|
layoutNode={leaf}
|
||||||
|
contents={contents}
|
||||||
|
transform={layoutLeafTransforms[leaf.id]}
|
||||||
|
onLeafClose={onLeafClose}
|
||||||
|
ready={ready}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
interface DisplayNodeProps<T> {
|
interface DisplayNodeProps<T> {
|
||||||
/**
|
/**
|
||||||
* The leaf node object, containing the data needed to display the leaf contents to the user.
|
* The leaf node object, containing the data needed to display the leaf contents to the user.
|
||||||
*/
|
*/
|
||||||
layoutNode: LayoutNode<T>;
|
layoutNode: LayoutNode<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A callback that accepts the data from the leaf node and displays the leaf contents to the user.
|
* contains callbacks and information about the contents (or styling) of of the TileLayout
|
||||||
*/
|
*/
|
||||||
renderContent: ContentRenderer<T>;
|
contents: TileLayoutContents<T>;
|
||||||
/**
|
|
||||||
* A callback that accepts the data from the leaf node and returns a preview that can be shown when the user drags a node.
|
|
||||||
*/
|
|
||||||
renderPreview?: PreviewRenderer<T>;
|
|
||||||
/**
|
/**
|
||||||
* A callback that is called when a leaf node gets closed.
|
* A callback that is called when a leaf node gets closed.
|
||||||
* @param node The node that is closed.
|
* @param node The node that is closed.
|
||||||
@ -331,14 +370,7 @@ const dragItemType = "TILE_ITEM";
|
|||||||
/**
|
/**
|
||||||
* The draggable and displayable portion of a leaf node in a layout tree.
|
* The draggable and displayable portion of a leaf node in a layout tree.
|
||||||
*/
|
*/
|
||||||
const DisplayNode = <T,>({
|
const DisplayNode = React.memo(<T,>({ layoutNode, contents, transform, onLeafClose, ready }: DisplayNodeProps<T>) => {
|
||||||
layoutNode,
|
|
||||||
renderContent,
|
|
||||||
renderPreview,
|
|
||||||
transform,
|
|
||||||
onLeafClose,
|
|
||||||
ready,
|
|
||||||
}: DisplayNodeProps<T>) => {
|
|
||||||
const tileNodeRef = useRef<HTMLDivElement>(null);
|
const tileNodeRef = useRef<HTMLDivElement>(null);
|
||||||
const dragHandleRef = useRef<HTMLDivElement>(null);
|
const dragHandleRef = useRef<HTMLDivElement>(null);
|
||||||
const previewRef = useRef<HTMLDivElement>(null);
|
const previewRef = useRef<HTMLDivElement>(null);
|
||||||
@ -370,11 +402,11 @@ const DisplayNode = <T,>({
|
|||||||
transform: `scale(${1 / devicePixelRatio})`,
|
transform: `scale(${1 / devicePixelRatio})`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{renderPreview?.(layoutNode.data)}
|
{contents.renderPreview?.(layoutNode.data)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}, [renderPreview, devicePixelRatio]);
|
}, [contents.renderPreview, devicePixelRatio]);
|
||||||
|
|
||||||
const [previewImage, setPreviewImage] = useState<HTMLImageElement>(null);
|
const [previewImage, setPreviewImage] = useState<HTMLImageElement>(null);
|
||||||
const [previewImageGeneration, setPreviewImageGeneration] = useState(0);
|
const [previewImageGeneration, setPreviewImageGeneration] = useState(0);
|
||||||
@ -414,7 +446,7 @@ const DisplayNode = <T,>({
|
|||||||
return (
|
return (
|
||||||
layoutNode.data && (
|
layoutNode.data && (
|
||||||
<div key="leaf" className="tile-leaf">
|
<div key="leaf" className="tile-leaf">
|
||||||
{renderContent(layoutNode.data, ready, onClose, dragHandleRef)}
|
{contents.renderContent(layoutNode.data, ready, onClose, dragHandleRef)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -436,7 +468,7 @@ const DisplayNode = <T,>({
|
|||||||
{previewElement}
|
{previewElement}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
interface OverlayNodeProps<T> {
|
interface OverlayNodeProps<T> {
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user