diff --git a/frontend/__snapshots__/lemon-ui-lemon-tree--default--dark.png b/frontend/__snapshots__/lemon-ui-lemon-tree--default--dark.png index 3e325418fdd74..aafed6b77aecf 100644 Binary files a/frontend/__snapshots__/lemon-ui-lemon-tree--default--dark.png and b/frontend/__snapshots__/lemon-ui-lemon-tree--default--dark.png differ diff --git a/frontend/__snapshots__/lemon-ui-lemon-tree--default--light.png b/frontend/__snapshots__/lemon-ui-lemon-tree--default--light.png index 66ab2e887142a..26706b0494a9f 100644 Binary files a/frontend/__snapshots__/lemon-ui-lemon-tree--default--light.png and b/frontend/__snapshots__/lemon-ui-lemon-tree--default--light.png differ diff --git a/frontend/__snapshots__/ui-colors--brand-accent-colors--dark.png b/frontend/__snapshots__/ui-colors--brand-accent-colors--dark.png new file mode 100644 index 0000000000000..0244bad277da8 Binary files /dev/null and b/frontend/__snapshots__/ui-colors--brand-accent-colors--dark.png differ diff --git a/frontend/__snapshots__/ui-colors--brand-accent-colors--light.png b/frontend/__snapshots__/ui-colors--brand-accent-colors--light.png new file mode 100644 index 0000000000000..a848c37074239 Binary files /dev/null and b/frontend/__snapshots__/ui-colors--brand-accent-colors--light.png differ diff --git a/frontend/__snapshots__/ui-colors--primitive-colors--dark.png b/frontend/__snapshots__/ui-colors--primitive-colors--dark.png new file mode 100644 index 0000000000000..98e6e027983d9 Binary files /dev/null and b/frontend/__snapshots__/ui-colors--primitive-colors--dark.png differ diff --git a/frontend/__snapshots__/ui-colors--primitive-colors--light.png b/frontend/__snapshots__/ui-colors--primitive-colors--light.png new file mode 100644 index 0000000000000..47949a669fddc Binary files /dev/null and b/frontend/__snapshots__/ui-colors--primitive-colors--light.png differ diff --git a/frontend/__snapshots__/ui-colors--semantic-colors--dark.png b/frontend/__snapshots__/ui-colors--semantic-colors--dark.png new file mode 100644 index 0000000000000..c6513fe071c6a Binary files /dev/null and b/frontend/__snapshots__/ui-colors--semantic-colors--dark.png differ diff --git a/frontend/__snapshots__/ui-colors--semantic-colors--light.png b/frontend/__snapshots__/ui-colors--semantic-colors--light.png new file mode 100644 index 0000000000000..242956a76f2ec Binary files /dev/null and b/frontend/__snapshots__/ui-colors--semantic-colors--light.png differ diff --git a/frontend/__snapshots__/ui-context-menu--default--dark.png b/frontend/__snapshots__/ui-context-menu--default--dark.png new file mode 100644 index 0000000000000..da0cf138ab563 Binary files /dev/null and b/frontend/__snapshots__/ui-context-menu--default--dark.png differ diff --git a/frontend/__snapshots__/ui-context-menu--default--light.png b/frontend/__snapshots__/ui-context-menu--default--light.png new file mode 100644 index 0000000000000..fbefe7098d2b3 Binary files /dev/null and b/frontend/__snapshots__/ui-context-menu--default--light.png differ diff --git a/frontend/package.json b/frontend/package.json index f9d3ca2f19a6b..ce7370939ac96 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -63,6 +63,8 @@ "@posthog/rrweb-plugin-console-record": "0.0.8", "@posthog/rrweb-types": "0.0.8", "@radix-ui/react-accordion": "^1.2.2", + "@radix-ui/react-context-menu": "^2.2.6", + "@radix-ui/react-slot": "^1.1.2", "@react-hook/size": "^2.1.2", "@sentry/react": "7.112.1", "@stripe/react-stripe-js": "^2.8.0", diff --git a/frontend/src/layout/navigation-3000/components/ProjectTree/ProjectTree.tsx b/frontend/src/layout/navigation-3000/components/ProjectTree/ProjectTree.tsx index 6b4ef5e291c5c..8d08f4343fca2 100644 --- a/frontend/src/layout/navigation-3000/components/ProjectTree/ProjectTree.tsx +++ b/frontend/src/layout/navigation-3000/components/ProjectTree/ProjectTree.tsx @@ -1,16 +1,17 @@ +import { IconPlusSmall } from '@posthog/icons' import { LemonBanner, LemonButton } from '@posthog/lemon-ui' import clsx from 'clsx' import { useActions, useValues } from 'kea' import { Resizer } from 'lib/components/Resizer/Resizer' import { More } from 'lib/lemon-ui/LemonButton/More' import { LemonTree } from 'lib/lemon-ui/LemonTree/LemonTree' +import { ContextMenuGroup, ContextMenuItem } from 'lib/ui/ContextMenu/ContextMenu' import { useRef } from 'react' import { themeLogic } from '~/layout/navigation-3000/themeLogic' import { FileSystemEntry } from '~/queries/schema/schema-general' import { navigation3000Logic } from '../../navigationLogic' -import { KeyboardShortcut } from '../KeyboardShortcut' import { NavbarBottom } from '../NavbarBottom' import { projectTreeLogic } from './projectTreeLogic' import { joinPath, splitPath } from './utils' @@ -19,30 +20,36 @@ export function ProjectTree({ contentRef }: { contentRef: React.RefObject(null) // Items that should not be draggable or droppable, or have a side action // TODO: sync with projectTreeLogic - const specialItemsIds: string[] = [ - 'project', - 'project/Explore', - 'project/Create new', - '__separator__', - '__apply_pending_actions__', - ] + const notDraggableIds: string[] = ['project', 'project/Explore', 'project/Create new', 'project/Unfiled'] + const notDroppableIds: string[] = ['project', 'project/Explore', 'project/Create new'] return ( <> @@ -52,30 +59,91 @@ export function ProjectTree({ contentRef }: { contentRef: React.RefObject +
+

Files

+
+ {pendingActionsCount > 0 ? ( + + {pendingActionsCount} {pendingActionsCount > 1 ? 'changes' : 'change'} + + ) : null} + { + cancelPendingActions() + toggleDragAndDrop(!dragAndDropEnabled) + }} + type="secondary" + size="small" + tooltip={ + dragAndDropEnabled + ? 'Click to cancel editing and changes' + : 'Click to editing and drag and drop' + } + > + {dragAndDropEnabled ? `Cancel` : 'Edit'} + + { + applyPendingActions() + toggleDragAndDrop(!dragAndDropEnabled) + } + : undefined + } + > + Save + + { + const folder = prompt('Create a new folder:') + if (folder) { + addFolder(folder) + } + }} + icon={} + /> +
+
+ +
+ { - if (node?.record?.type === 'project' || node?.record?.type === 'folder') { - updateLastViewedPath(node.record?.path) + if (node?.record?.path) { + updateLastViewedId(node?.id || '') } }} onFolderClick={(folder, isExpanded) => { if (folder) { - updateSelectedFolder(folder.record?.path || '') - toggleFolder(folder.record?.path || '', isExpanded) + toggleFolderOpen(folder?.id || '', isExpanded) } }} onSetExpandedItemIds={updateExpandedFolders} - enableDragAndDrop={true} + enableDragAndDrop={dragAndDropEnabled} onDragEnd={(dragEvent) => { const oldPath = dragEvent.active.id as string const folder = dragEvent.over?.id + if (oldPath === folder) { + return false + } + if (folder === '') { const oldSplit = splitPath(oldPath) const oldFile = oldSplit.pop() @@ -100,14 +168,15 @@ export function ProjectTree({ contentRef }: { contentRef: React.RefObject { const path = item.record?.path || '' - // disable dropping for special items - if (specialItemsIds.includes(item.id || '')) { + // disable dropping for these IDS + if (notDroppableIds.includes(item.id || '')) { return false } @@ -121,8 +190,76 @@ export function ProjectTree({ contentRef }: { contentRef: React.RefObject { + if (notDraggableIds.includes(item.id || '')) { + return undefined + } + return ( + + {item.record?.type === 'folder' || item.record?.type === 'project' ? ( + { + e.stopPropagation() + const folder = prompt( + item.record?.path + ? `Create a folder under "${item.record?.path}":` + : 'Create a new folder:', + '' + ) + if (folder) { + addFolder( + item.record?.path ? `${item.record?.path}/${folder}` : folder + ) + } + }} + > + New Folder + + ) : null} + {item.record?.path ? ( + { + const oldPath = item.record?.path + const splits = splitPath(oldPath) + if (splits.length > 0) { + const folder = prompt('New name?', splits[splits.length - 1]) + if (folder) { + moveItem(oldPath, joinPath([...splits.slice(0, -1), folder])) + } + } + }} + > + Rename + + ) : null} + {item.record?.path ? ( + { + e.stopPropagation() + if (item.record?.path) { + void navigator.clipboard.writeText(item.record?.path) + } + }} + > + Copy Path + + ) : null} + {item.record?.created_at ? ( + { + e.stopPropagation() + deleteItem(item.record as unknown as FileSystemEntry) + }} + > + Delete + + ) : null} + {/* Add more menu items as needed */} + + ) + }} itemSideAction={(item) => { - if (specialItemsIds.includes(item.id || '')) { + if (notDraggableIds.includes(item.id || '')) { return undefined } return { @@ -145,7 +282,7 @@ export function ProjectTree({ contentRef }: { contentRef: React.RefObject -
  • - Hold down to enable drag and drop. -
  • +
  • Right click on tree item for more options.
  • diff --git a/frontend/src/layout/navigation-3000/components/ProjectTree/projectTreeLogic.tsx b/frontend/src/layout/navigation-3000/components/ProjectTree/projectTreeLogic.tsx index f2c72ed7449c0..270e5fb818ccd 100644 --- a/frontend/src/layout/navigation-3000/components/ProjectTree/projectTreeLogic.tsx +++ b/frontend/src/layout/navigation-3000/components/ProjectTree/projectTreeLogic.tsx @@ -1,5 +1,4 @@ -import { IconBook, IconUpload } from '@posthog/icons' -import { Spinner } from '@posthog/lemon-ui' +import { IconBook } from '@posthog/icons' import { actions, afterMount, connect, kea, listeners, path, reducers, selectors } from 'kea' import { loaders } from 'kea-loaders' import { router } from 'kea-router' @@ -7,7 +6,7 @@ import api from 'lib/api' import { GroupsAccessStatus } from 'lib/introductions/groupsAccessLogic' import { TreeDataItem } from 'lib/lemon-ui/LemonTree/LemonTree' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' -import { capitalizeFirstLetter } from 'lib/utils' +import { capitalizeFirstLetter, shouldIgnoreInput } from 'lib/utils' import { urls } from 'scenes/urls' import { groupsModel } from '~/models/groupsModel' @@ -37,15 +36,15 @@ export const projectTreeLogic = kea([ queueAction: (action: ProjectTreeAction) => ({ action }), removeQueuedAction: (action: ProjectTreeAction) => ({ action }), applyPendingActions: true, + cancelPendingActions: true, createSavedItem: (savedItem: FileSystemEntry) => ({ savedItem }), updateSavedItem: (savedItem: FileSystemEntry) => ({ savedItem }), deleteSavedItem: (savedItem: FileSystemEntry) => ({ savedItem }), - updateExpandedFolders: (folders: string[]) => ({ folders }), - updateActiveFolder: (folder: string | null) => ({ folder }), - updateLastViewedPath: (path: string) => ({ path }), - toggleFolder: (folder: string, isExpanded: boolean) => ({ folder, isExpanded }), - updateSelectedFolder: (folder: string) => ({ folder }), + updateExpandedFolders: (folderIds: string[]) => ({ folderIds }), + updateLastViewedId: (id: string) => ({ id }), + toggleFolderOpen: (folderId: string, isExpanded: boolean) => ({ folderId, isExpanded }), updateHelpNoticeVisibility: (visible: boolean) => ({ visible }), + toggleDragAndDrop: (enabled: boolean) => ({ enabled }), }), loaders(({ actions, values }) => ({ savedItems: [ @@ -90,6 +89,12 @@ export const projectTreeLogic = kea([ } return true }, + cancelPendingActions: async () => { + for (const action of values.pendingActions) { + actions.removeQueuedAction(action) + } + return true + }, }, ], })), @@ -107,6 +112,7 @@ export const projectTreeLogic = kea([ { queueAction: (state, { action }) => [...state, action], removeQueuedAction: (state, { action }) => state.filter((a) => a !== action), + cancelPendingActions: () => [], }, ], savedItems: [ @@ -122,21 +128,14 @@ export const projectTreeLogic = kea([ [] as string[], { persist: true }, { - updateExpandedFolders: (_, { folders }) => folders, + updateExpandedFolders: (_, { folderIds }) => folderIds, }, ], - activeFolder: [ - null as string | null, - { persist: true }, - { - updateActiveFolder: (_, { folder }) => folder, - }, - ], - lastViewedPath: [ + lastViewedId: [ '', { persist: true }, { - updateLastViewedPath: (_, { path }) => path, + updateLastViewedId: (_, { id }) => id, }, ], helpNoticeVisible: [ @@ -146,6 +145,12 @@ export const projectTreeLogic = kea([ updateHelpNoticeVisibility: (_, { visible }) => visible, }, ], + dragAndDropEnabled: [ + false, + { + toggleDragAndDrop: (_, { enabled }) => enabled, + }, + ], }), selectors({ unfiledLoading: [(s) => [s.unfiledLoadingCount], (unfiledLoadingCount) => unfiledLoadingCount > 0], @@ -270,27 +275,13 @@ export const projectTreeLogic = kea([ convertFileSystemEntryToTreeDataItem(getDefaultTree(groupNodes)), ], projectRow: [ - (s) => [s.pendingActionsCount, s.pendingLoaderLoading], - (pendingActionsCount, pendingLoaderLoading): TreeDataItem[] => [ - ...(pendingActionsCount > 0 - ? [ - { - id: '__apply_pending_actions__', - name: `--- Apply${ - pendingLoaderLoading ? 'ing' : '' - } ${pendingActionsCount} unsaved change${pendingActionsCount > 1 ? 's' : ''} ---`, - icon: pendingLoaderLoading ? : , - onClick: !pendingLoaderLoading - ? () => projectTreeLogic.actions.applyPendingActions() - : undefined, - }, - ] - : [ - { - id: '__separator__', - name: '', - }, - ]), + () => [], + (): TreeDataItem[] => [ + { + id: 'top-separator', + name: '', + type: 'separator', + }, { id: 'project', name: 'Default Project', @@ -334,24 +325,38 @@ export const projectTreeLogic = kea([ newPath: folder, }) }, - toggleFolder: ({ folder, isExpanded }) => { + toggleFolderOpen: ({ folderId, isExpanded }) => { if (isExpanded) { - actions.updateExpandedFolders(values.expandedFolders.filter((f) => f !== folder)) + actions.updateExpandedFolders(values.expandedFolders.filter((f) => f !== folderId)) } else { - actions.updateExpandedFolders([...values.expandedFolders, folder]) + actions.updateExpandedFolders([...values.expandedFolders, folderId]) } }, - updateSelectedFolder: ({ folder }) => { - actions.updateActiveFolder(folder) - actions.updateLastViewedPath(folder) + cancelPendingActions: () => { + // Clear all pending actions without applying them + for (const action of values.pendingActions) { + actions.removeQueuedAction(action) + } }, })), - afterMount(({ actions }) => { + afterMount(({ actions, cache }) => { actions.loadSavedItems() actions.loadUnfiledItems('feature_flag') actions.loadUnfiledItems('experiment') actions.loadUnfiledItems('insight') actions.loadUnfiledItems('dashboard') actions.loadUnfiledItems('notebook') + + // register keyboard shortcuts + cache.onKeyDown = (event: KeyboardEvent) => { + if (shouldIgnoreInput(event)) { + return + } + if (event.key === 'Escape') { + event.preventDefault() + actions.toggleDragAndDrop(false) + } + } + window.addEventListener('keydown', cache.onKeyDown) }), ]) diff --git a/frontend/src/lib/lemon-ui/LemonTree/LemonTree.stories.tsx b/frontend/src/lib/lemon-ui/LemonTree/LemonTree.stories.tsx index 425865012d5fa..29fc100127550 100644 --- a/frontend/src/lib/lemon-ui/LemonTree/LemonTree.stories.tsx +++ b/frontend/src/lib/lemon-ui/LemonTree/LemonTree.stories.tsx @@ -24,11 +24,15 @@ const meta: Meta = { }, showFolderActiveState: false, expandAllFolders: false, - // defaultSelectedFolderOrNodeId: 'pis_n3o4p', + defaultSelectedFolderOrNodeId: 'pis_n3o4p', data: [ { - id: 'gt_7d8f9', + id: 'xxxxxxxxxxxxxx', name: 'Growth team', + record: { + type: 'folder', + path: 'Growth team', + }, children: [ { id: 'gsm_a1b2c', @@ -37,31 +41,55 @@ const meta: Meta = { // eslint-disable-next-line no-console console.log('clicked growth support metrics', open) }, + record: { + type: 'file', + path: 'Growth team/Growth Support Metrics', + }, }, { id: 'ssc_3d4e5', name: 'Self-serve credits', icon: , disabledReason: "you're not cool enough", + record: { + type: 'file', + path: 'Growth team/Self-serve credits', + }, }, { id: 'ot_f6g7h', name: 'Onboarding things', + record: { + type: 'folder', + path: 'Growth team/Onboarding things', + }, children: [ { id: 'cf_8i9j0', name: 'Conversion funnel', icon: , + record: { + type: 'file', + path: 'Growth team/Onboarding things/Conversion funnel', + }, }, { id: 'mpu_k1l2m', name: 'Multi-product usage', icon: , + record: { + type: 'file', + path: 'Growth team/Onboarding things/Multi-product usage', + }, }, { id: 'pis_n3o4p', name: 'Post-install survey', icon: , + record: { + type: 'file', + path: 'Growth team/Onboarding things/Post-install survey', + }, }, ], }, @@ -69,37 +97,65 @@ const meta: Meta = { id: 'ob2_q5r6s', name: 'Onboarding 2.0', disabledReason: "you're not cool enough", + record: { + type: 'folder', + path: 'Growth team/Onboarding 2.0', + }, children: [ { id: 'hsc_t7u8v', name: 'Hypothesis & success criteria', icon: , + record: { + type: 'file', + path: 'Growth team/Onboarding 2.0/Hypothesis & success criteria', + }, }, { id: 'ob2a_w9x0y', name: 'Onboarding 2.0', icon: , + record: { + type: 'file', + path: 'Growth team/Onboarding 2.0/Onboarding 2.0', + }, }, { id: 'ob2b_z1a2b', name: 'Onboarding 2.0', icon: , + record: { + type: 'file', + path: 'Growth team/Onboarding 2.0/Onboarding 2.0', + }, }, { id: 'ob2c_c3d4e', name: 'Onboarding 2.0', icon: , + record: { + type: 'file', + path: 'Growth team/Onboarding 2.0/Onboarding 2.0', + }, }, ], }, { id: 'bt_f5g6h', name: 'Billing test', + record: { + type: 'folder', + path: 'Growth team/Billing test', + }, children: [ { id: 'os_i7j8k', name: 'other stuff', icon: , + record: { + type: 'file', + path: 'Growth team/Billing test/other stuff', + }, }, ], }, @@ -108,18 +164,34 @@ const meta: Meta = { { id: 'et_l9m0n', name: 'Exec team', + record: { + type: 'file', + path: 'Exec team', + }, }, { id: 'wv_o1p2q', name: 'Website & vibes', + record: { + type: 'file', + path: 'Website & vibes', + }, }, { id: 'pa_r3s4t', name: 'Product analytics', + record: { + type: 'file', + path: 'Product analytics', + }, }, { id: 'uf_u5v6w', - name: 'Unfilled', + name: 'Unfiled', + record: { + type: 'file', + path: 'Unfiled', + }, }, ], }, diff --git a/frontend/src/lib/lemon-ui/LemonTree/LemonTree.tsx b/frontend/src/lib/lemon-ui/LemonTree/LemonTree.tsx index 42452508c7de4..4ca17dccba189 100644 --- a/frontend/src/lib/lemon-ui/LemonTree/LemonTree.tsx +++ b/frontend/src/lib/lemon-ui/LemonTree/LemonTree.tsx @@ -5,6 +5,7 @@ import { ScrollableShadows } from 'lib/components/ScrollableShadows/ScrollableSh import { cn } from 'lib/utils/css-classes' import { forwardRef, HTMLAttributes, useCallback, useEffect, useRef, useState } from 'react' +import { ContextMenu, ContextMenuContent, ContextMenuTrigger } from '../../ui/ContextMenu/ContextMenu' import { LemonButton, SideAction } from '../LemonButton' import { Spinner } from '../Spinner/Spinner' import { getIcon, TreeNodeDraggable, TreeNodeDroppable } from './LemonTreeUtils' @@ -24,6 +25,8 @@ export type TreeDataItem = { children?: TreeDataItem[] /** Disabled: The reason the item is disabled. */ disabledReason?: string + + type?: 'node' | 'separator' /** * Handle a click on the item. * @param open - boolean to indicate if it's a folder and it's open state @@ -50,6 +53,8 @@ type LemonTreeBaseProps = Omit, 'onDragEnd'> & { isItemDroppable?: (item: TreeDataItem) => boolean /** The side action to render for the item. */ itemSideAction?: (item: TreeDataItem) => SideAction | undefined + /** The context menu to render for the item. */ + itemContextMenu?: (item: TreeDataItem) => React.ReactNode /** Whether the item is loading */ isItemLoading?: (item: TreeDataItem) => boolean /** Whether the item is unapplied */ @@ -84,6 +89,8 @@ export type LemonTreeNodeProps = LemonTreeBaseProps & { handleClick: (item: TreeDataItem | undefined, isKeyboardAction?: boolean) => void /** The depth of the item. */ depth?: number + /** Whether the context menu is open */ + onContextMenuOpen?: (open: boolean) => void } const LemonTreeNode = forwardRef( @@ -104,45 +111,51 @@ const LemonTreeNode = forwardRef( depth = 0, itemSideAction, enableDragAndDrop = false, + onContextMenuOpen, + itemContextMenu, ...props }, ref ): JSX.Element => { const DEPTH_OFFSET = 4 + 8 * depth // 4 is .25rem to match lemon button padding x axis - // Handle meta key to enable dragging - const [isModifierKeyPressed, setIsModifierKeyPressed] = useState(false) + const [isContextMenuOpenForItem, setIsContextMenuOpenForItem] = useState(undefined) if (!(data instanceof Array)) { data = [data] } - // TODO: move this keydown listener to the parent component - useEffect(() => { - const handleKeyDown = (e: KeyboardEvent): void => { - if (e.metaKey || e.ctrlKey) { - setIsModifierKeyPressed(true) - } - } - - const handleKeyUp = (e: KeyboardEvent): void => { - if (!e.metaKey && !e.ctrlKey) { - setIsModifierKeyPressed(false) - } - } - - window.addEventListener('keydown', handleKeyDown) - window.addEventListener('keyup', handleKeyUp) + function handleContextMenuOpen(open: boolean, itemId: string): void { + // Set local state + setIsContextMenuOpenForItem(open ? itemId : undefined) - return () => { - window.removeEventListener('keydown', handleKeyDown) - window.removeEventListener('keyup', handleKeyUp) - } - }, []) + // Tell parent that the context menu is open + onContextMenuOpen?.(open) + } return (
      {data.map((item) => { + if (item.type === 'separator') { + return ( +
      +
      +
      + ) + } + + let cursorClass = 'cursor-pointer' + + if (enableDragAndDrop) { + if (isItemDraggable?.(item)) { + cursorClass = 'cursor-grab' + } else { + cursorClass = 'cursor-not-allowed' + } + } else { + cursorClass = 'cursor-pointer' + } + const content = ( ( > - handleClick(item)} - onKeyDown={(e) => e.key === 'Enter' && handleClick(item, true)} - type="tertiary" - role="treeitem" - tabIndex={-1} - size="small" - fullWidth - data-id={item.id} - active={ - selectedId === item.id || - (showFolderActiveState && - item.children && - expandedItemIds?.includes(item.id)) - } - icon={getIcon({ - item, - expandedItemIds: expandedItemIds ?? [], - defaultNodeIcon, - })} - disabledReason={item.disabledReason} - tooltipPlacement="right" - style={{ paddingLeft: `${DEPTH_OFFSET}px` }} - truncate - tooltip={item.name} - sideAction={itemSideAction ? itemSideAction(item) : undefined} + { + handleContextMenuOpen(open, item.id) + }} > - - {renderItem ? ( - <> - {renderItem(item, item.name)} - {item.record?.loading && } - {item.record?.unapplied && ( - + + { + if (!enableDragAndDrop) { + handleClick(item) + } + }} + onKeyDown={(e) => e.key === 'Enter' && handleClick(item, true)} + type="tertiary" + role="treeitem" + tabIndex={-1} + size="small" + fullWidth + data-id={item.id} + active={ + selectedId === item.id || + (showFolderActiveState && + item.children && + expandedItemIds?.includes(item.id)) + } + icon={getIcon({ + item, + expandedItemIds: expandedItemIds ?? [], + defaultNodeIcon, + })} + // disabledReason={item.disabledReason} + disabled={!isItemDraggable?.(item) && enableDragAndDrop} + tooltipPlacement="right" + style={{ paddingLeft: `${DEPTH_OFFSET}px` }} + truncate + tooltip={item.name} + sideAction={itemSideAction ? itemSideAction(item) : undefined} + > + + {renderItem ? ( + <> + {renderItem(item, item.name)} + {item.record?.loading && } + {item.record?.unapplied && ( + + )} + + ) : ( + item.name )} - - ) : ( - item.name - )} - - + + + + + {isContextMenuOpenForItem === item.id && itemContextMenu?.(item) ? ( + {itemContextMenu(item)} + ) : null} + {item.children && ( - {/* Depth line */} -
      ( isItemDraggable={isItemDraggable} isItemDroppable={isItemDroppable} enableDragAndDrop={enableDragAndDrop} + onContextMenuOpen={onContextMenuOpen} + itemContextMenu={itemContextMenu} {...props} /> @@ -250,18 +277,18 @@ const LemonTreeNode = forwardRef( if (isItemDraggable?.(item)) { wrappedContent = ( - - + + {wrappedContent} ) } else if (isItemDroppable?.(item)) { wrappedContent = ( - + {wrappedContent} ) @@ -294,22 +321,28 @@ const LemonTree = forwardRef( isItemDroppable, itemSideAction, enableDragAndDrop = false, + itemContextMenu, + isFinishedBuildingTreeData, ...props }, ref ): JSX.Element => { const TYPE_AHEAD_TIMEOUT = 500 + // Scrollable container + const containerRef = useRef(null) const [selectedId, setSelectedId] = useState(defaultSelectedFolderOrNodeId) const [focusedId, setFocusedId] = useState(defaultSelectedFolderOrNodeId) + const [hasFocusedContent, setHasFocusedContent] = useState(false) // Add new state for type-ahead const [typeAheadBuffer, setTypeAheadBuffer] = useState('') const typeAheadTimeoutRef = useRef() + const [isNodeTreeContextMenuOpen, setIsNodeTreeContextMenuOpen] = useState(false) function collectAllFolderIds(items: TreeDataItem[] | TreeDataItem, allIds: string[]): void { if (items instanceof Array) { items.forEach((item) => { - if (!item.disabledReason && item.record?.type === 'folder') { + if (!item.disabledReason && item.children) { allIds.push(item.id) } if (item.children) { @@ -317,7 +350,7 @@ const LemonTree = forwardRef( } }) } else { - if (!items.disabledReason && items.record?.type === 'folder') { + if (!items.disabledReason && items.children) { allIds.push(items.id) } if (items.children) { @@ -374,7 +407,7 @@ const LemonTree = forwardRef( nodeArray.forEach((node) => { items.push(node) - if (node.children && expandedItemIds?.includes(node.id)) { + if (node.children && expandedItemIdsState?.includes(node.id)) { traverse(node.children) } }) @@ -382,13 +415,14 @@ const LemonTree = forwardRef( traverse(data) return items - }, [data, expandedItemIds]) + }, [data, expandedItemIdsState]) // Focus on provided content ref const focusContent = useCallback(() => { if (contentRef?.current) { contentRef.current.focus() setFocusedId(undefined) // Remove focus from tree when moving to content + setHasFocusedContent(true) } }, [contentRef]) @@ -411,6 +445,11 @@ const LemonTree = forwardRef( // Add function to handle type-ahead search const handleTypeAhead = useCallback( (char: string) => { + // Don't allow typeahead when context menu is open + if (isNodeTreeContextMenuOpen) { + return + } + // Clear existing timeout if (typeAheadTimeoutRef.current) { clearTimeout(typeAheadTimeoutRef.current) @@ -442,8 +481,9 @@ const LemonTree = forwardRef( // If item is in a collapsed folder, expand the path to it const path = findPathToItem(Array.isArray(data) ? data : [data], match.id) if (path.length > 0) { - setExpandedItemIdsState([...new Set([...expandedItemIdsState, ...path])]) - onSetExpandedItemIds && onSetExpandedItemIds([...new Set([...expandedItemIdsState, ...path])]) + const newExpandedIds = [...new Set([...expandedItemIdsState, ...path])] + setExpandedItemIdsState(newExpandedIds) + onSetExpandedItemIds && onSetExpandedItemIds(newExpandedIds) } } }, @@ -455,6 +495,7 @@ const LemonTree = forwardRef( findPathToItem, onSetExpandedItemIds, expandedItemIdsState, + isNodeTreeContextMenuOpen, ] ) @@ -463,8 +504,10 @@ const LemonTree = forwardRef( // Update focusedId when clicking setFocusedId(item?.id) + const isFolder = item?.children && item?.children?.length >= 0 + // Handle click on a node - if (item?.record?.type === 'file') { + if (!isFolder) { if (onNodeClick) { setSelectedId(item?.id) onNodeClick(item) @@ -474,10 +517,15 @@ const LemonTree = forwardRef( focusContent() } } - } else if (item?.record?.type === 'folder') { + } else if (isFolder) { // Handle click on a folder if (onFolderClick) { - onFolderClick(item, !expandedItemIdsState.includes(item.id)) + // Update expanded state + const newExpandedIds = expandedItemIdsState.includes(item.id) + ? expandedItemIdsState.filter((id) => id !== item.id) + : [...expandedItemIdsState, item.id] + setExpandedItemIdsState(newExpandedIds) + onFolderClick(item, expandedItemIdsState.includes(item.id)) } } if (item?.onClick) { @@ -492,6 +540,11 @@ const LemonTree = forwardRef( // Update handleKeyDown to include type-ahead const handleKeyDown = useCallback( (e: React.KeyboardEvent) => { + // Don't allow keyboard navigation when context menu is open + if (isNodeTreeContextMenuOpen) { + return + } + // Handle single printable characters for type-ahead if (e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) { handleTypeAhead(e.key) @@ -512,11 +565,16 @@ const LemonTree = forwardRef( e.preventDefault() const currentItem = visibleItems[currentIndex] // Expand folder if current item is an unexpanded, non-disabled folder - if (currentItem?.children && !currentItem.disabledReason) { + if ( + currentItem?.children && + currentItem?.children?.length >= 0 && + !currentItem.disabledReason + ) { // If folder is not expanded, expand it if (!expandedItemIdsState.includes(currentItem.id)) { - setExpandedItemIdsState([...expandedItemIdsState, currentItem.id]) - onSetExpandedItemIds && onSetExpandedItemIds([...expandedItemIdsState, currentItem.id]) + const newExpandedIds = [...new Set([...expandedItemIdsState, currentItem.id])] + setExpandedItemIdsState(newExpandedIds) + onSetExpandedItemIds && onSetExpandedItemIds(newExpandedIds) } else { // If folder is already expanded, focus first child const nextItem = visibleItems[currentIndex + 1] @@ -537,10 +595,14 @@ const LemonTree = forwardRef( const currentItem = visibleItems[currentIndex] // If current item is an expanded folder, collapse it - if (currentItem?.children && expandedItemIdsState.includes(currentItem.id)) { - setExpandedItemIdsState(expandedItemIdsState.filter((id) => id !== currentItem.id)) - onSetExpandedItemIds && - onSetExpandedItemIds(expandedItemIdsState.filter((id) => id !== currentItem.id)) + if ( + currentItem?.children && + currentItem?.children?.length >= 0 && + expandedItemIdsState.includes(currentItem.id) + ) { + const newExpandedIds = expandedItemIdsState.filter((id) => id !== currentItem.id) + setExpandedItemIdsState(newExpandedIds) + onSetExpandedItemIds && onSetExpandedItemIds(newExpandedIds) return } @@ -585,7 +647,6 @@ const LemonTree = forwardRef( // If no item is focused, focus the first item if (visibleItems.length > 0) { setFocusedId(visibleItems[0].id) - setSelectedId(undefined) } } else if (currentIndex < visibleItems.length - 1) { setFocusedId(visibleItems[currentIndex + 1].id) @@ -602,7 +663,6 @@ const LemonTree = forwardRef( // If no item is focused, focus the first item if (visibleItems.length > 0) { setFocusedId(visibleItems[0].id) - setSelectedId(undefined) } } else if (currentIndex > 0) { // Otherwise move focus to previous item @@ -641,21 +701,17 @@ const LemonTree = forwardRef( // Skip if item is disabled if (!currentItem.disabledReason) { - if (currentItem.children) { - // Handle folder click - handleClick(currentItem, true) - + if (currentItem.children && currentItem.children?.length >= 0) { // Toggle folder expanded state if (expandedItemIdsState.includes(currentItem.id)) { + onFolderClick?.(currentItem, false) // Close folder by removing from expanded IDs setExpandedItemIdsState(expandedItemIdsState.filter((id) => id !== currentItem.id)) - onSetExpandedItemIds && - onSetExpandedItemIds(expandedItemIdsState.filter((id) => id !== currentItem.id)) } else { + onFolderClick?.(currentItem, true) // Open folder by adding to expanded IDs - setExpandedItemIdsState([...expandedItemIdsState, currentItem.id]) - onSetExpandedItemIds && - onSetExpandedItemIds([...expandedItemIdsState, currentItem.id]) + const newExpandedIds = [...new Set([...expandedItemIdsState, currentItem.id])] + setExpandedItemIdsState(newExpandedIds) } } else { if (onNodeClick) { @@ -685,15 +741,68 @@ const LemonTree = forwardRef( handleTypeAhead, data, focusContent, - handleClick, onNodeClick, + onFolderClick, onSetExpandedItemIds, + isNodeTreeContextMenuOpen, ] ) + // Add function to scroll focused item into view + const scrollFocusedIntoView = useCallback(() => { + if (!containerRef.current) { + return + } + + // Look for either focused or selected element + const elementId = focusedId || selectedId + if (!elementId) { + return + } + + // Find the element + const element = containerRef.current.querySelector(`[data-id="${elementId}"]`) + if (!element) { + return + } + + // Get container bounds + const containerBounds = containerRef.current.getBoundingClientRect() + const elementBounds = element.getBoundingClientRect() + + // Calculate if element is outside visible area + const SCROLL_PADDING = 64 + const isAboveFold = elementBounds.top - SCROLL_PADDING < containerBounds.top + const isBelowFold = elementBounds.bottom + SCROLL_PADDING > containerBounds.bottom + + if (isAboveFold || isBelowFold) { + element.scrollIntoView({ + block: 'nearest', + behavior: 'smooth', + }) + } + }, [selectedId, focusedId]) + + // Scroll to focused item when tree is finished building or prop is not provided + useEffect(() => { + if (isFinishedBuildingTreeData ?? true) { + scrollFocusedIntoView() + } + }, [scrollFocusedIntoView, isFinishedBuildingTreeData]) + + useEffect(() => { + // On prop change, set focusedId if it's not already focused + // if the content has been focused (via keyboard), don't focus the tree + if (defaultSelectedFolderOrNodeId && !hasFocusedContent) { + setFocusedId(defaultSelectedFolderOrNodeId) + setSelectedId(defaultSelectedFolderOrNodeId) + } + }, [defaultSelectedFolderOrNodeId, hasFocusedContent]) + return ( ( className="flex-1" innerClassName="p-2" > - + { + // Set local state + setExpandedItemIdsState(ids) + // Call prop callback if provided + onSetExpandedItemIds?.(ids) + }} defaultNodeIcon={defaultNodeIcon} showFolderActiveState={showFolderActiveState} itemSideAction={itemSideAction} @@ -723,6 +837,10 @@ const LemonTree = forwardRef( isItemDraggable={isItemDraggable} isItemDroppable={isItemDroppable} enableDragAndDrop={enableDragAndDrop} + onContextMenuOpen={(open) => { + setIsNodeTreeContextMenuOpen(open) + }} + itemContextMenu={itemContextMenu} {...props} /> diff --git a/frontend/src/lib/ui/Colors/Colors.stories.tsx b/frontend/src/lib/ui/Colors/Colors.stories.tsx index 915d39defff4b..13d62f04db94e 100644 --- a/frontend/src/lib/ui/Colors/Colors.stories.tsx +++ b/frontend/src/lib/ui/Colors/Colors.stories.tsx @@ -6,7 +6,7 @@ import { useEffect, useState } from 'react' import { themeLogic } from '~/layout/navigation-3000/themeLogic' const meta: Meta = { - title: 'Design System/Colors', + title: 'UI/Colors', parameters: { docs: { description: { diff --git a/frontend/src/lib/ui/ContextMenu/ContextMenu.stories.tsx b/frontend/src/lib/ui/ContextMenu/ContextMenu.stories.tsx new file mode 100644 index 0000000000000..20ffec05d73b2 --- /dev/null +++ b/frontend/src/lib/ui/ContextMenu/ContextMenu.stories.tsx @@ -0,0 +1,79 @@ +import { Meta, StoryFn, StoryObj } from '@storybook/react' + +import { + ContextMenu, + ContextMenuCheckboxItem, + ContextMenuContent, + ContextMenuItem, + ContextMenuLabel, + ContextMenuRadioGroup, + ContextMenuRadioItem, + ContextMenuSeparator, + ContextMenuShortcut, + ContextMenuSub, + ContextMenuSubContent, + ContextMenuSubTrigger, + ContextMenuTrigger, +} from './ContextMenu' + +type Story = StoryObj +const meta: Meta = { + title: 'UI/Context Menu', + component: ContextMenu, + args: {}, + tags: ['autodocs'], +} +export default meta + +const BasicTemplate: StoryFn = (props: React.ComponentProps) => { + return ( + + + Right click here + + + + Back + ⌘[ + + + Forward + ⌘] + + + Reload + ⌘R + + + More Tools + + + Save Page As... + ⇧⌘S + + Create Shortcut... + Name Window... + + Developer Tools + + + + + Show Bookmarks Bar + ⌘⇧B + + Show Full URLs + + + People + + Pedro Duarte + Colm Tuite + + + + ) +} + +export const Default: Story = BasicTemplate.bind({}) +Default.args = {} diff --git a/frontend/src/lib/ui/ContextMenu/ContextMenu.tsx b/frontend/src/lib/ui/ContextMenu/ContextMenu.tsx new file mode 100644 index 0000000000000..8f972f566d16a --- /dev/null +++ b/frontend/src/lib/ui/ContextMenu/ContextMenu.tsx @@ -0,0 +1,195 @@ +'use client' + +import { IconCheckCircle, IconChevronRight } from '@posthog/icons' +import * as ContextMenuPrimitive from '@radix-ui/react-context-menu' +import { cn } from 'lib/utils/css-classes' +import * as React from 'react' + +const ContextMenu = ContextMenuPrimitive.Root + +const ContextMenuTrigger = ContextMenuPrimitive.Trigger + +const ContextMenuGroup = ContextMenuPrimitive.Group + +const ContextMenuPortal = ContextMenuPrimitive.Portal + +const ContextMenuSub = ContextMenuPrimitive.Sub + +const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup + +const ContextMenuSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>( + ({ className, inset, children, ...props }, ref): JSX.Element => ( + + {children} + + + ) +) +ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName + +const ContextMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>( + ({ className, ...props }, ref): JSX.Element => ( + + ) +) +ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName + +const ContextMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>( + ({ className, ...props }, ref): JSX.Element => ( + + + + ) +) +ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName + +const ContextMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>( + ({ className, inset, ...props }, ref): JSX.Element => ( + + ) +) +ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName + +const ContextMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>( + ({ className, children, checked, ...props }, ref): JSX.Element => ( + + + + + + + {children} + + ) +) +ContextMenuCheckboxItem.displayName = ContextMenuPrimitive.CheckboxItem.displayName + +const ContextMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>( + ({ className, children, ...props }, ref): JSX.Element => ( + + + +
      + + + {children} + + ) +) +ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName + +const ContextMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>( + ({ className, inset, ...props }, ref): JSX.Element => ( + + ) +) +ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName + +const ContextMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>( + ({ className, ...props }, ref): JSX.Element => ( + + ) +) +ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName + +const ContextMenuShortcut = ({ className, ...props }: React.HTMLAttributes): JSX.Element => { + return +} +ContextMenuShortcut.displayName = 'ContextMenuShortcut' + +export { + ContextMenu, + ContextMenuCheckboxItem, + ContextMenuContent, + ContextMenuGroup, + ContextMenuItem, + ContextMenuLabel, + ContextMenuPortal, + ContextMenuRadioGroup, + ContextMenuRadioItem, + ContextMenuSeparator, + ContextMenuShortcut, + ContextMenuSub, + ContextMenuSubContent, + ContextMenuSubTrigger, + ContextMenuTrigger, +} diff --git a/frontend/src/styles/base.scss b/frontend/src/styles/base.scss index a6f4868468746..9e1275542c370 100644 --- a/frontend/src/styles/base.scss +++ b/frontend/src/styles/base.scss @@ -395,6 +395,12 @@ --bg-fill-primary: var(--color-white); --bg-fill-secondary: var(--primitive-3000-25); --bg-fill-tertiary: var(--primitive-3000-50); + --bg-fill-highlight-100: color-mix(in oklab, var(--color-black) 10%, transparent); + --bg-fill-highlight-150: color-mix(in oklab, var(--color-black) 15%, transparent); + --bg-fill-highlight-200: color-mix(in oklab, var(--color-black) 20%, transparent); + --bg-fill-highlight-inverse-100: color-mix(in oklab, var(--color-white) 10%, transparent); + --bg-fill-highlight-inverse-150: color-mix(in oklab, var(--color-white) 15%, transparent); + --bg-fill-highlight-inverse-200: color-mix(in oklab, var(--color-white) 20%, transparent); // Highlights --bg-fill-primary-highlight: color-mix( @@ -571,6 +577,7 @@ // this allows us to place some modals on top of others // we should never be forgiven // if we ever need more than 7 modals active at the same time + --z-top: 9999; --z-modal: 1100; --z-hedgehog-buddy: 1050; --z-annotation-popover: 100; @@ -822,6 +829,12 @@ --bg-fill-primary: var(--primitive-neutral-cool-900); --bg-fill-secondary: var(--primitive-neutral-cool-850); --bg-fill-tertiary: var(--primitive-neutral-cool-800); + --bg-fill-highlight-100: color-mix(in oklab, var(--color-white) 10%, transparent); + --bg-fill-highlight-inverse-100: color-mix(in oklab, var(--color-black) 10%, transparent); + --bg-fill-highlight-150: color-mix(in oklab, var(--color-white) 15%, transparent); + --bg-fill-highlight-inverse-150: color-mix(in oklab, var(--color-black) 15%, transparent); + --bg-fill-highlight-200: color-mix(in oklab, var(--color-white) 20%, transparent); + --bg-fill-highlight-inverse-200: color-mix(in oklab, var(--color-black) 20%, transparent); --bg-fill-info-secondary: var(--color-blue-950); --bg-fill-info-tertiary: var(--color-blue-950); --bg-fill-warning-secondary: var(--color-yellow-950); diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index 47b9aa854d672..c0f8711324c46 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -153,6 +153,7 @@ const deprecatedColors = { 'lifecycle-dormant-hover': 'var(--lifecycle-dormant-hover)', // Z-indexes + 'z-top': 'var(--z-top)', 'z-bottom-notice': 'var(--z-bottom-notice)', 'z-command-palette': 'var(--z-command-palette)', 'z-force-modal-above-popovers': 'var(--z-force-modal-above-popovers)', @@ -628,11 +629,18 @@ const config = { 'surface-secondary': 'var(--bg-surface-secondary)', 'surface-tertiary': 'var(--bg-surface-tertiary)', 'surface-tooltip': 'var(--bg-surface-tooltip)', + 'surface-tooltip-inverse': 'var(--bg-surface-tooltip-inverse)', 'surface-popover': 'var(--bg-surface-popover)', - + 'surface-popover-inverse': 'var(--bg-surface-popover-inverse)', 'fill-primary': 'var(--bg-fill-primary)', 'fill-secondary': 'var(--bg-fill-secondary)', 'fill-tertiary': 'var(--bg-fill-tertiary)', + 'fill-highlight-100': 'var(--bg-fill-highlight-100)', + 'fill-highlight-inverse-100': 'var(--bg-fill-highlight-inverse-100)', + 'fill-highlight-150': 'var(--bg-fill-highlight-150)', + 'fill-highlight-inverse-150': 'var(--bg-fill-highlight-inverse-150)', + 'fill-highlight-200': 'var(--bg-fill-highlight-200)', + 'fill-highlight-inverse-200': 'var(--bg-fill-highlight-inverse-200)', 'fill-primary-highlight': 'var(--bg-fill-primary-highlight)', 'fill-info-secondary': 'var(--bg-fill-info-secondary)', 'fill-info-tertiary': 'var(--bg-fill-info-tertiary)', @@ -766,6 +774,9 @@ const config = { 2: '2 2 0%', 3: '3 3 0%', }, + zIndex: { + 'top': 'var(--z-top)', + }, }, }, plugins: [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cca84414e6467..12d592b429758 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,10 +39,10 @@ importers: devDependencies: '@parcel/packager-ts': specifier: 2.13.3 - version: 2.13.3(@parcel/core@2.13.3) + version: 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15)) '@parcel/transformer-typescript-types': specifier: 2.13.3 - version: 2.13.3(@parcel/core@2.13.3)(typescript@4.9.5) + version: 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))(typescript@4.9.5) eslint: specifier: ^8.57.0 version: 8.57.0 @@ -63,7 +63,7 @@ importers: version: 2.29.0(@typescript-eslint/parser@7.1.1(eslint@8.57.0)(typescript@4.9.5))(eslint@8.57.0) eslint-plugin-jest: specifier: ^28.6.0 - version: 28.6.0(@typescript-eslint/eslint-plugin@7.1.1(@typescript-eslint/parser@7.1.1(eslint@8.57.0)(typescript@4.9.5))(eslint@8.57.0)(typescript@4.9.5))(eslint@8.57.0)(jest@29.7.0)(typescript@4.9.5) + version: 28.6.0(@typescript-eslint/eslint-plugin@7.1.1(@typescript-eslint/parser@7.1.1(eslint@8.57.0)(typescript@4.9.5))(eslint@8.57.0)(typescript@4.9.5))(eslint@8.57.0)(jest@29.7.0(@types/node@18.18.4)(ts-node@10.9.1(@swc/core@1.11.4(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5)))(typescript@4.9.5) eslint-plugin-posthog: specifier: workspace:* version: link:common/eslint_rules @@ -96,7 +96,7 @@ importers: version: 4.3.0(stylelint@15.11.0(typescript@4.9.5)) stylelint-config-standard-scss: specifier: ^11.1.0 - version: 11.1.0(postcss@8.5.2)(stylelint@15.11.0(typescript@4.9.5)) + version: 11.1.0(postcss@8.4.31)(stylelint@15.11.0(typescript@4.9.5)) stylelint-order: specifier: ^6.0.3 version: 6.0.3(stylelint@15.11.0(typescript@4.9.5)) @@ -195,7 +195,7 @@ importers: version: 3.12.1 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@18.18.4)(ts-node@10.9.1(@swc/core@1.10.14(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5)) + version: 29.7.0(@types/node@18.18.4)(ts-node@10.9.1(@swc/core@1.11.4(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5)) parcel: specifier: ^2.13.3 version: 2.13.3(@swc/helpers@0.5.15)(cssnano@7.0.6(postcss@8.5.2))(postcss@8.5.2)(relateurl@0.2.7)(svgo@3.3.2)(terser@5.19.1)(typescript@4.9.5) @@ -303,7 +303,7 @@ importers: version: 7.6.4(@babel/core@7.26.0)(@swc/core@1.11.4(@swc/helpers@0.5.15))(@swc/helpers@0.5.15)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(type-fest@3.5.3)(typescript@4.9.5)(webpack-cli@5.1.4)(webpack-hot-middleware@2.25.4) '@storybook/test-runner': specifier: ^0.16.0 - version: 0.16.0(@swc/helpers@0.5.15)(encoding@0.1.13) + version: 0.16.0(@swc/helpers@0.5.15)(@types/node@18.18.4)(encoding@0.1.13)(ts-node@10.9.1(@swc/core@1.11.4(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5)) '@storybook/theming': specifier: ^7.6.4 version: 7.6.20(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -369,7 +369,7 @@ importers: version: 7.24.0 '@cypress/webpack-preprocessor': specifier: ^6.0.2 - version: 6.0.2(@babel/core@7.26.0)(@babel/preset-env@7.23.5(@babel/core@7.26.0))(babel-loader@8.3.0(@babel/core@7.26.0)(webpack@5.88.2))(webpack@5.88.2) + version: 6.0.2(@babel/core@7.26.0)(@babel/preset-env@7.23.5(@babel/core@7.26.0))(babel-loader@8.3.0(@babel/core@7.26.0)(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))))(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))) '@posthog/frontend': specifier: workspace:* version: link:../frontend @@ -378,7 +378,7 @@ importers: version: link:../common/storybook css-loader: specifier: '*' - version: 3.6.0(webpack@5.88.2) + version: 3.6.0(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))) cypress: specifier: ^13.11.0 version: 13.11.0 @@ -396,28 +396,28 @@ importers: version: link:../common/eslint_rules file-loader: specifier: '*' - version: 6.2.0(webpack@5.88.2) + version: 6.2.0(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))) less-loader: specifier: '*' - version: 7.3.0(less@4.2.2)(webpack@5.88.2) + version: 7.3.0(less@4.2.2)(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))) postcss-loader: specifier: '*' - version: 4.3.0(postcss@8.5.2)(webpack@5.88.2) + version: 4.3.0(postcss@8.5.2)(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))) posthog-js: specifier: '*' version: 1.217.2 sass-loader: specifier: '*' - version: 10.3.1(sass@1.56.0)(webpack@5.88.2) + version: 10.3.1(sass@1.56.0)(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))) style-loader: specifier: '*' - version: 2.0.0(webpack@5.88.2) + version: 2.0.0(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))) typescript: specifier: ~4.9.5 version: 4.9.5 webpack: specifier: '*' - version: 5.88.2 + version: 5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15)) devDependencies: '@babel/core': specifier: ^7.22.10 @@ -448,7 +448,7 @@ importers: version: 7.23.3(@babel/core@7.26.0) babel-loader: specifier: ^8.0.6 - version: 8.3.0(@babel/core@7.26.0)(webpack@5.88.2) + version: 8.3.0(@babel/core@7.26.0)(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))) babel-plugin-import: specifier: ^1.13.0 version: 1.13.8 @@ -573,6 +573,12 @@ importers: '@radix-ui/react-accordion': specifier: ^1.2.2 version: 1.2.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-context-menu': + specifier: ^2.2.6 + version: 2.2.6(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-slot': + specifier: ^1.1.2 + version: 1.1.2(@types/react@17.0.52)(react@18.2.0) '@react-hook/size': specifier: ^2.1.2 version: 2.1.2(react@18.2.0) @@ -1535,7 +1541,7 @@ importers: version: link:../../common/eslint_rules jest: specifier: '*' - version: 29.7.0(@types/node@18.18.4)(ts-node@10.9.1(@swc/core@1.10.14(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5)) + version: 29.7.0(@types/node@18.18.4)(ts-node@10.9.1(@swc/core@1.11.4(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5)) kea: specifier: '*' version: 3.1.5(react@18.2.0) @@ -4190,6 +4196,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-arrow@1.1.2': + resolution: {integrity: sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==} + 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-collapsible@1.1.2': resolution: {integrity: sha512-PliMB63vxz7vggcyq0IxNYk8vGDrLXVWw4+W4B8YnwI1s18x7YZYqlG9PLX7XxAJUi0g2DxP4XKJMFHh/iVh9A==} peerDependencies: @@ -4229,6 +4248,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-collection@1.1.2': + resolution: {integrity: sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==} + 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-compose-refs@1.0.1': resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} peerDependencies: @@ -4247,6 +4279,19 @@ packages: '@types/react': optional: true + '@radix-ui/react-context-menu@2.2.6': + resolution: {integrity: sha512-aUP99QZ3VU84NPsHeaFt4cQUNgJqFsLLOt/RbbWXszZ6MP0DpDyjkFZORr4RpAEx3sUBk+Kc8h13yGtC5Qw8dg==} + 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-context@1.0.1': resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} peerDependencies: @@ -4296,6 +4341,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-dismissable-layer@1.1.5': + resolution: {integrity: sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==} + 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: @@ -4305,6 +4363,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.3': resolution: {integrity: sha512-upXdPfqI4islj2CslyfUBNlaJCPybbqRHAi1KER7Isel9Q2AtSJ0zRBZv8mWQiFXD2nyAJ4BhC3yXgZ6kMBSrQ==} peerDependencies: @@ -4318,6 +4385,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-focus-scope@1.1.2': + resolution: {integrity: sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==} + 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-id@1.0.1': resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==} peerDependencies: @@ -4336,6 +4416,19 @@ packages: '@types/react': optional: true + '@radix-ui/react-menu@2.1.6': + resolution: {integrity: sha512-tBBb5CXDJW3t2mo9WlO7r6GTmWV0F0uzHZVFmlRmYpiSK1CDU5IKojP1pm7oknpBOrFZx/YgBRW9oorPO2S/Lg==} + 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-popper@1.1.2': resolution: {integrity: sha512-1CnGGfFi/bbqtJZZ0P/NQY20xdG3E0LALJaLUEoKwPLwl6PPPfbeiCqMVQnhoFRAxjJj4RpBRJzDmUgsex2tSg==} peerDependencies: @@ -4349,6 +4442,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-popper@1.2.2': + resolution: {integrity: sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==} + 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-portal@1.0.3': resolution: {integrity: sha512-xLYZeHrWoPmA5mEKEfZZevoVRK/Q43GfzRXkWV6qawIWWK8t6ifIiLQdd7rmQ4Vk1bmI21XhqF9BN3jWf+phpA==} peerDependencies: @@ -4362,6 +4468,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-portal@1.1.4': + resolution: {integrity: sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==} + 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.1.2': resolution: {integrity: sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==} peerDependencies: @@ -4401,6 +4520,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-primitive@2.0.2': + resolution: {integrity: sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==} + 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-roving-focus@1.0.4': resolution: {integrity: sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==} peerDependencies: @@ -4414,6 +4546,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-roving-focus@1.1.2': + resolution: {integrity: sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw==} + 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-select@1.2.2': resolution: {integrity: sha512-zI7McXr8fNaSrUY9mZe4x/HC0jTLY9fWNhO1oLWYMQGDXuV4UCivIGTxwioSzO0ZCYX9iSLyWmAh/1TOmX3Cnw==} peerDependencies: @@ -4458,6 +4603,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-slot@1.1.2': + resolution: {integrity: sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-toggle-group@1.0.4': resolution: {integrity: sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==} peerDependencies: @@ -4542,6 +4696,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-escape-keydown@1.1.0': + resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-layout-effect@1.0.1': resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} peerDependencies: @@ -4578,6 +4741,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-rect@1.1.0': + resolution: {integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-size@1.0.1': resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} peerDependencies: @@ -4587,6 +4759,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-size@1.1.0': + resolution: {integrity: sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-visually-hidden@1.0.3': resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==} peerDependencies: @@ -4603,6 +4784,9 @@ packages: '@radix-ui/rect@1.0.1': resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} + '@radix-ui/rect@1.1.0': + resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} + '@react-hook/latest@1.0.3': resolution: {integrity: sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg==} peerDependencies: @@ -6556,6 +6740,10 @@ packages: '@types/react': optional: true + aria-hidden@1.2.4: + resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} + engines: {node: '>=10'} + aria-query@5.1.3: resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} @@ -12538,6 +12726,9 @@ packages: preact@10.25.4: resolution: {integrity: sha512-jLdZDb+Q+odkHJ+MpW/9U5cODzqnB+fy2EiHSZES7ldV5LK7yjlVzTp7R8Xy6W6y75kfK8iWYtFVH7lvjwrCMA==} + preact@10.26.3: + resolution: {integrity: sha512-OJCfNTdttkOTCbTN+gCnXn/woDqz1dIjvP+gdCoYGP2kKuX6w79FAP8qgY/r7jgAunvqHVVmEOKzKOFWzrXZdw==} + preact@10.26.4: resolution: {integrity: sha512-KJhO7LBFTjP71d83trW+Ilnjbo+ySsaAgCfXOXUlmGzJ4ygYPWmysm77yg4emwfmoz3b22yvH5IsVFHbhUaH5w==} @@ -13006,6 +13197,16 @@ packages: '@types/react': optional: true + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + react-remove-scroll@2.5.5: resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==} engines: {node: '>=10'} @@ -13016,6 +13217,16 @@ packages: '@types/react': optional: true + react-remove-scroll@2.6.3: + resolution: {integrity: sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + react-resizable@3.0.5: resolution: {integrity: sha512-vKpeHhI5OZvYn82kXOs1bC8aOXktGU5AmKAgaZS4F5JPburCtbmDPqE7Pzp+1kN4+Wb81LlF33VpGwWwtXem+w==} peerDependencies: @@ -13038,6 +13249,16 @@ packages: '@types/react': optional: true + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + react-syntax-highlighter@15.5.0: resolution: {integrity: sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==} peerDependencies: @@ -14765,6 +14986,16 @@ packages: '@types/react': optional: true + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + use-composed-ref@1.3.0: resolution: {integrity: sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==} peerDependencies: @@ -14816,6 +15047,16 @@ packages: '@types/react': optional: true + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + use-sync-external-store@1.2.0: resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} peerDependencies: @@ -17084,15 +17325,15 @@ snapshots: tunnel-agent: 0.6.0 uuid: 8.3.2 - '@cypress/webpack-preprocessor@6.0.2(@babel/core@7.26.0)(@babel/preset-env@7.23.5(@babel/core@7.26.0))(babel-loader@8.3.0(@babel/core@7.26.0)(webpack@5.88.2))(webpack@5.88.2)': + '@cypress/webpack-preprocessor@6.0.2(@babel/core@7.26.0)(@babel/preset-env@7.23.5(@babel/core@7.26.0))(babel-loader@8.3.0(@babel/core@7.26.0)(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))))(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15)))': dependencies: '@babel/core': 7.26.0 '@babel/preset-env': 7.23.5(@babel/core@7.26.0) - babel-loader: 8.3.0(@babel/core@7.26.0)(webpack@5.88.2) + babel-loader: 8.3.0(@babel/core@7.26.0)(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))) bluebird: 3.7.1 debug: 4.4.0(supports-color@8.1.1) lodash: 4.17.21 - webpack: 5.88.2 + webpack: 5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15)) transitivePeerDependencies: - supports-color @@ -18007,14 +18248,6 @@ snapshots: '@parcel/utils': 2.13.3 lmdb: 2.8.5 - '@parcel/cache@2.13.3(@parcel/core@2.13.3)': - dependencies: - '@parcel/core': 2.13.3 - '@parcel/fs': 2.13.3(@parcel/core@2.13.3) - '@parcel/logger': 2.13.3 - '@parcel/utils': 2.13.3 - lmdb: 2.8.5 - '@parcel/codeframe@2.13.3': dependencies: chalk: 4.1.2 @@ -18071,36 +18304,6 @@ snapshots: - typescript - uncss - '@parcel/core@2.13.3': - dependencies: - '@mischnic/json-sourcemap': 0.1.1 - '@parcel/cache': 2.13.3(@parcel/core@2.13.3) - '@parcel/diagnostic': 2.13.3 - '@parcel/events': 2.13.3 - '@parcel/feature-flags': 2.13.3 - '@parcel/fs': 2.13.3(@parcel/core@2.13.3) - '@parcel/graph': 3.3.3 - '@parcel/logger': 2.13.3 - '@parcel/package-manager': 2.13.3(@parcel/core@2.13.3) - '@parcel/plugin': 2.13.3(@parcel/core@2.13.3) - '@parcel/profiler': 2.13.3 - '@parcel/rust': 2.13.3 - '@parcel/source-map': 2.1.1 - '@parcel/types': 2.13.3(@parcel/core@2.13.3) - '@parcel/utils': 2.13.3 - '@parcel/workers': 2.13.3(@parcel/core@2.13.3) - base-x: 3.0.10 - browserslist: 4.24.3 - clone: 2.1.2 - dotenv: 16.4.7 - dotenv-expand: 11.0.7 - json5: 2.2.3 - msgpackr: 1.11.2 - nullthrows: 1.1.1 - semver: 7.7.0 - transitivePeerDependencies: - - '@swc/helpers' - '@parcel/core@2.13.3(@swc/helpers@0.5.15)': dependencies: '@mischnic/json-sourcemap': 0.1.1 @@ -18150,16 +18353,6 @@ snapshots: '@parcel/watcher': 2.5.1 '@parcel/workers': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15)) - '@parcel/fs@2.13.3(@parcel/core@2.13.3)': - dependencies: - '@parcel/core': 2.13.3 - '@parcel/feature-flags': 2.13.3 - '@parcel/rust': 2.13.3 - '@parcel/types-internal': 2.13.3 - '@parcel/utils': 2.13.3 - '@parcel/watcher': 2.5.1 - '@parcel/workers': 2.13.3(@parcel/core@2.13.3) - '@parcel/graph@3.3.3': dependencies: '@parcel/feature-flags': 2.13.3 @@ -18194,18 +18387,6 @@ snapshots: transitivePeerDependencies: - '@parcel/core' - '@parcel/node-resolver-core@3.4.3(@parcel/core@2.13.3)': - dependencies: - '@mischnic/json-sourcemap': 0.1.1 - '@parcel/diagnostic': 2.13.3 - '@parcel/fs': 2.13.3(@parcel/core@2.13.3) - '@parcel/rust': 2.13.3 - '@parcel/utils': 2.13.3 - nullthrows: 1.1.1 - semver: 7.7.0 - transitivePeerDependencies: - - '@parcel/core' - '@parcel/optimizer-css@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))': dependencies: '@parcel/diagnostic': 2.13.3 @@ -18282,21 +18463,6 @@ snapshots: transitivePeerDependencies: - '@swc/helpers' - '@parcel/package-manager@2.13.3(@parcel/core@2.13.3)': - dependencies: - '@parcel/core': 2.13.3 - '@parcel/diagnostic': 2.13.3 - '@parcel/fs': 2.13.3(@parcel/core@2.13.3) - '@parcel/logger': 2.13.3 - '@parcel/node-resolver-core': 3.4.3(@parcel/core@2.13.3) - '@parcel/types': 2.13.3(@parcel/core@2.13.3) - '@parcel/utils': 2.13.3 - '@parcel/workers': 2.13.3(@parcel/core@2.13.3) - '@swc/core': 1.11.4(@swc/helpers@0.5.15) - semver: 7.7.0 - transitivePeerDependencies: - - '@swc/helpers' - '@parcel/packager-css@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))': dependencies: '@parcel/diagnostic': 2.13.3 @@ -18352,12 +18518,6 @@ snapshots: transitivePeerDependencies: - '@parcel/core' - '@parcel/packager-ts@2.13.3(@parcel/core@2.13.3)': - dependencies: - '@parcel/plugin': 2.13.3(@parcel/core@2.13.3) - transitivePeerDependencies: - - '@parcel/core' - '@parcel/packager-wasm@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))': dependencies: '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15)) @@ -18370,12 +18530,6 @@ snapshots: transitivePeerDependencies: - '@parcel/core' - '@parcel/plugin@2.13.3(@parcel/core@2.13.3)': - dependencies: - '@parcel/types': 2.13.3(@parcel/core@2.13.3) - transitivePeerDependencies: - - '@parcel/core' - '@parcel/profiler@2.13.3': dependencies: '@parcel/diagnostic': 2.13.3 @@ -18588,18 +18742,6 @@ snapshots: transitivePeerDependencies: - '@parcel/core' - '@parcel/transformer-typescript-types@2.13.3(@parcel/core@2.13.3)(typescript@4.9.5)': - dependencies: - '@parcel/diagnostic': 2.13.3 - '@parcel/plugin': 2.13.3(@parcel/core@2.13.3) - '@parcel/source-map': 2.1.1 - '@parcel/ts-utils': 2.13.3(typescript@4.9.5) - '@parcel/utils': 2.13.3 - nullthrows: 1.1.1 - typescript: 4.9.5 - transitivePeerDependencies: - - '@parcel/core' - '@parcel/ts-utils@2.13.3(typescript@4.9.5)': dependencies: nullthrows: 1.1.1 @@ -18619,13 +18761,6 @@ snapshots: transitivePeerDependencies: - '@parcel/core' - '@parcel/types@2.13.3(@parcel/core@2.13.3)': - dependencies: - '@parcel/types-internal': 2.13.3 - '@parcel/workers': 2.13.3(@parcel/core@2.13.3) - transitivePeerDependencies: - - '@parcel/core' - '@parcel/utils@2.13.3': dependencies: '@parcel/codeframe': 2.13.3 @@ -18707,16 +18842,6 @@ snapshots: '@parcel/utils': 2.13.3 nullthrows: 1.1.1 - '@parcel/workers@2.13.3(@parcel/core@2.13.3)': - dependencies: - '@parcel/core': 2.13.3 - '@parcel/diagnostic': 2.13.3 - '@parcel/logger': 2.13.3 - '@parcel/profiler': 2.13.3 - '@parcel/types-internal': 2.13.3 - '@parcel/utils': 2.13.3 - nullthrows: 1.1.1 - '@pkgjs/parseargs@0.11.0': optional: true @@ -18844,6 +18969,15 @@ snapshots: '@types/react': 17.0.52 '@types/react-dom': 18.2.14 + '@radix-ui/react-arrow@1.1.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 17.0.52 + '@types/react-dom': 18.2.14 + '@radix-ui/react-collapsible@1.1.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@radix-ui/primitive': 1.1.1 @@ -18885,6 +19019,18 @@ snapshots: '@types/react': 17.0.52 '@types/react-dom': 18.2.14 + '@radix-ui/react-collection@1.1.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.1(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-context': 1.1.1(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-slot': 1.1.2(@types/react@17.0.52)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 17.0.52 + '@types/react-dom': 18.2.14 + '@radix-ui/react-compose-refs@1.0.1(@types/react@17.0.52)(react@18.2.0)': dependencies: '@babel/runtime': 7.24.0 @@ -18898,6 +19044,20 @@ snapshots: optionalDependencies: '@types/react': 17.0.52 + '@radix-ui/react-context-menu@2.2.6(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-context': 1.1.1(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-menu': 2.1.6(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@17.0.52)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 17.0.52 + '@types/react-dom': 18.2.14 + '@radix-ui/react-context@1.0.1(@types/react@17.0.52)(react@18.2.0)': dependencies: '@babel/runtime': 7.24.0 @@ -18938,6 +19098,19 @@ snapshots: '@types/react': 17.0.52 '@types/react-dom': 18.2.14 + '@radix-ui/react-dismissable-layer@1.1.5(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@17.0.52)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 17.0.52 + '@types/react-dom': 18.2.14 + '@radix-ui/react-focus-guards@1.0.1(@types/react@17.0.52)(react@18.2.0)': dependencies: '@babel/runtime': 7.24.0 @@ -18945,6 +19118,12 @@ snapshots: optionalDependencies: '@types/react': 17.0.52 + '@radix-ui/react-focus-guards@1.1.1(@types/react@17.0.52)(react@18.2.0)': + dependencies: + react: 18.2.0 + optionalDependencies: + '@types/react': 17.0.52 + '@radix-ui/react-focus-scope@1.0.3(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.24.0 @@ -18957,6 +19136,17 @@ snapshots: '@types/react': 17.0.52 '@types/react-dom': 18.2.14 + '@radix-ui/react-focus-scope@1.1.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.1(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@17.0.52)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 17.0.52 + '@types/react-dom': 18.2.14 + '@radix-ui/react-id@1.0.1(@types/react@17.0.52)(react@18.2.0)': dependencies: '@babel/runtime': 7.24.0 @@ -18972,6 +19162,32 @@ snapshots: optionalDependencies: '@types/react': 17.0.52 + '@radix-ui/react-menu@2.1.6(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-collection': 1.1.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-context': 1.1.1(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-direction': 1.1.0(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.1.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-id': 1.1.0(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-popper': 1.2.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-portal': 1.1.4(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-roving-focus': 1.1.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-slot': 1.1.2(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@17.0.52)(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.3(@types/react@17.0.52)(react@18.2.0) + optionalDependencies: + '@types/react': 17.0.52 + '@types/react-dom': 18.2.14 + '@radix-ui/react-popper@1.1.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.24.0 @@ -18991,6 +19207,24 @@ snapshots: '@types/react': 17.0.52 '@types/react-dom': 18.2.14 + '@radix-ui/react-popper@1.2.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@floating-ui/react-dom': 2.0.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-arrow': 1.1.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-context': 1.1.1(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-use-rect': 1.1.0(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-use-size': 1.1.0(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/rect': 1.1.0 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 17.0.52 + '@types/react-dom': 18.2.14 + '@radix-ui/react-portal@1.0.3(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.24.0 @@ -19001,6 +19235,16 @@ snapshots: '@types/react': 17.0.52 '@types/react-dom': 18.2.14 + '@radix-ui/react-portal@1.1.4(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@17.0.52)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 17.0.52 + '@types/react-dom': 18.2.14 + '@radix-ui/react-presence@1.1.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.1(@types/react@17.0.52)(react@18.2.0) @@ -19030,6 +19274,15 @@ snapshots: '@types/react': 17.0.52 '@types/react-dom': 18.2.14 + '@radix-ui/react-primitive@2.0.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/react-slot': 1.1.2(@types/react@17.0.52)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 17.0.52 + '@types/react-dom': 18.2.14 + '@radix-ui/react-roving-focus@1.0.4(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.24.0 @@ -19048,6 +19301,23 @@ snapshots: '@types/react': 17.0.52 '@types/react-dom': 18.2.14 + '@radix-ui/react-roving-focus@1.1.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-collection': 1.1.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-context': 1.1.1(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-direction': 1.1.0(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-id': 1.1.0(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@17.0.52)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@17.0.52)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 17.0.52 + '@types/react-dom': 18.2.14 + '@radix-ui/react-select@1.2.2(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.24.0 @@ -19103,6 +19373,13 @@ snapshots: optionalDependencies: '@types/react': 17.0.52 + '@radix-ui/react-slot@1.1.2(@types/react@17.0.52)(react@18.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.1(@types/react@17.0.52)(react@18.2.0) + react: 18.2.0 + optionalDependencies: + '@types/react': 17.0.52 + '@radix-ui/react-toggle-group@1.0.4(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.24.0 @@ -19183,6 +19460,13 @@ snapshots: optionalDependencies: '@types/react': 17.0.52 + '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@17.0.52)(react@18.2.0)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@17.0.52)(react@18.2.0) + react: 18.2.0 + optionalDependencies: + '@types/react': 17.0.52 + '@radix-ui/react-use-layout-effect@1.0.1(@types/react@17.0.52)(react@18.2.0)': dependencies: '@babel/runtime': 7.24.0 @@ -19211,6 +19495,13 @@ snapshots: optionalDependencies: '@types/react': 17.0.52 + '@radix-ui/react-use-rect@1.1.0(@types/react@17.0.52)(react@18.2.0)': + dependencies: + '@radix-ui/rect': 1.1.0 + react: 18.2.0 + optionalDependencies: + '@types/react': 17.0.52 + '@radix-ui/react-use-size@1.0.1(@types/react@17.0.52)(react@18.2.0)': dependencies: '@babel/runtime': 7.24.0 @@ -19219,6 +19510,13 @@ snapshots: optionalDependencies: '@types/react': 17.0.52 + '@radix-ui/react-use-size@1.1.0(@types/react@17.0.52)(react@18.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@17.0.52)(react@18.2.0) + react: 18.2.0 + optionalDependencies: + '@types/react': 17.0.52 + '@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.2.14)(@types/react@17.0.52)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.24.0 @@ -19233,6 +19531,8 @@ snapshots: dependencies: '@babel/runtime': 7.24.0 + '@radix-ui/rect@1.1.0': {} + '@react-hook/latest@1.0.3(react@18.2.0)': dependencies: react: 18.2.0 @@ -20476,7 +20776,7 @@ snapshots: - encoding - supports-color - '@storybook/test-runner@0.16.0(@swc/helpers@0.5.15)(encoding@0.1.13)': + '@storybook/test-runner@0.16.0(@swc/helpers@0.5.15)(@types/node@18.18.4)(encoding@0.1.13)(ts-node@10.9.1(@swc/core@1.11.4(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5))': dependencies: '@babel/core': 7.26.0 '@babel/generator': 7.26.3 @@ -20493,14 +20793,14 @@ snapshots: commander: 9.4.1 expect-playwright: 0.8.0 glob: 10.4.5 - jest: 29.7.0(@types/node@18.18.4)(ts-node@10.9.1(@swc/core@1.10.14(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5)) + jest: 29.7.0(@types/node@18.18.4)(ts-node@10.9.1(@swc/core@1.11.4(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5)) jest-circus: 29.7.0 jest-environment-node: 29.7.0 jest-junit: 16.0.0 - jest-playwright-preset: 4.0.0(jest-circus@29.7.0)(jest-environment-node@29.7.0)(jest-runner@29.7.0)(jest@29.7.0) + jest-playwright-preset: 4.0.0(jest-circus@29.7.0)(jest-environment-node@29.7.0)(jest-runner@29.7.0)(jest@29.7.0(@types/node@18.18.4)(ts-node@10.9.1(@swc/core@1.11.4(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5))) jest-runner: 29.7.0 jest-serializer-html: 7.1.0 - jest-watch-typeahead: 2.2.2(jest@29.7.0) + jest-watch-typeahead: 2.2.2(jest@29.7.0(@types/node@18.18.4)(ts-node@10.9.1(@swc/core@1.11.4(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5))) node-fetch: 2.6.9(encoding@0.1.13) playwright: 1.45.0 read-pkg-up: 7.0.1 @@ -22047,6 +22347,10 @@ snapshots: optionalDependencies: '@types/react': 17.0.52 + aria-hidden@1.2.4: + dependencies: + tslib: 2.8.1 + aria-query@5.1.3: dependencies: deep-equal: 2.1.0 @@ -22283,6 +22587,15 @@ snapshots: transitivePeerDependencies: - supports-color + babel-loader@8.3.0(@babel/core@7.26.0)(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))): + dependencies: + '@babel/core': 7.26.0 + find-cache-dir: 3.3.2 + loader-utils: 2.0.4 + make-dir: 3.1.0 + schema-utils: 2.7.1 + webpack: 5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15)) + babel-loader@8.3.0(@babel/core@7.26.0)(webpack@5.88.2): dependencies: '@babel/core': 7.26.0 @@ -23330,6 +23643,23 @@ snapshots: postcss-selector-parser: 7.1.0 postcss-value-parser: 4.2.0 + css-loader@3.6.0(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))): + dependencies: + camelcase: 5.3.1 + cssesc: 3.0.0 + icss-utils: 4.1.1 + loader-utils: 1.4.2 + normalize-path: 3.0.0 + postcss: 7.0.39 + postcss-modules-extract-imports: 2.0.0 + postcss-modules-local-by-default: 3.0.3 + postcss-modules-scope: 2.2.0 + postcss-modules-values: 3.0.0 + postcss-value-parser: 4.2.0 + schema-utils: 2.7.1 + semver: 6.3.1 + webpack: 5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15)) + css-loader@3.6.0(webpack@5.88.2): dependencies: camelcase: 5.3.1 @@ -24554,7 +24884,7 @@ snapshots: eslint-import-resolver-node@0.3.9: dependencies: - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7(supports-color@5.5.0) is-core-module: 2.13.1 resolve: 1.22.8 transitivePeerDependencies: @@ -24562,7 +24892,7 @@ snapshots: eslint-module-utils@2.8.0(@typescript-eslint/parser@7.1.1(eslint@8.57.0)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): dependencies: - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7(supports-color@5.5.0) optionalDependencies: '@typescript-eslint/parser': 7.1.1(eslint@8.57.0)(typescript@4.9.5) eslint: 8.57.0 @@ -24604,7 +24934,7 @@ snapshots: array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 array.prototype.flatmap: 1.3.2 - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7(supports-color@5.5.0) doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 @@ -24636,17 +24966,6 @@ snapshots: - supports-color - typescript - eslint-plugin-jest@28.6.0(@typescript-eslint/eslint-plugin@7.1.1(@typescript-eslint/parser@7.1.1(eslint@8.57.0)(typescript@4.9.5))(eslint@8.57.0)(typescript@4.9.5))(eslint@8.57.0)(jest@29.7.0)(typescript@4.9.5): - dependencies: - '@typescript-eslint/utils': 7.1.1(eslint@8.57.0)(typescript@4.9.5) - eslint: 8.57.0 - optionalDependencies: - '@typescript-eslint/eslint-plugin': 7.1.1(@typescript-eslint/parser@7.1.1(eslint@8.57.0)(typescript@4.9.5))(eslint@8.57.0)(typescript@4.9.5) - jest: 29.7.0(@types/node@18.18.4)(ts-node@10.9.1(@swc/core@1.10.14(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5)) - transitivePeerDependencies: - - supports-color - - typescript - eslint-plugin-no-only-tests@3.3.0: {} eslint-plugin-node@11.1.0(eslint@8.57.0): @@ -25068,6 +25387,12 @@ snapshots: dependencies: flat-cache: 3.2.0 + file-loader@6.2.0(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))): + dependencies: + loader-utils: 2.0.4 + schema-utils: 3.3.0 + webpack: 5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15)) + file-loader@6.2.0(webpack@5.88.2): dependencies: loader-utils: 2.0.4 @@ -26146,7 +26471,7 @@ snapshots: hogan.js: 3.0.2 htm: 3.1.1 instantsearch-ui-components: 0.3.0 - preact: 10.26.4 + preact: 10.26.3 qs: 6.9.7 search-insights: 2.13.0 @@ -26845,10 +27170,10 @@ snapshots: '@types/node': 18.18.4 jest-util: 29.7.0 - jest-playwright-preset@4.0.0(jest-circus@29.7.0)(jest-environment-node@29.7.0)(jest-runner@29.7.0)(jest@29.7.0): + jest-playwright-preset@4.0.0(jest-circus@29.7.0)(jest-environment-node@29.7.0)(jest-runner@29.7.0)(jest@29.7.0(@types/node@18.18.4)(ts-node@10.9.1(@swc/core@1.11.4(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5))): dependencies: expect-playwright: 0.8.0 - jest: 29.7.0(@types/node@18.18.4)(ts-node@10.9.1(@swc/core@1.10.14(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5)) + jest: 29.7.0(@types/node@18.18.4)(ts-node@10.9.1(@swc/core@1.11.4(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5)) jest-circus: 29.7.0 jest-environment-node: 29.7.0 jest-process-manager: 0.4.0 @@ -27002,11 +27327,11 @@ snapshots: leven: 3.1.0 pretty-format: 29.7.0 - jest-watch-typeahead@2.2.2(jest@29.7.0): + jest-watch-typeahead@2.2.2(jest@29.7.0(@types/node@18.18.4)(ts-node@10.9.1(@swc/core@1.11.4(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5))): dependencies: ansi-escapes: 6.0.0 chalk: 5.4.1 - jest: 29.7.0(@types/node@18.18.4)(ts-node@10.9.1(@swc/core@1.10.14(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5)) + jest: 29.7.0(@types/node@18.18.4)(ts-node@10.9.1(@swc/core@1.11.4(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5)) jest-regex-util: 29.6.3 jest-watcher: 29.7.0 slash: 5.1.0 @@ -27338,6 +27663,14 @@ snapshots: dotenv: 16.4.7 dotenv-expand: 10.0.0 + less-loader@7.3.0(less@4.2.2)(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))): + dependencies: + klona: 2.0.5 + less: 4.2.2 + loader-utils: 2.0.4 + schema-utils: 3.3.0 + webpack: 5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15)) + less-loader@7.3.0(less@4.2.2)(webpack@5.88.2): dependencies: klona: 2.0.5 @@ -29122,6 +29455,16 @@ snapshots: postcss: 8.5.2 ts-node: 10.9.1(@swc/core@1.11.4(@swc/helpers@0.5.15))(@types/node@18.18.4)(typescript@4.9.5) + postcss-loader@4.3.0(postcss@8.5.2)(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))): + dependencies: + cosmiconfig: 7.1.0 + klona: 2.0.5 + loader-utils: 2.0.4 + postcss: 8.5.2 + schema-utils: 3.3.0 + semver: 7.7.0 + webpack: 5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15)) + postcss-loader@4.3.0(postcss@8.5.2)(webpack@5.88.2): dependencies: cosmiconfig: 7.1.0 @@ -29394,6 +29737,10 @@ snapshots: dependencies: postcss: 8.4.31 + postcss-scss@4.0.9(postcss@8.4.31): + dependencies: + postcss: 8.4.31 + postcss-scss@4.0.9(postcss@8.5.2): dependencies: postcss: 8.5.2 @@ -29511,6 +29858,8 @@ snapshots: preact@10.25.4: {} + preact@10.26.3: {} + preact@10.26.4: {} prelude-ls@1.1.2: {} @@ -30079,6 +30428,14 @@ snapshots: optionalDependencies: '@types/react': 17.0.52 + react-remove-scroll-bar@2.3.8(@types/react@17.0.52)(react@18.2.0): + dependencies: + react: 18.2.0 + react-style-singleton: 2.2.3(@types/react@17.0.52)(react@18.2.0) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 17.0.52 + react-remove-scroll@2.5.5(@types/react@17.0.52)(react@18.2.0): dependencies: react: 18.2.0 @@ -30090,6 +30447,17 @@ snapshots: optionalDependencies: '@types/react': 17.0.52 + react-remove-scroll@2.6.3(@types/react@17.0.52)(react@18.2.0): + dependencies: + react: 18.2.0 + react-remove-scroll-bar: 2.3.8(@types/react@17.0.52)(react@18.2.0) + react-style-singleton: 2.2.3(@types/react@17.0.52)(react@18.2.0) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@17.0.52)(react@18.2.0) + use-sidecar: 1.1.3(@types/react@17.0.52)(react@18.2.0) + optionalDependencies: + '@types/react': 17.0.52 + react-resizable@3.0.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: prop-types: 15.8.1 @@ -30114,6 +30482,14 @@ snapshots: optionalDependencies: '@types/react': 17.0.52 + react-style-singleton@2.2.3(@types/react@17.0.52)(react@18.2.0): + dependencies: + get-nonce: 1.0.1 + react: 18.2.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 17.0.52 + react-syntax-highlighter@15.5.0(react@18.2.0): dependencies: '@babel/runtime': 7.24.0 @@ -30632,6 +31008,17 @@ snapshots: sass-embedded-win32-ia32: 1.70.0 sass-embedded-win32-x64: 1.70.0 + sass-loader@10.3.1(sass@1.56.0)(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))): + dependencies: + klona: 2.0.5 + loader-utils: 2.0.4 + neo-async: 2.6.2 + schema-utils: 3.3.0 + semver: 7.7.0 + webpack: 5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15)) + optionalDependencies: + sass: 1.56.0 + sass-loader@10.3.1(sass@1.56.0)(webpack@5.88.2): dependencies: klona: 2.0.5 @@ -31256,6 +31643,12 @@ snapshots: stubs@3.0.0: {} + style-loader@2.0.0(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))): + dependencies: + loader-utils: 2.0.4 + schema-utils: 3.3.0 + webpack: 5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15)) + style-loader@2.0.0(webpack@5.88.2): dependencies: loader-utils: 2.0.4 @@ -31279,6 +31672,15 @@ snapshots: stylelint: 15.11.0(typescript@4.9.5) stylelint-order: 6.0.3(stylelint@15.11.0(typescript@4.9.5)) + stylelint-config-recommended-scss@13.1.0(postcss@8.4.31)(stylelint@15.11.0(typescript@4.9.5)): + dependencies: + postcss-scss: 4.0.9(postcss@8.4.31) + stylelint: 15.11.0(typescript@4.9.5) + stylelint-config-recommended: 13.0.0(stylelint@15.11.0(typescript@4.9.5)) + stylelint-scss: 5.3.1(stylelint@15.11.0(typescript@4.9.5)) + optionalDependencies: + postcss: 8.4.31 + stylelint-config-recommended-scss@13.1.0(postcss@8.5.2)(stylelint@15.11.0(typescript@4.9.5)): dependencies: postcss-scss: 4.0.9(postcss@8.5.2) @@ -31292,6 +31694,14 @@ snapshots: dependencies: stylelint: 15.11.0(typescript@4.9.5) + stylelint-config-standard-scss@11.1.0(postcss@8.4.31)(stylelint@15.11.0(typescript@4.9.5)): + dependencies: + stylelint: 15.11.0(typescript@4.9.5) + stylelint-config-recommended-scss: 13.1.0(postcss@8.4.31)(stylelint@15.11.0(typescript@4.9.5)) + stylelint-config-standard: 34.0.0(stylelint@15.11.0(typescript@4.9.5)) + optionalDependencies: + postcss: 8.4.31 + stylelint-config-standard-scss@11.1.0(postcss@8.5.2)(stylelint@15.11.0(typescript@4.9.5)): dependencies: stylelint: 15.11.0(typescript@4.9.5) @@ -31596,14 +32006,16 @@ snapshots: '@swc/core': 1.11.4(@swc/helpers@0.5.15) esbuild: 0.18.20 - terser-webpack-plugin@5.3.9(webpack@5.88.2): + terser-webpack-plugin@5.3.9(@swc/core@1.11.4(@swc/helpers@0.5.15))(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.1 terser: 5.19.1 - webpack: 5.88.2 + webpack: 5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15)) + optionalDependencies: + '@swc/core': 1.11.4(@swc/helpers@0.5.15) terser@5.19.1: dependencies: @@ -32133,6 +32545,13 @@ snapshots: optionalDependencies: '@types/react': 17.0.52 + use-callback-ref@1.3.3(@types/react@17.0.52)(react@18.2.0): + dependencies: + react: 18.2.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 17.0.52 + use-composed-ref@1.3.0(react@18.2.0): dependencies: react: 18.2.0 @@ -32174,6 +32593,14 @@ snapshots: optionalDependencies: '@types/react': 17.0.52 + use-sidecar@1.1.3(@types/react@17.0.52)(react@18.2.0): + dependencies: + detect-node-es: 1.1.0 + react: 18.2.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 17.0.52 + use-sync-external-store@1.2.0(react@18.2.0): dependencies: react: 18.2.0 @@ -32364,7 +32791,7 @@ snapshots: webpack-virtual-modules@0.5.0: {} - webpack@5.88.2: + webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15)): dependencies: '@types/eslint-scope': 3.7.4 '@types/estree': 1.0.1 @@ -32387,7 +32814,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.9(webpack@5.88.2) + terser-webpack-plugin: 5.3.9(@swc/core@1.11.4(@swc/helpers@0.5.15))(webpack@5.88.2(@swc/core@1.11.4(@swc/helpers@0.5.15))) watchpack: 2.4.0 webpack-sources: 3.2.3 transitivePeerDependencies: