From 783f8dea76b99ce72711dbfa383e627f2ba957be Mon Sep 17 00:00:00 2001
From: Mamadou DICKO <63923024+mamadoudicko@users.noreply.github.com>
Date: Wed, 12 Jul 2023 14:56:25 +0200
Subject: [PATCH] [ShareableBrain] User email and role inputs form (#608)
* feat: add invitation emails form
* test(ShareBrain): add tests
---
.../components/BrainActions/BrainActions.tsx | 16 +--
.../components/BrainActions/ShareBrain.tsx | 47 ---------
.../BrainActions/components/DeleteBrain.tsx | 19 ++++
.../components/ShareBrain/ShareBrain.tsx | 97 +++++++++++++++++++
.../ShareBrain/__tests__/ShareBrain.test.tsx | 50 ++++++++++
.../ShareBrain/components/InvitedUserRow.tsx | 69 +++++++++++++
.../components/ShareBrain/components/index.ts | 1 +
.../ShareBrain/hooks/useShareBrain.ts | 83 ++++++++++++++++
.../components/ShareBrain/index.ts | 1 +
.../utils/generateBrainAssignation.ts | 9 ++
.../BrainActions/components/index.ts | 2 +
.../components/BrainActions/types.ts | 9 ++
frontend/lib/components/ui/Select.tsx | 96 ++++++++++++++++++
frontend/package.json | 1 +
frontend/yarn.lock | 49 ++++++++++
15 files changed, 488 insertions(+), 61 deletions(-)
delete mode 100644 frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/ShareBrain.tsx
create mode 100644 frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/DeleteBrain.tsx
create mode 100644 frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/ShareBrain.tsx
create mode 100644 frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/__tests__/ShareBrain.test.tsx
create mode 100644 frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/InvitedUserRow.tsx
create mode 100644 frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/index.ts
create mode 100644 frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/hooks/useShareBrain.ts
create mode 100644 frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/index.ts
create mode 100644 frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/utils/generateBrainAssignation.ts
create mode 100644 frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/index.ts
create mode 100644 frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/types.ts
create mode 100644 frontend/lib/components/ui/Select.tsx
diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/BrainActions.tsx b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/BrainActions.tsx
index 4cba45a62..85b15a1c8 100644
--- a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/BrainActions.tsx
+++ b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/BrainActions.tsx
@@ -1,28 +1,16 @@
import { UUID } from "crypto";
-import { MdDelete } from "react-icons/md";
-import Button from "@/lib/components/ui/Button";
-import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
-
-import { ShareBrain } from "./ShareBrain";
+import { DeleteBrain, ShareBrain } from "./components";
type BrainActionsProps = {
brainId: UUID;
};
export const BrainActions = ({ brainId }: BrainActionsProps): JSX.Element => {
- const { deleteBrain } = useBrainContext();
-
return (
-
+
);
};
diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/ShareBrain.tsx b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/ShareBrain.tsx
deleted file mode 100644
index 7c7eef7ef..000000000
--- a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/ShareBrain.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import { UUID } from "crypto";
-import { MdContentPaste, MdShare } from "react-icons/md";
-
-import Button from "@/lib/components/ui/Button";
-import Modal from "@/lib/components/ui/Modal";
-import { useToast } from "@/lib/hooks";
-
-type ShareBrainModalProps = {
- brainId: UUID;
-};
-
-export const ShareBrain = ({ brainId }: ShareBrainModalProps): JSX.Element => {
- const { publish } = useToast();
-
- const baseUrl = window.location.origin;
- const brainShareLink = `${baseUrl}/brain_subscription_invitation=${brainId}`;
-
- const handleCopyInvitationLink = async () => {
- await navigator.clipboard.writeText(brainShareLink);
- publish({
- variant: "success",
- text: "Copied to clipboard",
- });
- };
-
- return (
- void 0}
- variant={"tertiary"}
- >
-
-
- }
- title="Share brain"
- >
-
-
{brainShareLink}
-
-
-
- );
-};
diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/DeleteBrain.tsx b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/DeleteBrain.tsx
new file mode 100644
index 000000000..0b1057393
--- /dev/null
+++ b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/DeleteBrain.tsx
@@ -0,0 +1,19 @@
+import { UUID } from "crypto";
+import { MdDelete } from "react-icons/md";
+
+import Button from "@/lib/components/ui/Button";
+import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
+
+export const DeleteBrain = ({ brainId }: { brainId: UUID }): JSX.Element => {
+ const { deleteBrain } = useBrainContext();
+
+ return (
+
+ );
+};
diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/ShareBrain.tsx b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/ShareBrain.tsx
new file mode 100644
index 000000000..befe7abaa
--- /dev/null
+++ b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/ShareBrain.tsx
@@ -0,0 +1,97 @@
+"use client";
+
+import { UUID } from "crypto";
+import { ImUserPlus } from "react-icons/im";
+import { MdContentPaste, MdShare } from "react-icons/md";
+
+import Button from "@/lib/components/ui/Button";
+import Modal from "@/lib/components/ui/Modal";
+
+import { InvitedUserRow } from "./components/InvitedUserRow";
+import { useShareBrain } from "./hooks/useShareBrain";
+
+type ShareBrainModalProps = {
+ brainId: UUID;
+};
+
+export const ShareBrain = ({ brainId }: ShareBrainModalProps): JSX.Element => {
+ const {
+ roleAssignations,
+ brainShareLink,
+ handleCopyInvitationLink,
+ updateRoleAssignation,
+ removeRoleAssignation,
+ inviteUsers,
+ addNewRoleAssignationRole,
+ } = useShareBrain(brainId);
+
+ const canAddNewRow =
+ roleAssignations.length === 0 ||
+ roleAssignations.filter((invitingUser) => invitingUser.email === "")
+ .length === 0;
+
+ return (
+ void 0}
+ variant={"tertiary"}
+ data-testId="share-brain-button"
+ >
+
+
+ }
+ CloseTrigger={}
+ title="Share brain"
+ >
+
+
+ );
+};
diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/__tests__/ShareBrain.test.tsx b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/__tests__/ShareBrain.test.tsx
new file mode 100644
index 000000000..f5974b82e
--- /dev/null
+++ b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/__tests__/ShareBrain.test.tsx
@@ -0,0 +1,50 @@
+import { fireEvent, render } from "@testing-library/react";
+import { describe, expect, it } from "vitest";
+
+import { ShareBrain } from "../ShareBrain";
+
+describe("ShareBrain", () => {
+ it("should render ShareBrain component properly", () => {
+ const { getByTestId } = render(
+
+ );
+ const shareButton = getByTestId("share-brain-button");
+ expect(shareButton).toBeDefined();
+ });
+
+ it("should render open share modal when share button is clicked", () => {
+ const { getByText, getByTestId } = render(
+
+ );
+ const shareButton = getByTestId("share-brain-button");
+ fireEvent.click(shareButton);
+ expect(getByText("Share brain")).toBeDefined();
+ });
+
+ it('shoud add new user row when "Add new user" button is clicked and only where there is no empty field', async () => {
+ const { getByTestId, findAllByTestId } = render(
+
+ );
+ const shareButton = getByTestId("share-brain-button");
+ fireEvent.click(shareButton);
+
+ let assignationRows = await findAllByTestId("assignation-row");
+
+ expect(assignationRows.length).toBe(1);
+
+ const firstAssignationRowEmailInput = (
+ await findAllByTestId("role-assignation-email-input")
+ )[0];
+
+ fireEvent.change(firstAssignationRowEmailInput, {
+ target: { value: "user@quivr.app" },
+ });
+
+ const addNewRoleAssignationButton = getByTestId("add-new-row-role-button");
+ fireEvent.click(addNewRoleAssignationButton);
+
+ assignationRows = await findAllByTestId("assignation-row");
+
+ expect(assignationRows.length).toBe(2);
+ });
+});
diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/InvitedUserRow.tsx b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/InvitedUserRow.tsx
new file mode 100644
index 000000000..946842c72
--- /dev/null
+++ b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/InvitedUserRow.tsx
@@ -0,0 +1,69 @@
+import { useEffect, useState } from "react";
+import { MdOutlineRemoveCircle } from "react-icons/md";
+
+import Field from "@/lib/components/ui/Field";
+import { Select } from "@/lib/components/ui/Select";
+
+import { BrainRoleAssignation, BrainRoleType } from "../../../types";
+
+type AddUserRowProps = {
+ onChange: (newRole: BrainRoleAssignation) => void;
+ removeCurrentInvitation?: () => void;
+ roleAssignation: BrainRoleAssignation;
+};
+
+type SelectOptionsProps = {
+ label: string;
+ value: BrainRoleType;
+};
+const SelectOptions: SelectOptionsProps[] = [
+ { label: "Viewer", value: "viewer" },
+ { label: "Editor", value: "editor" },
+];
+
+export const InvitedUserRow = ({
+ onChange,
+ removeCurrentInvitation,
+ roleAssignation,
+}: AddUserRowProps): JSX.Element => {
+ const [selectedRole, setSelectedRole] = useState(
+ roleAssignation.role
+ );
+ const [email, setEmail] = useState(roleAssignation.email);
+
+ useEffect(() => {
+ onChange({
+ ...roleAssignation,
+ email,
+ role: selectedRole,
+ });
+ }, [email, selectedRole]);
+
+ return (
+
+
+
+
+
+ setEmail(e.target.value)}
+ value={email}
+ onBlur={() => email === "" && removeCurrentInvitation?.()}
+ data-testid="role-assignation-email-input"
+ />
+
+
+
+ );
+};
diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/index.ts b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/index.ts
new file mode 100644
index 000000000..89cee7a15
--- /dev/null
+++ b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/index.ts
@@ -0,0 +1 @@
+export * from "./InvitedUserRow";
diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/hooks/useShareBrain.ts b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/hooks/useShareBrain.ts
new file mode 100644
index 000000000..3a74e835b
--- /dev/null
+++ b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/hooks/useShareBrain.ts
@@ -0,0 +1,83 @@
+import { useState } from "react";
+
+import { useToast } from "@/lib/hooks";
+
+import { BrainRoleAssignation } from "../../../types";
+import { generateBrainAssignation } from "../utils/generateBrainAssignation";
+
+// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+export const useShareBrain = (brainId: string) => {
+ const baseUrl = window.location.origin;
+ const { publish } = useToast();
+
+ const brainShareLink = `${baseUrl}/brain_subscription_invitation=${brainId}`;
+
+ const [roleAssignations, setRoleAssignation] = useState<
+ BrainRoleAssignation[]
+ >([generateBrainAssignation()]);
+
+ const handleCopyInvitationLink = async () => {
+ await navigator.clipboard.writeText(brainShareLink);
+ publish({
+ variant: "success",
+ text: "Copied to clipboard",
+ });
+ };
+
+ const removeRoleAssignation = (assignationIndex: number) => () => {
+ if (roleAssignations.length === 1) {
+ return;
+ }
+ setRoleAssignation(
+ roleAssignations.filter((_, index) => index !== assignationIndex)
+ );
+ };
+
+ const updateRoleAssignation =
+ (rowIndex: number) => (data: BrainRoleAssignation) => {
+ const concernedRow = roleAssignations[rowIndex];
+
+ if (concernedRow !== undefined) {
+ setRoleAssignation(
+ roleAssignations.map((row, index) => {
+ if (index === rowIndex) {
+ return data;
+ }
+
+ return row;
+ })
+ );
+ } else {
+ setRoleAssignation([...roleAssignations, data]);
+ }
+ };
+
+ const inviteUsers = (): void => {
+ const inviteUsersPayload = roleAssignations
+ .filter(({ email }) => email !== "")
+ .map((assignation) => ({
+ email: assignation.email,
+ role: assignation.role,
+ }));
+
+ alert(
+ `You will soon be able to invite ${JSON.stringify(
+ inviteUsersPayload
+ )}. Wait a bit`
+ );
+ };
+
+ const addNewRoleAssignationRole = () => {
+ setRoleAssignation([...roleAssignations, generateBrainAssignation()]);
+ };
+
+ return {
+ roleAssignations,
+ brainShareLink,
+ handleCopyInvitationLink,
+ updateRoleAssignation,
+ removeRoleAssignation,
+ inviteUsers,
+ addNewRoleAssignationRole,
+ };
+};
diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/index.ts b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/index.ts
new file mode 100644
index 000000000..94aa3e255
--- /dev/null
+++ b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/index.ts
@@ -0,0 +1 @@
+export * from "./ShareBrain";
diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/utils/generateBrainAssignation.ts b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/utils/generateBrainAssignation.ts
new file mode 100644
index 000000000..bce74cf41
--- /dev/null
+++ b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/utils/generateBrainAssignation.ts
@@ -0,0 +1,9 @@
+import { BrainRoleAssignation } from "../../../types";
+
+export const generateBrainAssignation = (): BrainRoleAssignation => {
+ return {
+ email: "",
+ role: "viewer",
+ id: Math.random().toString(),
+ };
+};
diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/index.ts b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/index.ts
new file mode 100644
index 000000000..14f743488
--- /dev/null
+++ b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/index.ts
@@ -0,0 +1,2 @@
+export * from "./DeleteBrain";
+export * from "./ShareBrain";
diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/types.ts b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/types.ts
new file mode 100644
index 000000000..ae821c3b4
--- /dev/null
+++ b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/types.ts
@@ -0,0 +1,9 @@
+export const roles = ["viewer", "editor"];
+
+export type BrainRoleType = (typeof roles)[number];
+
+export type BrainRoleAssignation = {
+ email: string;
+ role: BrainRoleType;
+ id: string;
+};
diff --git a/frontend/lib/components/ui/Select.tsx b/frontend/lib/components/ui/Select.tsx
new file mode 100644
index 000000000..e90865adf
--- /dev/null
+++ b/frontend/lib/components/ui/Select.tsx
@@ -0,0 +1,96 @@
+/* eslint-disable max-lines */
+import { BsCheckCircleFill } from "react-icons/bs";
+
+import Popover from "@/lib/components/ui/Popover";
+
+type SelectOptionProps = {
+ label: string;
+ value: string;
+};
+
+type SelectProps = {
+ options: SelectOptionProps[];
+ value?: SelectOptionProps["value"];
+ onChange: (option: SelectOptionProps["value"]) => void;
+ label?: string;
+};
+
+const selectedStyle = "rounded-lg bg-black text-white";
+
+export const Select = ({
+ onChange,
+ options,
+ value,
+ label,
+}: SelectProps): JSX.Element => {
+ const selectedValueLabel = options.find(
+ (option) => option.value === value
+ )?.label;
+
+ return (
+
+ {label !== undefined && (
+
+ )}
+
+
+
+
+ {selectedValueLabel ?? label ?? "Select"}
+
+
+
+
+
+
+ }
+ CloseTrigger={}
+ >
+
+
+
+
+ );
+};
diff --git a/frontend/package.json b/frontend/package.json
index af88918f5..3d8819f06 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -22,6 +22,7 @@
"@june-so/analytics-next": "^2.0.0",
"@radix-ui/react-dialog": "^1.0.3",
"@radix-ui/react-popover": "^1.0.6",
+ "@radix-ui/react-select": "^1.2.2",
"@radix-ui/react-toast": "^1.1.3",
"@radix-ui/react-tooltip": "^1.0.6",
"@sentry/nextjs": "^7.57.0",
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index 9d4fc7721..bb025768a 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -742,6 +742,13 @@
picocolors "^1.0.0"
tslib "^2.5.0"
+"@radix-ui/number@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.0.1.tgz#644161a3557f46ed38a042acf4a770e826021674"
+ integrity sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
"@radix-ui/primitive@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.0.1.tgz#e46f9958b35d10e9f6dc71c497305c22e3e55dbd"
@@ -803,6 +810,13 @@
aria-hidden "^1.1.1"
react-remove-scroll "2.5.5"
+"@radix-ui/react-direction@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.0.1.tgz#9cb61bf2ccf568f3421422d182637b7f47596c9b"
+ integrity sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
"@radix-ui/react-dismissable-layer@1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.4.tgz#883a48f5f938fa679427aa17fcba70c5494c6978"
@@ -904,6 +918,34 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-slot" "1.0.2"
+"@radix-ui/react-select@^1.2.2":
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-select/-/react-select-1.2.2.tgz#caa981fa0d672cf3c1b2a5240135524e69b32181"
+ integrity sha512-zI7McXr8fNaSrUY9mZe4x/HC0jTLY9fWNhO1oLWYMQGDXuV4UCivIGTxwioSzO0ZCYX9iSLyWmAh/1TOmX3Cnw==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/number" "1.0.1"
+ "@radix-ui/primitive" "1.0.1"
+ "@radix-ui/react-collection" "1.0.3"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-direction" "1.0.1"
+ "@radix-ui/react-dismissable-layer" "1.0.4"
+ "@radix-ui/react-focus-guards" "1.0.1"
+ "@radix-ui/react-focus-scope" "1.0.3"
+ "@radix-ui/react-id" "1.0.1"
+ "@radix-ui/react-popper" "1.1.2"
+ "@radix-ui/react-portal" "1.0.3"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-slot" "1.0.2"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+ "@radix-ui/react-use-controllable-state" "1.0.1"
+ "@radix-ui/react-use-layout-effect" "1.0.1"
+ "@radix-ui/react-use-previous" "1.0.1"
+ "@radix-ui/react-visually-hidden" "1.0.3"
+ aria-hidden "^1.1.1"
+ react-remove-scroll "2.5.5"
+
"@radix-ui/react-slot@1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab"
@@ -980,6 +1022,13 @@
dependencies:
"@babel/runtime" "^7.13.10"
+"@radix-ui/react-use-previous@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.0.1.tgz#b595c087b07317a4f143696c6a01de43b0d0ec66"
+ integrity sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
"@radix-ui/react-use-rect@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.0.1.tgz#fde50b3bb9fd08f4a1cd204572e5943c244fcec2"