refactored collection listing component [WIP]

This commit is contained in:
daniel31x13
2024-02-29 00:05:38 -05:00
parent f77ef58396
commit ac70c9e29c
4 changed files with 397 additions and 245 deletions
+340 -238
View File
@@ -1,257 +1,359 @@
import useAccountStore from "@/store/account";
import useCollectionStore from "@/store/collections";
import React, { Component, useCallback, useEffect, useState } from "react";
import Tree, {
mutateTree,
moveItemOnTree,
RenderItemParams,
TreeItem,
TreeData,
ItemId,
TreeSourcePosition,
TreeDestinationPosition,
} from "@atlaskit/tree";
import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
import Link from "next/link";
import { useRouter } from "next/router";
import React, { useEffect, useState } from "react";
import {
DragDropContext,
Draggable,
DraggableProvided,
} from "react-beautiful-dnd";
import { StrictModeDroppable as Droppable } from "./StrictModeDroppable";
import useCollectionStore from "@/store/collections";
type Props = {
links: boolean;
};
const collections = [
{
id: 262,
name: "dasd",
description: "",
color: "#0ea5e9",
parentId: null,
isPublic: false,
ownerId: 1,
createdAt: "2024-02-18T23:40:44.043Z",
updatedAt: "2024-02-19T19:16:14.873Z",
parent: null,
members: [
{
userId: 17,
collectionId: 262,
canCreate: true,
canUpdate: false,
canDelete: false,
createdAt: "2024-02-19T19:16:14.873Z",
updatedAt: "2024-02-19T19:16:14.873Z",
user: { username: "test", name: "ben", image: "" },
},
],
_count: { links: 0 },
},
{
id: 268,
name: "ab",
description: "",
color: "#0ea5e9",
parentId: 267,
isPublic: false,
ownerId: 17,
createdAt: "2024-02-19T21:06:52.545Z",
updatedAt: "2024-02-19T21:06:52.545Z",
parent: { id: 267, name: "a" },
members: [],
_count: { links: 0 },
},
{
id: 269,
name: "abc",
description: "",
color: "#0ea5e9",
parentId: 268,
isPublic: false,
ownerId: 17,
createdAt: "2024-02-19T21:07:08.565Z",
updatedAt: "2024-02-19T21:07:08.565Z",
parent: { id: 268, name: "ab" },
members: [],
_count: { links: 0 },
},
{
id: 267,
name: "a",
description: "",
color: "#0ea5e9",
parentId: null,
isPublic: false,
ownerId: 17,
createdAt: "2024-02-19T21:06:45.402Z",
updatedAt: "2024-02-26T16:59:20.312Z",
parent: null,
members: [],
_count: { links: 0 },
},
{
id: 80,
name: "abc",
description: "s",
color: "#0ea5e9",
parentId: 79,
isPublic: false,
ownerId: 1,
createdAt: "2024-02-05T07:00:46.881Z",
updatedAt: "2024-02-27T06:11:46.358Z",
parent: { id: 79, name: "ab" },
members: [
{
userId: 17,
collectionId: 80,
canCreate: false,
canUpdate: false,
canDelete: false,
createdAt: "2024-02-27T06:11:46.358Z",
updatedAt: "2024-02-27T06:11:46.358Z",
user: { username: "test", name: "ben", image: "" },
},
{
userId: 2,
collectionId: 80,
canCreate: false,
canUpdate: false,
canDelete: false,
createdAt: "2024-02-27T06:11:46.358Z",
updatedAt: "2024-02-27T06:11:46.358Z",
user: {
username: "sarah_connor",
name: "Sarah Smith",
image: "uploads/avatar/2.jpg",
},
},
],
_count: { links: 0 },
},
];
const CollectionListing = ({ links }: Props) => {
const { collections } = useCollectionStore();
const { account, updateAccount } = useAccountStore();
// Use local state to store the collection order so we don't have to wait for a response from the API to update the UI
const [localCollectionOrder, setLocalCollectionOrder] = useState<number[]>(
[]
);
const [active, setActive] = useState("");
const router = useRouter();
const DragDropWithNestingTree = () => {
const buildTreeFromCollections = (collections) => {
// Step 1: Map Collections to TreeItems
const items = collections.reduce((acc, collection) => {
acc[collection.id] = {
id: collection.id.toString(),
children: [],
hasChildren: false, // Initially assume no children, adjust in Step 2
isExpanded: false,
data: {
title: collection.name,
description: collection.description,
color: collection.color,
isPublic: collection.isPublic,
ownerId: collection.ownerId,
createdAt: collection.createdAt,
updatedAt: collection.updatedAt,
},
};
return acc;
}, {});
useEffect(() => {
setActive(router.asPath);
setLocalCollectionOrder(account.collectionOrder || []);
// if a collection wasn't in the collectionOrder, add it to the end
if (account.username) {
if (!account.collectionOrder || account.collectionOrder.length === 0)
updateAccount({
...account,
collectionOrder: collections
.filter((e) => e.parentId === null) // Filter out collections with non-null parentId
.map((e) => e.id as number), // Use "as number" to assert that e.id is a number
});
else {
const newCollectionOrder: number[] = [
...(account.collectionOrder || []),
];
collections?.forEach((collection) => {
if (
account.username &&
!newCollectionOrder.includes(collection.id as number) &&
(!collection.parentId || collection.ownerId !== account.id)
) {
newCollectionOrder.push(collection.id as number);
}
});
if (newCollectionOrder.length > account.collectionOrder.length) {
updateAccount({
...account,
collectionOrder: newCollectionOrder,
});
}
// Step 2: Build Hierarchy
collections.forEach((collection) => {
const parentId = collection.parentId;
if (parentId !== null && items[parentId]) {
items[parentId].children.push(collection.id.toString());
items[parentId].hasChildren = true;
}
}
}, [router, collections, account]);
});
return (
<DragDropContext
onDragEnd={(result) => {
if (!result.destination) {
return; // Dragged outside the droppable area, do nothing
}
const updatedCollectionOrder = [...account.collectionOrder];
const [movedCollectionId] = updatedCollectionOrder.splice(
result.source.index,
1
);
updatedCollectionOrder.splice(
result.destination.index,
0,
movedCollectionId
);
// Update local state with the new collection order
setLocalCollectionOrder(updatedCollectionOrder);
// Update account with the new collection order
updateAccount({
...account,
collectionOrder: updatedCollectionOrder,
});
}}
>
<Droppable droppableId="collections">
{(provided) => (
<div ref={provided.innerRef} {...provided.droppableProps}>
{localCollectionOrder?.map((collectionId, index) => {
const collection = collections.find((c) => c.id === collectionId);
if (collection) {
return (
<Draggable
key={collection.id}
draggableId={`collection-${collection.id}`}
index={index}
>
{(provided) => (
<CollectionItem
innerRef={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
key={index}
collection={collection}
active={active}
collections={collections}
/>
)}
</Draggable>
);
}
})}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
);
};
export default CollectionListing;
const CollectionItem = ({
collection,
active,
collections,
innerRef,
...props
}: {
collection: CollectionIncludingMembersAndLinkCount;
active: string;
collections: CollectionIncludingMembersAndLinkCount[];
innerRef?: DraggableProvided["innerRef"];
}) => {
const hasChildren = collections.some((e) => e.parentId === collection.id);
// Check if the current collection or any of its subcollections is active
const isActiveOrParentOfActive = React.useMemo(() => {
const isActive = active === `/collections/${collection.id}`;
if (isActive) return true;
const checkIfParentOfActive = (parentId: number): boolean => {
return collections.some((e) => {
if (e.id === parseInt(active.split("/collections/")[1])) {
if (e.parentId === parentId) return true;
if (e.parentId) return checkIfParentOfActive(e.parentId);
}
return false;
});
// Define a root item to act as the top-level node of your tree if needed
const rootId = "root";
items[rootId] = {
id: rootId,
children: collections
.filter((c) => c.parentId === null)
.map((c) => c.id.toString()),
hasChildren: true,
isExpanded: true,
data: { title: "Root" },
};
return checkIfParentOfActive(collection.id as number);
}, [active, collection.id, collections]);
return { rootId, items };
};
const [isOpen, setIsOpen] = useState(isActiveOrParentOfActive);
const [tree, setTree] = useState<TreeData>();
const { collections } = useCollectionStore();
useEffect(() => {
setIsOpen(isActiveOrParentOfActive);
}, [isActiveOrParentOfActive]);
const initialTree = buildTreeFromCollections(collections);
collections[0] && setTree(initialTree);
}, [collections]);
return hasChildren ? (
<>
<div
ref={innerRef}
{...props}
className={`${
active === `/collections/${collection.id}`
? "bg-primary/20 is-active"
: "hover:bg-neutral/20"
} duration-100 rounded-md flex w-full items-center cursor-pointer mb-1 px-2 gap-1`}
>
<button
onClick={() => setIsOpen(!isOpen)}
className="flex items-center"
>
<i
className={`bi-chevron-down ${
isOpen ? "rotate-reverse" : "rotate"
}`}
></i>
const getIcon = useCallback((item, onExpand, onCollapse) => {
if (item.children && item.children.length > 0) {
return item.isExpanded ? (
<button onClick={() => onCollapse(item.id)}>
<div className="bi-chevron-down"></div>
</button>
<Link href={`/collections/${collection.id}`} className="w-full">
) : (
<button onClick={() => onExpand(item.id)}>
<div className="bi-chevron-right"></div>
</button>
);
}
return <span>&bull;</span>;
}, []);
const renderItem = useCallback(
({ item, onExpand, onCollapse, provided }: RenderItemParams) => {
return (
<div ref={provided.innerRef} {...provided.draggableProps}>
<div
className={`py-1 cursor-pointer flex items-center gap-2 w-full h-8 capitalize`}
className="flex gap-1 items-center"
{...provided.dragHandleProps}
>
<i
className="bi-folder-fill text-2xl drop-shadow"
style={{ color: collection.color }}
></i>
<p className="truncate w-full">{collection.name}</p>
{collection.isPublic ? (
<i
className="bi-globe2 text-sm text-black/50 dark:text-white/50 drop-shadow"
title="This collection is being shared publicly."
></i>
) : undefined}
<div className="drop-shadow text-neutral text-xs">
{collection._count?.links}
</div>
</div>
</Link>
</div>
{isOpen && hasChildren && (
<div className="ml-4 pl-1 border-l border-neutral-content">
{collections
.filter((e) => e.parentId === collection.id)
.map((subCollection) => (
<CollectionItem
key={subCollection.id}
collection={subCollection}
active={active}
collections={collections}
/>
))}
</div>
)}
</>
) : (
<div ref={innerRef} {...props}>
<Link href={`/collections/${collection.id}`} className="w-full">
<div
className={`${
active === `/collections/${collection.id}`
? "bg-primary/20"
: "hover:bg-neutral/20"
} duration-100 py-1 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8 capitalize mb-1`}
>
<i
className="bi-folder-fill text-2xl drop-shadow"
style={{ color: collection.color }}
></i>
<p className="truncate w-full">{collection.name}</p>
{collection.isPublic ? (
<i
className="bi-globe2 text-sm text-black/50 dark:text-white/50 drop-shadow"
title="This collection is being shared publicly."
></i>
) : undefined}
<div className="drop-shadow text-neutral text-xs">
{collection._count?.links}
{getIcon(item, onExpand, onCollapse)}
{item.data ? item.data.title : ""}
</div>
</div>
</Link>
</div>
);
},
[getIcon]
);
const onExpand = useCallback(
(itemId: ItemId) => {
if (tree) {
setTree((currentTree) =>
mutateTree(currentTree, itemId, { isExpanded: true })
);
}
},
[tree]
);
const onCollapse = useCallback(
(itemId: ItemId) => {
if (tree) {
setTree((currentTree) =>
mutateTree(currentTree, itemId, { isExpanded: false })
);
}
},
[tree]
);
const onDragEnd = useCallback(
(source: TreeSourcePosition, destination?: TreeDestinationPosition) => {
if (!destination || !tree) {
return;
}
setTree((currentTree) =>
moveItemOnTree(currentTree, source, destination)
);
},
[tree]
);
if (!tree) {
return <div>Loading...</div>; // or any other loading state representation
}
return (
<Tree
tree={tree}
renderItem={renderItem}
onExpand={onExpand}
onCollapse={onCollapse}
onDragEnd={onDragEnd}
isDragEnabled
isNestingEnabled
/>
);
};
export default DragDropWithNestingTree;
class TreeBuilder {
rootId: ItemId;
items: Record<ItemId, TreeItem>;
constructor(rootId: ItemId) {
const rootItem = this._createItem(`${rootId}`);
this.rootId = rootItem.id;
this.items = {
[rootItem.id]: rootItem,
};
}
withLeaf(id: number) {
const leafItem = this._createItem(`${this.rootId}-${id}`);
this._addItemToRoot(leafItem.id);
this.items[leafItem.id] = leafItem;
return this;
}
withSubTree(tree: TreeBuilder) {
const subTree = tree.build();
this._addItemToRoot(`${this.rootId}-${subTree.rootId}`);
Object.keys(subTree.items).forEach((itemId) => {
const finalId = `${this.rootId}-${itemId}`;
this.items[finalId] = {
...subTree.items[itemId],
id: finalId,
children: subTree.items[itemId].children.map(
(i) => `${this.rootId}-${i}`
),
};
});
return this;
}
build() {
return {
rootId: this.rootId,
items: this.items,
};
}
_addItemToRoot(id: string) {
const rootItem = this.items[this.rootId];
rootItem.children.push(id);
rootItem.isExpanded = true;
rootItem.hasChildren = true;
}
_createItem = (id: string) => {
return {
id: `${id}`,
children: [],
hasChildren: false,
isExpanded: false,
isChildrenLoading: false,
data: {
title: `Title ${id}`,
},
};
};
}
const complexTree: TreeData = new TreeBuilder(1)
.withLeaf(0) // 0
.withLeaf(1) // 1
.withSubTree(
new TreeBuilder(2) // 2
.withLeaf(0) // 3
.withLeaf(1) // 4
.withLeaf(2) // 5
.withLeaf(3) // 6
)
.withLeaf(3) // 7
.withLeaf(4) // 8
.withLeaf(5) // 9
.withSubTree(
new TreeBuilder(6) // 10
.withLeaf(0) // 11
.withLeaf(1) // 12
.withSubTree(
new TreeBuilder(2) // 13
.withLeaf(0) // 14
.withLeaf(1) // 15
.withLeaf(2) // 16
)
.withLeaf(3) // 17
.withLeaf(4) // 18
)
.withLeaf(7) // 19
.withLeaf(8) // 20
.build();
+2 -1
View File
@@ -19,6 +19,7 @@
"format": "prettier --write \"**/*.{ts,tsx,js,json,md}\""
},
"dependencies": {
"@atlaskit/tree": "^8.8.7",
"@auth/prisma-adapter": "^1.0.1",
"@aws-sdk/client-s3": "^3.379.1",
"@headlessui/react": "^1.7.15",
@@ -84,4 +85,4 @@
"ts-node": "^10.9.2",
"typescript": "4.9.4"
}
}
}
+1
View File
@@ -0,0 +1 @@
declare module "@atlaskit/navigation";
+54 -6
View File
@@ -12,6 +12,15 @@
resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30"
integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
"@atlaskit/tree@^8.8.7":
version "8.8.7"
resolved "https://registry.yarnpkg.com/@atlaskit/tree/-/tree-8.8.7.tgz#f895137b063f676a490abb0b5deb939a96f51fd7"
integrity sha512-ftbFCzZoa5tZh35EdwMEP9lPuBfw19vtB1CcBmDDMP0AnyEXLjUVfVo8kIls6oI4wivYfIWkZgrUlgN+Jk1b0Q==
dependencies:
"@babel/runtime" "^7.0.0"
css-box-model "^1.2.0"
react-beautiful-dnd-next "11.0.5"
"@auth/core@0.9.0":
version "0.9.0"
resolved "https://registry.yarnpkg.com/@auth/core/-/core-0.9.0.tgz#7a5d66eea0bc059cef072734698547ae2a0c86a6"
@@ -614,6 +623,21 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/runtime-corejs2@^7.4.5":
version "7.24.0"
resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.24.0.tgz#23c12d76ac8a7a0ec223c4b0c3b937f9c203fa33"
integrity sha512-RZVGq1it0GA1K8rb+z7v7NzecP6VYCMedN7yHsCCIQUMmRXFCPJD8GISdf6uIGj7NDDihg7ieQEzpdpQbUL75Q==
dependencies:
core-js "^2.6.12"
regenerator-runtime "^0.14.0"
"@babel/runtime@^7.0.0":
version "7.24.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.0.tgz#584c450063ffda59697021430cb47101b085951e"
integrity sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==
dependencies:
regenerator-runtime "^0.14.0"
"@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.7", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
version "7.21.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.5.tgz#8492dddda9644ae3bda3b45eabe87382caee7200"
@@ -2640,6 +2664,11 @@ cookie@0.5.0, cookie@^0.5.0:
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
core-js@^2.6.12:
version "2.6.12"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
core-util-is@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@@ -2675,7 +2704,7 @@ crypto-js@^4.2.0:
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==
css-box-model@^1.2.0:
css-box-model@^1.1.2, 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==
@@ -4351,7 +4380,7 @@ make-error@^1.1.1:
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
memoize-one@^5.1.1:
memoize-one@^5.0.4, 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==
@@ -5079,7 +5108,7 @@ queue-microtask@^1.2.2:
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
raf-schd@^4.0.2:
raf-schd@^4.0.0, 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==
@@ -5094,6 +5123,20 @@ raw-body@2.4.1:
iconv-lite "0.4.24"
unpipe "1.0.0"
react-beautiful-dnd-next@11.0.5:
version "11.0.5"
resolved "https://registry.yarnpkg.com/react-beautiful-dnd-next/-/react-beautiful-dnd-next-11.0.5.tgz#41e693733bbdeb6269b9e4b923a36de2e99ed761"
integrity sha512-kM5Mob41HkA3ShS9uXqeMkW51L5bVsfttxfrwwHucu7I6SdnRKCyN78t6QiLH/UJQQ8T4ukI6NeQAQQpGwolkg==
dependencies:
"@babel/runtime-corejs2" "^7.4.5"
css-box-model "^1.1.2"
memoize-one "^5.0.4"
raf-schd "^4.0.0"
react-redux "^7.0.3"
redux "^4.0.1"
tiny-invariant "^1.0.4"
use-memo-one "^1.1.0"
react-beautiful-dnd@^13.1.1:
version "13.1.1"
resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz#b0f3087a5840920abf8bb2325f1ffa46d8c4d0a2"
@@ -5142,7 +5185,7 @@ react-is@^17.0.2:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
react-redux@^7.2.0:
react-redux@^7.0.3, react-redux@^7.2.0:
version "7.2.9"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.9.tgz#09488fbb9416a4efe3735b7235055442b042481d"
integrity sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==
@@ -5244,7 +5287,7 @@ readdirp@~3.6.0:
dependencies:
picomatch "^2.2.1"
redux@^4.0.0, redux@^4.0.4:
redux@^4.0.0, redux@^4.0.1, redux@^4.0.4:
version "4.2.1"
resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197"
integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==
@@ -5774,6 +5817,11 @@ tiny-glob@^0.2.9:
globalyzer "0.1.0"
globrex "^0.1.2"
tiny-invariant@^1.0.4:
version "1.3.3"
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127"
integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==
tiny-invariant@^1.0.6:
version "1.3.1"
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642"
@@ -6015,7 +6063,7 @@ use-isomorphic-layout-effect@^1.1.2:
resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb"
integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==
use-memo-one@^1.1.1:
use-memo-one@^1.1.0, use-memo-one@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.3.tgz#2fd2e43a2169eabc7496960ace8c79efef975e99"
integrity sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==