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.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import React, { Dispatch, ReactNode, SetStateAction, useEffect, useState } from "react";
|
||||
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
|
||||
import classNames from "classnames";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
|
||||
import {_t} from "../../../languageHandler";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import RoomAvatar from "../avatars/RoomAvatar";
|
||||
import {useContextMenu} from "../../structures/ContextMenu";
|
||||
import { useContextMenu } from "../../structures/ContextMenu";
|
||||
import SpaceCreateMenu from "./SpaceCreateMenu";
|
||||
import {SpaceItem} from "./SpaceTreeLevel";
|
||||
import { SpaceItem } from "./SpaceTreeLevel";
|
||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||
import {useEventEmitter} from "../../../hooks/useEventEmitter";
|
||||
import { useEventEmitter } from "../../../hooks/useEventEmitter";
|
||||
import SpaceStore, {
|
||||
UPDATE_INVITED_SPACES,
|
||||
UPDATE_SELECTED_SPACE,
|
||||
|
@ -38,9 +38,9 @@ import {
|
|||
RovingAccessibleTooltipButton,
|
||||
RovingTabIndexProvider,
|
||||
} from "../../../accessibility/RovingTabIndex";
|
||||
import {Key} from "../../../Keyboard";
|
||||
import {RoomNotificationStateStore} from "../../../stores/notifications/RoomNotificationStateStore";
|
||||
import {NotificationState} from "../../../stores/notifications/NotificationState";
|
||||
import { Key } from "../../../Keyboard";
|
||||
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
|
||||
import { NotificationState } from "../../../stores/notifications/NotificationState";
|
||||
|
||||
interface IButtonProps {
|
||||
space?: Room;
|
||||
|
@ -121,11 +121,62 @@ const useSpaces = (): [Room[], Room[], Room | null] => {
|
|||
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 = () => {
|
||||
// We don't need the handle as we position the menu in a constant location
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<void>();
|
||||
const [invites, spaces, activeSpace] = useSpaces();
|
||||
const [isPanelCollapsed, setPanelCollapsed] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -134,10 +185,6 @@ const SpacePanel = () => {
|
|||
}
|
||||
}, [isPanelCollapsed]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const newClasses = classNames("mx_SpaceButton_new", {
|
||||
mx_SpaceButton_newCancel: menuDisplayed,
|
||||
});
|
||||
|
||||
let contextMenu = null;
|
||||
if (menuDisplayed) {
|
||||
contextMenu = <SpaceCreateMenu onFinished={closeMenu} />;
|
||||
|
@ -204,7 +251,11 @@ const SpacePanel = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const activeSpaces = activeSpace ? [activeSpace] : [];
|
||||
const onNewClick = menuDisplayed ? closeMenu : () => {
|
||||
if (!isPanelCollapsed) setPanelCollapsed(true);
|
||||
openMenu();
|
||||
};
|
||||
|
||||
return (
|
||||
<DragDropContext onDragEnd={result => {
|
||||
if (!result.destination) return; // dropped outside the list
|
||||
|
@ -226,59 +277,26 @@ const SpacePanel = () => {
|
|||
pointerEvents: "none",
|
||||
} : undefined}
|
||||
>
|
||||
<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>
|
||||
)) }
|
||||
<InnerSpacePanel
|
||||
isPanelCollapsed={isPanelCollapsed}
|
||||
setPanelCollapsed={setPanelCollapsed}
|
||||
>
|
||||
{ provided.placeholder }
|
||||
</div>
|
||||
</InnerSpacePanel>
|
||||
|
||||
<SpaceButton
|
||||
className={newClasses}
|
||||
className={classNames("mx_SpaceButton_new", {
|
||||
mx_SpaceButton_newCancel: menuDisplayed,
|
||||
})}
|
||||
tooltip={menuDisplayed ? _t("Cancel") : _t("Create a space")}
|
||||
onClick={menuDisplayed ? closeMenu : () => {
|
||||
if (!isPanelCollapsed) setPanelCollapsed(true);
|
||||
openMenu();
|
||||
}}
|
||||
onClick={onNewClick}
|
||||
isNarrow={isPanelCollapsed}
|
||||
/>
|
||||
</AutoHideScrollbar>
|
||||
)}
|
||||
</Droppable>
|
||||
<AccessibleTooltipButton
|
||||
className={classNames("mx_SpacePanel_toggleCollapse", {expanded: !isPanelCollapsed})}
|
||||
className={classNames("mx_SpacePanel_toggleCollapse", { expanded: !isPanelCollapsed })}
|
||||
onClick={() => setPanelCollapsed(!isPanelCollapsed)}
|
||||
title={isPanelCollapsed ? _t("Expand space panel") : _t("Collapse space panel")}
|
||||
/>
|
||||
|
|
Loading…
Reference in a new issue