From b0b42a9e0cca0e31fb31d1e00b78c3015b6f5663 Mon Sep 17 00:00:00 2001 From: Karolis Ramanauskas Date: Fri, 13 Dec 2024 09:13:32 +0200 Subject: [PATCH] feat(explorer): export table data (#3380) --- .changeset/ten-hornets-greet.md | 5 + packages/explorer/package.json | 1 + .../[worldAddress]/explore/ExportButton.tsx | 51 ++++ .../[worldAddress]/explore/TablesViewer.tsx | 3 + .../explore/utils/exportTableData.ts | 20 ++ .../src/components/ui/DropdownMenu.tsx | 229 ++++++++++++++++++ pnpm-lock.yaml | 181 +++++++++++++- 7 files changed, 486 insertions(+), 4 deletions(-) create mode 100644 .changeset/ten-hornets-greet.md create mode 100644 packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/ExportButton.tsx create mode 100644 packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/utils/exportTableData.ts create mode 100644 packages/explorer/src/components/ui/DropdownMenu.tsx diff --git a/.changeset/ten-hornets-greet.md b/.changeset/ten-hornets-greet.md new file mode 100644 index 0000000000..c609b226c2 --- /dev/null +++ b/.changeset/ten-hornets-greet.md @@ -0,0 +1,5 @@ +--- +"@latticexyz/explorer": patch +--- + +Added support for exporting table data in CSV, JSON, and TXT formats. diff --git a/packages/explorer/package.json b/packages/explorer/package.json index d92e80c83d..187ab12a82 100644 --- a/packages/explorer/package.json +++ b/packages/explorer/package.json @@ -48,6 +48,7 @@ "@monaco-editor/react": "^4.6.0", "@radix-ui/react-checkbox": "^1.1.1", "@radix-ui/react-dialog": "^1.1.1", + "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-label": "^2.1.0", "@radix-ui/react-popover": "^1.1.1", "@radix-ui/react-select": "^2.1.1", diff --git a/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/ExportButton.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/ExportButton.tsx new file mode 100644 index 0000000000..bdd56fbd00 --- /dev/null +++ b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/ExportButton.tsx @@ -0,0 +1,51 @@ +import { DownloadIcon } from "lucide-react"; +import { Button } from "../../../../../../components/ui/Button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "../../../../../../components/ui/DropdownMenu"; +import { TData } from "../../../../queries/useTableDataQuery"; +import { exportTableData } from "./utils/exportTableData"; + +export function ExportButton({ tableData, isLoading }: { tableData?: TData; isLoading: boolean }) { + return ( + + + + + + { + const csv = tableData?.rows.map((row) => tableData.columns.map((col) => row[col]).join(",")).join("\n"); + const header = tableData?.columns.join(",") + "\n"; + exportTableData(header + csv, "data.csv", "text/csv"); + }} + > + CSV + + { + const json = JSON.stringify(tableData?.rows, null, 2); + exportTableData(json, "data.json", "application/json"); + }} + > + JSON + + { + const txt = tableData?.rows.map((row) => tableData.columns.map((col) => row[col]).join("\t")).join("\n"); + const header = tableData?.columns.join("\t") + "\n"; + exportTableData(header + txt, "data.txt", "text/plain"); + }} + > + TXT + + + + ); +} diff --git a/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/TablesViewer.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/TablesViewer.tsx index 5703311358..53f356b3a7 100644 --- a/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/TablesViewer.tsx +++ b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/TablesViewer.tsx @@ -20,6 +20,7 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from ". import { cn } from "../../../../../../utils"; import { TData, TDataRow, useTableDataQuery } from "../../../../queries/useTableDataQuery"; import { EditableTableCell } from "./EditableTableCell"; +import { ExportButton } from "./ExportButton"; import { typeSortingFn } from "./utils/typeSortingFn"; const initialSortingState: SortingState = []; @@ -105,6 +106,8 @@ export function TablesViewer({ table, query }: { table?: TableType; query?: stri className="max-w-sm rounded border px-2 py-1" disabled={!tableData} /> + +
, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + + +)); +DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName; + +const DropdownMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName; + +const DropdownMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + + + +)); +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; + +const DropdownMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; + +const DropdownMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + + + {children} + +)); +DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName; + +const DropdownMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)); +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName; + +const DropdownMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; + +const DropdownMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; + +const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes) => { + return ; +}; +DropdownMenuShortcut.displayName = "DropdownMenuShortcut"; + +export { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuRadioGroup, +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f5203926f7..b2e3acec78 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -507,6 +507,9 @@ importers: '@radix-ui/react-dialog': specifier: ^1.1.1 version: 1.1.1(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-dropdown-menu': + specifier: ^2.1.2 + version: 2.1.2(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-label': specifier: ^2.1.0 version: 2.1.0(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -836,10 +839,10 @@ importers: version: 8.3.4 jest: specifier: ^29.3.1 - version: 29.5.0(@types/node@18.19.50) + version: 29.5.0(@types/node@20.12.12) ts-jest: specifier: ^29.0.5 - version: 29.0.5(@babel/core@7.21.4)(@jest/types@29.6.3)(babel-jest@29.5.0(@babel/core@7.21.4))(jest@29.5.0(@types/node@18.19.50))(typescript@5.4.2) + version: 29.0.5(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.5.0(@babel/core@7.25.2))(jest@29.5.0(@types/node@20.12.12))(typescript@5.4.2) tsup: specifier: ^6.7.0 version: 6.7.0(postcss@8.4.47)(typescript@5.4.2) @@ -1252,10 +1255,10 @@ importers: version: 27.4.1 jest: specifier: ^29.3.1 - version: 29.5.0(@types/node@20.12.12) + version: 29.5.0(@types/node@18.19.50) ts-jest: specifier: ^29.0.5 - version: 29.0.5(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.5.0(@babel/core@7.25.2))(jest@29.5.0(@types/node@20.12.12))(typescript@5.4.2) + version: 29.0.5(@babel/core@7.21.4)(@jest/types@29.6.3)(babel-jest@29.5.0(@babel/core@7.21.4))(jest@29.5.0(@types/node@18.19.50))(typescript@5.4.2) tsup: specifier: ^6.7.0 version: 6.7.0(postcss@8.4.47)(typescript@5.4.2) @@ -4029,6 +4032,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-context@1.1.1': + resolution: {integrity: sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-dialog@1.0.5': resolution: {integrity: sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==} peerDependencies: @@ -4090,6 +4102,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-dismissable-layer@1.1.1': + resolution: {integrity: sha512-QSxg29lfr/xcev6kSz7MAlmDnzbP1eI/Dwn3Tp1ip0KT5CUELsxkekFEMVBEoykI3oV39hKT4TKZzBNMbcTZYQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-dropdown-menu@2.1.1': resolution: {integrity: sha512-y8E+x9fBq9qvteD2Zwa4397pUVhYsh9iq44b5RD5qu1GMJWBCBuVg1hMyItbc6+zH00TxGRqd9Iot4wzf3OoBQ==} peerDependencies: @@ -4103,6 +4128,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-dropdown-menu@2.1.2': + resolution: {integrity: sha512-GVZMR+eqK8/Kes0a36Qrv+i20bAPXSn8rCBTHx30w+3ECnR5o3xixAlqcVaYvLeyKUsm0aqyhWfmUcqufM8nYA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-focus-guards@1.0.1': resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==} peerDependencies: @@ -4121,6 +4159,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-focus-guards@1.1.1': + resolution: {integrity: sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-focus-scope@1.0.4': resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==} peerDependencies: @@ -4217,6 +4264,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-menu@2.1.2': + resolution: {integrity: sha512-lZ0R4qR2Al6fZ4yCCZzu/ReTFrylHFxIqy7OezIpWF4bL0o9biKo0pFIvkaew3TyZ9Fy5gYVrR5zCGZBVbO1zg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-navigation-menu@1.2.0': resolution: {integrity: sha512-OQ8tcwAOR0DhPlSY3e4VMXeHiol7la4PPdJWhhwJiJA+NLX0SaCaonOkRnI3gCDHoZ7Fo7bb/G6q25fRM2Y+3Q==} peerDependencies: @@ -4282,6 +4342,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-portal@1.1.2': + resolution: {integrity: sha512-WeDYLGPxJb/5EGBoedyJbT0MpoULmwnIPMJMSldkuiMsBAv7N1cRdsTWZWht9vpPOiN3qyiGAtbK2is47/uMFg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-presence@1.0.1': resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} peerDependencies: @@ -4308,6 +4381,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-presence@1.1.1': + resolution: {integrity: sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-primitive@1.0.3': resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} peerDependencies: @@ -6895,6 +6981,7 @@ packages: eciesjs@0.3.20: resolution: {integrity: sha512-Rz5AB8v9+xmMdS/R7RzWPe/R8DP5QfyrkA6ce4umJopoB5su2H2aDy/GcgIfwhmCwxnBkqGf/PbGzmKcGtIgGA==} + deprecated: Please upgrade to v0.4+ ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -14809,6 +14896,12 @@ snapshots: optionalDependencies: '@types/react': 18.2.22 + '@radix-ui/react-context@1.1.1(@types/react@18.2.22)(react@18.2.0)': + dependencies: + react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.22 + '@radix-ui/react-dialog@1.0.5(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.0 @@ -14887,6 +14980,19 @@ snapshots: '@types/react': 18.2.22 '@types/react-dom': 18.2.7 + '@radix-ui/react-dismissable-layer@1.1.1(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.22)(react@18.2.0) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.22)(react@18.2.0) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.2.22)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.22 + '@types/react-dom': 18.2.7 + '@radix-ui/react-dropdown-menu@2.1.1(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@radix-ui/primitive': 1.1.0 @@ -14902,6 +15008,21 @@ snapshots: '@types/react': 18.2.22 '@types/react-dom': 18.2.7 + '@radix-ui/react-dropdown-menu@2.1.2(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.22)(react@18.2.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.2.22)(react@18.2.0) + '@radix-ui/react-id': 1.1.0(@types/react@18.2.22)(react@18.2.0) + '@radix-ui/react-menu': 2.1.2(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.2.22)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.22 + '@types/react-dom': 18.2.7 + '@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.22)(react@18.2.0)': dependencies: '@babel/runtime': 7.25.0 @@ -14915,6 +15036,12 @@ snapshots: optionalDependencies: '@types/react': 18.2.22 + '@radix-ui/react-focus-guards@1.1.1(@types/react@18.2.22)(react@18.2.0)': + dependencies: + react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.22 + '@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.0 @@ -15019,6 +15146,32 @@ snapshots: '@types/react': 18.2.22 '@types/react-dom': 18.2.7 + '@radix-ui/react-menu@2.1.2(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.22)(react@18.2.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.2.22)(react@18.2.0) + '@radix-ui/react-direction': 1.1.0(@types/react@18.2.22)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.1.1(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.2.22)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-id': 1.1.0(@types/react@18.2.22)(react@18.2.0) + '@radix-ui/react-popper': 1.2.0(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-portal': 1.1.2(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-presence': 1.1.1(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-roving-focus': 1.1.0(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-slot': 1.1.0(@types/react@18.2.22)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.22)(react@18.2.0) + aria-hidden: 1.2.4 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-remove-scroll: 2.6.0(@types/react@18.2.22)(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.22 + '@types/react-dom': 18.2.7 + '@radix-ui/react-navigation-menu@1.2.0(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@radix-ui/primitive': 1.1.0 @@ -15102,6 +15255,16 @@ snapshots: '@types/react': 18.2.22 '@types/react-dom': 18.2.7 + '@radix-ui/react-portal@1.1.2(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.22)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.22 + '@types/react-dom': 18.2.7 + '@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.0 @@ -15123,6 +15286,16 @@ snapshots: '@types/react': 18.2.22 '@types/react-dom': 18.2.7 + '@radix-ui/react-presence@1.1.1(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.22)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.22)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.22 + '@types/react-dom': 18.2.7 + '@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.0