diff --git a/package.json b/package.json index 270c86ddba..2d2506e1df 100644 --- a/package.json +++ b/package.json @@ -91,6 +91,7 @@ "qs": "^6.9.6", "re-resizable": "^6.9.0", "react": "^16.14.0", + "react-beautiful-dnd": "^13.1.0", "react-dom": "^16.14.0", "react-focus-lock": "^2.5.0", "react-transition-group": "^4.4.1", @@ -135,6 +136,7 @@ "@types/parse5": "^6.0.0", "@types/qrcode": "^1.3.5", "@types/react": "^16.9", + "@types/react-beautiful-dnd": "^13.0.0", "@types/react-dom": "^16.9.10", "@types/react-transition-group": "^4.4.0", "@types/sanitize-html": "^2.3.1", diff --git a/res/css/structures/_SpacePanel.scss b/res/css/structures/_SpacePanel.scss index c433ccf275..e64057d16c 100644 --- a/res/css/structures/_SpacePanel.scss +++ b/res/css/structures/_SpacePanel.scss @@ -31,7 +31,6 @@ $activeBorderColor: $secondary-fg-color; // Create another flexbox so the Panel fills the container display: flex; flex-direction: column; - overflow-y: auto; .mx_SpacePanel_spaceTreeWrapper { flex: 1; @@ -69,6 +68,12 @@ $activeBorderColor: $secondary-fg-color; cursor: pointer; } + .mx_SpaceItem_dragging { + .mx_SpaceButton_toggleCollapse { + visibility: hidden; + } + } + .mx_SpaceTreeLevel { display: flex; flex-direction: column; diff --git a/src/components/views/spaces/SpacePanel.tsx b/src/components/views/spaces/SpacePanel.tsx index eb63b21f0e..27f097e9d4 100644 --- a/src/components/views/spaces/SpacePanel.tsx +++ b/src/components/views/spaces/SpacePanel.tsx @@ -15,8 +15,9 @@ limitations under the License. */ import React, { 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 { Room } from "matrix-js-sdk/src/models/room"; import {_t} from "../../../languageHandler"; import RoomAvatar from "../avatars/RoomAvatar"; @@ -204,58 +205,89 @@ const SpacePanel = () => { }; const activeSpaces = activeSpace ? [activeSpace] : []; - const expandCollapseButtonTitle = isPanelCollapsed ? _t("Expand space panel") : _t("Collapse space panel"); - // TODO drag and drop for re-arranging order - return - {({onKeyDownHandler}) => ( - - )} - + { contextMenu } + + )} + + + ); }; export default SpacePanel; diff --git a/src/components/views/spaces/SpaceTreeLevel.tsx b/src/components/views/spaces/SpaceTreeLevel.tsx index f34baf256b..7ac863b239 100644 --- a/src/components/views/spaces/SpaceTreeLevel.tsx +++ b/src/components/views/spaces/SpaceTreeLevel.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from "react"; +import React, {InputHTMLAttributes, LegacyRef} from "react"; import classNames from "classnames"; import {Room} from "matrix-js-sdk/src/models/room"; @@ -49,13 +49,14 @@ import {EventType} from "matrix-js-sdk/src/@types/event"; import {StaticNotificationState} from "../../../stores/notifications/StaticNotificationState"; import {NotificationColor} from "../../../stores/notifications/NotificationColor"; -interface IItemProps { +interface IItemProps extends InputHTMLAttributes { space?: Room; activeSpaces: Room[]; isNested?: boolean; isPanelCollapsed?: boolean; onExpand?: Function; parents?: Set; + innerRef?: LegacyRef; } interface IItemState { @@ -300,18 +301,18 @@ export class SpaceItem extends React.PureComponent { } render() { - const {space, activeSpaces, isNested} = this.props; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { space, activeSpaces, isNested, isPanelCollapsed, onExpand, parents, innerRef, + ...otherProps } = this.props; - const forceCollapsed = this.props.isPanelCollapsed; - const isNarrow = this.props.isPanelCollapsed; - const collapsed = this.state.collapsed || forceCollapsed; + const collapsed = this.state.collapsed || isPanelCollapsed; const childSpaces = SpaceStore.instance.getChildSpaces(space.roomId) - .filter(s => !this.props.parents?.has(s.roomId)); + .filter(s => !parents?.has(s.roomId)); const isActive = activeSpaces.includes(space); - const itemClasses = classNames({ + const itemClasses = classNames(this.props.className, { "mx_SpaceItem": true, - "mx_SpaceItem_narrow": isNarrow, + "mx_SpaceItem_narrow": isPanelCollapsed, "collapsed": collapsed, "hasSubSpaces": childSpaces && childSpaces.length, }); @@ -320,7 +321,7 @@ export class SpaceItem extends React.PureComponent { const classes = classNames("mx_SpaceButton", { mx_SpaceButton_active: isActive, mx_SpaceButton_hasMenuOpen: !!this.state.contextMenuPosition, - mx_SpaceButton_narrow: isNarrow, + mx_SpaceButton_narrow: isPanelCollapsed, mx_SpaceButton_invite: isInvite, }); const notificationState = isInvite @@ -333,7 +334,7 @@ export class SpaceItem extends React.PureComponent { spaces={childSpaces} activeSpaces={activeSpaces} isNested={true} - parents={new Set(this.props.parents).add(this.props.space.roomId)} + parents={new Set(parents).add(space.roomId)} />; } @@ -353,7 +354,7 @@ export class SpaceItem extends React.PureComponent { /> : null; let button; - if (isNarrow) { + if (isPanelCollapsed) { button = ( { } return ( -
  • +
  • { button } { childItems }
  • diff --git a/src/stores/SpaceStore.tsx b/src/stores/SpaceStore.tsx index 1333fc5d37..9ef961ce2d 100644 --- a/src/stores/SpaceStore.tsx +++ b/src/stores/SpaceStore.tsx @@ -63,12 +63,6 @@ const partitionSpacesAndRooms = (arr: Room[]): [Room[], Room[]] => { // [spaces, const SpaceTagOrderingField = "org.matrix.mscXXXX.space"; -const getSpaceTagOrdering = (space: Room): number | undefined => { - return space?.getAccountData(EventType.Tag)?.getContent()?.tags?.[SpaceTagOrderingField]?.order; -}; - -const sortRootSpaces = (spaces: Room[]): Room[] => sortBy(spaces, [getSpaceTagOrdering, "roomId"]); - // For sorting space children using a validated `order`, `m.room.create`'s `origin_server_ts`, `room_id` export const getChildOrder = (order: string, creationTs: number, roomId: string): Array>> => { let validatedOrder: string = null; @@ -104,6 +98,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { private _activeSpace?: Room = null; private _suggestedRooms: ISuggestedRoom[] = []; private _invitedSpaces = new Set(); + private spaceOrderLocalEchoMap = new Map(); public get invitedSpaces(): Room[] { return Array.from(this._invitedSpaces); @@ -335,7 +330,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { // rootSpaces.push(space); // }); - this.rootSpaces = sortRootSpaces(rootSpaces); + this.rootSpaces = this.sortRootSpaces(rootSpaces); this.parentMap = backrefs; // if the currently selected space no longer exists, remove its selection @@ -347,7 +342,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { this.emit(UPDATE_TOP_LEVEL_SPACES, this.spacePanelSpaces); // build initial state of invited spaces as we would have missed the emitted events about the room at launch - this._invitedSpaces = new Set(sortRootSpaces(invitedSpaces)); + this._invitedSpaces = new Set(this.sortRootSpaces(invitedSpaces)); this.emit(UPDATE_INVITED_SPACES, this.invitedSpaces); }, 100, {trailing: true, leading: true}); @@ -484,17 +479,22 @@ export class SpaceStoreClass extends AsyncStoreWithClient { private onRoomAccountData = (ev: MatrixEvent, room: Room, lastEv?: MatrixEvent) => { if (!room.isSpaceRoom() || ev.getType() !== EventType.Tag) return; + this.spaceOrderLocalEchoMap.delete(room.roomId); // clear any local echo const order = ev.getContent()?.tags?.[SpaceTagOrderingField]?.order; const lastOrder = lastEv?.getContent()?.tags?.[SpaceTagOrderingField]?.order; if (order !== lastOrder) { - const rootSpaces = sortRootSpaces(this.rootSpaces); - if (arrayHasOrderChange(this.rootSpaces, rootSpaces)) { - this.rootSpaces = rootSpaces; - this.emit(UPDATE_TOP_LEVEL_SPACES, this.spacePanelSpaces); - } + this.notifyIfOrderChanged(); } }; + private notifyIfOrderChanged(): void { + const rootSpaces = this.sortRootSpaces(this.rootSpaces); + if (arrayHasOrderChange(this.rootSpaces, rootSpaces)) { + this.rootSpaces = rootSpaces; + this.emit(UPDATE_TOP_LEVEL_SPACES, this.spacePanelSpaces); + } + } + private onRoomState = (ev: MatrixEvent) => { const room = this.matrixClient.getRoom(ev.getRoomId()); if (!room) return; @@ -624,6 +624,51 @@ export class SpaceStoreClass extends AsyncStoreWithClient { } childSpaces.forEach(s => this.traverseSpace(s.roomId, fn, includeRooms, newPath)); } + + private getSpaceTagOrdering = (space: Room): number | undefined => { + if (this.spaceOrderLocalEchoMap.has(space.roomId)) return this.spaceOrderLocalEchoMap.get(space.roomId); + return space.tags?.[SpaceTagOrderingField]?.order; + }; + + private sortRootSpaces(spaces: Room[]): Room[] { + return sortBy(spaces, [this.getSpaceTagOrdering, "roomId"]); + } + + public moveRootSpace(fromIndex: number, toIndex: number): void { + if ( + fromIndex < 0 || toIndex < 0 || + fromIndex > this.rootSpaces.length || toIndex > this.rootSpaces.length || + fromIndex === toIndex + ) { + return; + } + const space = this.rootSpaces[fromIndex]; + const orders = this.rootSpaces.map(this.getSpaceTagOrdering); + + let prevOrder = orders[toIndex - 1]; + let nextOrder = orders[toIndex]; // accounts for downwards displacement of existing inhabitant of this index + + if (prevOrder === undefined && nextOrder === undefined) { + // TODO WHAT A PAIN + } + + prevOrder = prevOrder || 0.0; + nextOrder = nextOrder || 1.0; + + if (prevOrder !== nextOrder) { + const order = prevOrder + ((nextOrder - prevOrder) / 2); + this.spaceOrderLocalEchoMap.set(space.roomId, order); + this.matrixClient.setRoomAccountData(space.roomId, EventType.Tag, { + tags: { + ...space.tags, + [SpaceTagOrderingField]: { order }, + }, + }); + this.notifyIfOrderChanged(); + } else { + // TODO REBUILD + } + } } export default class SpaceStore { diff --git a/yarn.lock b/yarn.lock index 2c84237730..7e24c220e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1024,6 +1024,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.12.1", "@babel/runtime@^7.9.2": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6" + integrity sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.10.4", "@babel/template@^7.12.7", "@babel/template@^7.3.3": version "7.12.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.7.tgz#c817233696018e39fbb6c491d2fb684e05ed43bc" @@ -1504,6 +1511,14 @@ dependencies: "@types/node" "*" +"@types/hoist-non-react-statics@^3.3.0": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" + integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" @@ -1620,6 +1635,13 @@ dependencies: "@types/node" "*" +"@types/react-beautiful-dnd@^13.0.0": + version "13.0.0" + resolved "https://registry.yarnpkg.com/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.0.0.tgz#e60d3d965312fcf1516894af92dc3e9249587db4" + integrity sha512-by80tJ8aTTDXT256Gl+RfLRtFjYbUWOnZuEigJgNsJrSEGxvFe5eY6k3g4VIvf0M/6+xoLgfYWoWonlOo6Wqdg== + dependencies: + "@types/react" "*" + "@types/react-dom@^16.9.10": version "16.9.10" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.10.tgz#4485b0bec3d41f856181b717f45fd7831101156f" @@ -1627,6 +1649,16 @@ dependencies: "@types/react" "^16" +"@types/react-redux@^7.1.16": + version "7.1.16" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.16.tgz#0fbd04c2500c12105494c83d4a3e45c084e3cb21" + integrity sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw== + dependencies: + "@types/hoist-non-react-statics" "^3.3.0" + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + redux "^4.0.0" + "@types/react-transition-group@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.0.tgz#882839db465df1320e4753e6e9f70ca7e9b4d46d" @@ -2696,6 +2728,13 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" +css-box-model@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1" + integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw== + dependencies: + tiny-invariant "^1.0.6" + css-select@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.2.tgz#8b52b6714ed3a80d8221ec971c543f3b12653286" @@ -4202,6 +4241,13 @@ highlight.js@^10.5.0: resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.5.0.tgz#3f09fede6a865757378f2d9ebdcbc15ba268f98f" integrity sha512-xTmvd9HiIHR6L53TMC7TKolEj65zG1XU+Onr8oi86mYa+nLcIbxTTWkpW7CsEwv/vK7u1zb8alZIMLDqqN6KTw== +hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + hosted-git-info@^2.1.4: version "2.8.9" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" @@ -5717,6 +5763,11 @@ mdurl@~1.0.1: resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= +memoize-one@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" + integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== + meow@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/meow/-/meow-9.0.0.tgz#cd9510bc5cac9dee7d03c73ee1f9ad959f4ea364" @@ -6632,6 +6683,11 @@ quick-lru@^4.0.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== +raf-schd@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a" + integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ== + raf@^3.4.1: version "3.4.1" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" @@ -6659,6 +6715,19 @@ re-resizable@^6.9.0: dependencies: fast-memoize "^2.5.1" +react-beautiful-dnd@^13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-13.1.0.tgz#ec97c81093593526454b0de69852ae433783844d" + integrity sha512-aGvblPZTJowOWUNiwd6tNfEpgkX5OxmpqxHKNW/4VmvZTNTbeiq7bA3bn5T+QSF2uibXB0D1DmJsb1aC/+3cUA== + dependencies: + "@babel/runtime" "^7.9.2" + css-box-model "^1.2.0" + memoize-one "^5.1.1" + raf-schd "^4.0.2" + react-redux "^7.2.0" + redux "^4.0.4" + use-memo-one "^1.1.1" + react-clientside-effect@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.3.tgz#95c95f520addfb71743608b990bfe01eb002012b" @@ -6688,7 +6757,7 @@ react-focus-lock@^2.5.0: use-callback-ref "^1.2.1" use-sidecar "^1.0.1" -react-is@^16.13.1, react-is@^16.8.1, react-is@^16.8.6: +react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.6: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -6698,6 +6767,18 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== +react-redux@^7.2.0: + version "7.2.4" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.4.tgz#1ebb474032b72d806de2e0519cd07761e222e225" + integrity sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA== + dependencies: + "@babel/runtime" "^7.12.1" + "@types/react-redux" "^7.1.16" + hoist-non-react-statics "^3.3.2" + loose-envify "^1.4.0" + prop-types "^15.7.2" + react-is "^16.13.1" + react-test-renderer@^16.0.0-0, react-test-renderer@^16.14.0: version "16.14.0" resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.14.0.tgz#e98360087348e260c56d4fe2315e970480c228ae" @@ -6818,6 +6899,13 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +redux@^4.0.0, redux@^4.0.4: + version "4.1.0" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.0.tgz#eb049679f2f523c379f1aff345c8612f294c88d4" + integrity sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g== + dependencies: + "@babel/runtime" "^7.9.2" + reflect.ownkeys@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz#749aceec7f3fdf8b63f927a04809e90c5c0b3460" @@ -7765,6 +7853,11 @@ through@^2.3.6: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= +tiny-invariant@^1.0.6: + version "1.1.0" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" + integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== + tmatch@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/tmatch/-/tmatch-2.0.1.tgz#0c56246f33f30da1b8d3d72895abaf16660f38cf" @@ -8070,6 +8163,11 @@ use-callback-ref@^1.2.1: resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.2.5.tgz#6115ed242cfbaed5915499c0a9842ca2912f38a5" integrity sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg== +use-memo-one@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.2.tgz#0c8203a329f76e040047a35a1197defe342fab20" + integrity sha512-u2qFKtxLsia/r8qG0ZKkbytbztzRb317XCkT7yP8wxL0tZ/CzK2G+WWie5vWvpyeP7+YoPIwbJoIHJ4Ba4k0oQ== + use-sidecar@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.0.4.tgz#38398c3723727f9f924bed2343dfa3db6aaaee46"