Break down the SpacePanel component
This commit is contained in:
parent
bceee7978e
commit
d4e376201f
1 changed files with 76 additions and 58 deletions
|
@ -14,18 +14,18 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { Dispatch, ReactNode, SetStateAction, useEffect, useState } from "react";
|
||||||
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
|
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
|
||||||
import {_t} from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import RoomAvatar from "../avatars/RoomAvatar";
|
import RoomAvatar from "../avatars/RoomAvatar";
|
||||||
import {useContextMenu} from "../../structures/ContextMenu";
|
import { useContextMenu } from "../../structures/ContextMenu";
|
||||||
import SpaceCreateMenu from "./SpaceCreateMenu";
|
import SpaceCreateMenu from "./SpaceCreateMenu";
|
||||||
import {SpaceItem} from "./SpaceTreeLevel";
|
import { SpaceItem } from "./SpaceTreeLevel";
|
||||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||||
import {useEventEmitter} from "../../../hooks/useEventEmitter";
|
import { useEventEmitter } from "../../../hooks/useEventEmitter";
|
||||||
import SpaceStore, {
|
import SpaceStore, {
|
||||||
UPDATE_INVITED_SPACES,
|
UPDATE_INVITED_SPACES,
|
||||||
UPDATE_SELECTED_SPACE,
|
UPDATE_SELECTED_SPACE,
|
||||||
|
@ -38,9 +38,9 @@ import {
|
||||||
RovingAccessibleTooltipButton,
|
RovingAccessibleTooltipButton,
|
||||||
RovingTabIndexProvider,
|
RovingTabIndexProvider,
|
||||||
} from "../../../accessibility/RovingTabIndex";
|
} from "../../../accessibility/RovingTabIndex";
|
||||||
import {Key} from "../../../Keyboard";
|
import { Key } from "../../../Keyboard";
|
||||||
import {RoomNotificationStateStore} from "../../../stores/notifications/RoomNotificationStateStore";
|
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
|
||||||
import {NotificationState} from "../../../stores/notifications/NotificationState";
|
import { NotificationState } from "../../../stores/notifications/NotificationState";
|
||||||
|
|
||||||
interface IButtonProps {
|
interface IButtonProps {
|
||||||
space?: Room;
|
space?: Room;
|
||||||
|
@ -121,11 +121,62 @@ const useSpaces = (): [Room[], Room[], Room | null] => {
|
||||||
return [invites, spaces, activeSpace];
|
return [invites, spaces, activeSpace];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface IInnerSpacePanelProps {
|
||||||
|
children?: ReactNode;
|
||||||
|
isPanelCollapsed: boolean;
|
||||||
|
setPanelCollapsed: Dispatch<SetStateAction<boolean>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optimisation based on https://github.com/atlassian/react-beautiful-dnd/blob/master/docs/api/droppable.md#recommended-droppable--performance-optimisation
|
||||||
|
const InnerSpacePanel = React.memo<IInnerSpacePanelProps>(({ children, isPanelCollapsed, setPanelCollapsed }) => {
|
||||||
|
const [invites, spaces, activeSpace] = useSpaces();
|
||||||
|
const activeSpaces = activeSpace ? [activeSpace] : [];
|
||||||
|
|
||||||
|
return <div className="mx_SpaceTreeLevel">
|
||||||
|
<SpaceButton
|
||||||
|
className="mx_SpaceButton_home"
|
||||||
|
onClick={() => SpaceStore.instance.setActiveSpace(null)}
|
||||||
|
selected={!activeSpace}
|
||||||
|
tooltip={_t("All rooms")}
|
||||||
|
notificationState={RoomNotificationStateStore.instance.globalState}
|
||||||
|
isNarrow={isPanelCollapsed}
|
||||||
|
/>
|
||||||
|
{ invites.map(s => (
|
||||||
|
<SpaceItem
|
||||||
|
key={s.roomId}
|
||||||
|
space={s}
|
||||||
|
activeSpaces={activeSpaces}
|
||||||
|
isPanelCollapsed={isPanelCollapsed}
|
||||||
|
onExpand={() => setPanelCollapsed(false)}
|
||||||
|
/>
|
||||||
|
)) }
|
||||||
|
{ spaces.map((s, i) => (
|
||||||
|
<Draggable key={s.roomId} draggableId={s.roomId} index={i}>
|
||||||
|
{(provided, snapshot) => (
|
||||||
|
<SpaceItem
|
||||||
|
{...provided.draggableProps}
|
||||||
|
{...provided.dragHandleProps}
|
||||||
|
key={s.roomId}
|
||||||
|
innerRef={provided.innerRef}
|
||||||
|
className={snapshot.isDragging
|
||||||
|
? "mx_SpaceItem_dragging"
|
||||||
|
: undefined}
|
||||||
|
space={s}
|
||||||
|
activeSpaces={activeSpaces}
|
||||||
|
isPanelCollapsed={isPanelCollapsed}
|
||||||
|
onExpand={() => setPanelCollapsed(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Draggable>
|
||||||
|
)) }
|
||||||
|
{ children }
|
||||||
|
</div>;
|
||||||
|
});
|
||||||
|
|
||||||
const SpacePanel = () => {
|
const SpacePanel = () => {
|
||||||
// We don't need the handle as we position the menu in a constant location
|
// We don't need the handle as we position the menu in a constant location
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<void>();
|
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<void>();
|
||||||
const [invites, spaces, activeSpace] = useSpaces();
|
|
||||||
const [isPanelCollapsed, setPanelCollapsed] = useState(true);
|
const [isPanelCollapsed, setPanelCollapsed] = useState(true);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -134,10 +185,6 @@ const SpacePanel = () => {
|
||||||
}
|
}
|
||||||
}, [isPanelCollapsed]); // eslint-disable-line react-hooks/exhaustive-deps
|
}, [isPanelCollapsed]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
|
|
||||||
const newClasses = classNames("mx_SpaceButton_new", {
|
|
||||||
mx_SpaceButton_newCancel: menuDisplayed,
|
|
||||||
});
|
|
||||||
|
|
||||||
let contextMenu = null;
|
let contextMenu = null;
|
||||||
if (menuDisplayed) {
|
if (menuDisplayed) {
|
||||||
contextMenu = <SpaceCreateMenu onFinished={closeMenu} />;
|
contextMenu = <SpaceCreateMenu onFinished={closeMenu} />;
|
||||||
|
@ -204,7 +251,11 @@ const SpacePanel = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const activeSpaces = activeSpace ? [activeSpace] : [];
|
const onNewClick = menuDisplayed ? closeMenu : () => {
|
||||||
|
if (!isPanelCollapsed) setPanelCollapsed(true);
|
||||||
|
openMenu();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DragDropContext onDragEnd={result => {
|
<DragDropContext onDragEnd={result => {
|
||||||
if (!result.destination) return; // dropped outside the list
|
if (!result.destination) return; // dropped outside the list
|
||||||
|
@ -226,59 +277,26 @@ const SpacePanel = () => {
|
||||||
pointerEvents: "none",
|
pointerEvents: "none",
|
||||||
} : undefined}
|
} : undefined}
|
||||||
>
|
>
|
||||||
<div className="mx_SpaceTreeLevel">
|
<InnerSpacePanel
|
||||||
<SpaceButton
|
|
||||||
className="mx_SpaceButton_home"
|
|
||||||
onClick={() => SpaceStore.instance.setActiveSpace(null)}
|
|
||||||
selected={!activeSpace}
|
|
||||||
tooltip={_t("All rooms")}
|
|
||||||
notificationState={RoomNotificationStateStore.instance.globalState}
|
|
||||||
isNarrow={isPanelCollapsed}
|
|
||||||
/>
|
|
||||||
{ invites.map(s => (
|
|
||||||
<SpaceItem
|
|
||||||
key={s.roomId}
|
|
||||||
space={s}
|
|
||||||
activeSpaces={activeSpaces}
|
|
||||||
isPanelCollapsed={isPanelCollapsed}
|
isPanelCollapsed={isPanelCollapsed}
|
||||||
onExpand={() => setPanelCollapsed(false)}
|
setPanelCollapsed={setPanelCollapsed}
|
||||||
/>
|
>
|
||||||
)) }
|
|
||||||
{ spaces.map((s, i) => (
|
|
||||||
<Draggable key={s.roomId} draggableId={s.roomId} index={i}>
|
|
||||||
{(provided, snapshot) => (
|
|
||||||
<SpaceItem
|
|
||||||
{...provided.draggableProps}
|
|
||||||
{...provided.dragHandleProps}
|
|
||||||
key={s.roomId}
|
|
||||||
innerRef={provided.innerRef}
|
|
||||||
className={snapshot.isDragging
|
|
||||||
? "mx_SpaceItem_dragging"
|
|
||||||
: undefined}
|
|
||||||
space={s}
|
|
||||||
activeSpaces={activeSpaces}
|
|
||||||
isPanelCollapsed={isPanelCollapsed}
|
|
||||||
onExpand={() => setPanelCollapsed(false)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Draggable>
|
|
||||||
)) }
|
|
||||||
{ provided.placeholder }
|
{ provided.placeholder }
|
||||||
</div>
|
</InnerSpacePanel>
|
||||||
|
|
||||||
<SpaceButton
|
<SpaceButton
|
||||||
className={newClasses}
|
className={classNames("mx_SpaceButton_new", {
|
||||||
|
mx_SpaceButton_newCancel: menuDisplayed,
|
||||||
|
})}
|
||||||
tooltip={menuDisplayed ? _t("Cancel") : _t("Create a space")}
|
tooltip={menuDisplayed ? _t("Cancel") : _t("Create a space")}
|
||||||
onClick={menuDisplayed ? closeMenu : () => {
|
onClick={onNewClick}
|
||||||
if (!isPanelCollapsed) setPanelCollapsed(true);
|
|
||||||
openMenu();
|
|
||||||
}}
|
|
||||||
isNarrow={isPanelCollapsed}
|
isNarrow={isPanelCollapsed}
|
||||||
/>
|
/>
|
||||||
</AutoHideScrollbar>
|
</AutoHideScrollbar>
|
||||||
)}
|
)}
|
||||||
</Droppable>
|
</Droppable>
|
||||||
<AccessibleTooltipButton
|
<AccessibleTooltipButton
|
||||||
className={classNames("mx_SpacePanel_toggleCollapse", {expanded: !isPanelCollapsed})}
|
className={classNames("mx_SpacePanel_toggleCollapse", { expanded: !isPanelCollapsed })}
|
||||||
onClick={() => setPanelCollapsed(!isPanelCollapsed)}
|
onClick={() => setPanelCollapsed(!isPanelCollapsed)}
|
||||||
title={isPanelCollapsed ? _t("Expand space panel") : _t("Collapse space panel")}
|
title={isPanelCollapsed ? _t("Expand space panel") : _t("Collapse space panel")}
|
||||||
/>
|
/>
|
||||||
|
|
Loading…
Reference in a new issue