diff --git a/apps/web/src/components/navbar/DatabaseManagement/dbConnectionSelector.tsx b/apps/web/src/components/navbar/DatabaseManagement/dbConnectionSelector.tsx index 2775725cf2d77cfce42fcd3a17e2305db0f43cc9..6ed8758c79b6eda3bf540d77777189015deb367f 100644 --- a/apps/web/src/components/navbar/DatabaseManagement/dbConnectionSelector.tsx +++ b/apps/web/src/components/navbar/DatabaseManagement/dbConnectionSelector.tsx @@ -5,7 +5,7 @@ import { deleteSaveState, selectSaveState } from '@graphpolaris/shared/lib/data- import { SettingsForm } from './forms/settings'; import { LoadingSpinner } from '@graphpolaris/shared/lib/components/LoadingSpinner'; import { addError } from '@graphpolaris/shared/lib/data-access/store/configSlice'; -import { DropdownTrigger, DropdownContainer, DropdownItemContainer } from '@graphpolaris/shared/lib/components/dropdowns'; +import { DropdownButton, DropdownContainer, DropdownItemContainer } from '@graphpolaris/shared/lib/components/dropdowns'; import { clearQB } from '@graphpolaris/shared/lib/data-access/store/querybuilderSlice'; import { clearSchema } from '@graphpolaris/shared/lib/data-access/store/schemaSlice'; import { DatabaseStatus, SaveStateI, nilUUID, wsDeleteState } from '@graphpolaris/shared/lib/data-access/broker'; @@ -17,6 +17,7 @@ export default function DatabaseSelector({}) { const session = useSessionCache(); const schemaGraph = useSchemaGraph(); const authCache = useAuthorizationCache(); + const dbSelectionMenuRef = React.useRef<HTMLDivElement>(null); const [hovered, setHovered] = useState<string | null>(null); const [connecting, setConnecting] = useState<boolean>(false); const [dbSelectionMenuOpen, setDbSelectionMenuOpen] = useState<boolean>(false); @@ -36,6 +37,18 @@ export default function DatabaseSelector({}) { } }, [session, settingsMenuOpen]); + useEffect(() => { + const handleClickOutside = ({ target }: MouseEvent) => { + if (dbSelectionMenuRef.current && !dbSelectionMenuRef.current.contains(target as Node)) { + setDbSelectionMenuOpen(false); + } + }; + document.addEventListener('click', handleClickOutside); + return () => { + document.removeEventListener('click', handleClickOutside); + }; + }, []); + useEffect(() => { setConnecting(false); }, [schemaGraph]); @@ -73,24 +86,8 @@ export default function DatabaseSelector({}) { }} /> )} - <DropdownContainer - open={dbSelectionMenuOpen} - onOpenChange={(ret) => { - console.log('dbSelectionMenuOpen', dbSelectionMenuOpen, ret); - - if (!ret) { - if (session.saveStates && Object.keys(session.saveStates).length === 0) setSettingsMenuOpen('add'); - else setDbSelectionMenuOpen(!dbSelectionMenuOpen); - } else { - setDbSelectionMenuOpen(true); - } - }} - > - <DropdownTrigger - onClick={() => { - setDbSelectionMenuOpen(!dbSelectionMenuOpen); - }} - className="w-[18rem]" + <DropdownContainer ref={dbSelectionMenuRef} className="w-[18rem]"> + <DropdownButton size="md" disabled={connecting || authCache.authorized === false || !!authCache.roomID} title={ @@ -129,10 +126,14 @@ export default function DatabaseSelector({}) { )} </div> } + onClick={() => { + if (session.saveStates && Object.keys(session.saveStates).length === 0) setSettingsMenuOpen('add'); + else setDbSelectionMenuOpen(!dbSelectionMenuOpen); + }} /> - {session.saveStates !== undefined && ( - <DropdownItemContainer> + {dbSelectionMenuOpen && session.saveStates !== undefined && ( + <DropdownItemContainer align="top-10 w-full z-30"> <li className="flex items-center p-2 hover:bg-secondary-50 cursor-pointer" onClick={(e) => { @@ -199,49 +200,51 @@ export default function DatabaseSelector({}) { {save.db.url} </p> </div> - <div className={`flex items-center ml-2 ${hovered === save.id ? 'display' : 'invisible'}`}> - <div - className="text-secondary-700 hover:text-secondary-400 transition-colors duration-300" - onClick={(e) => { - e.preventDefault(); - e.stopPropagation(); - setSettingsMenuOpen('update'); - setSelectedSaveState(save); - }} - > - <Tooltip> - <TooltipTrigger> - <Settings /> - </TooltipTrigger> - <TooltipContent side={'top'}> - <p>Change the connection details</p> - </TooltipContent> - </Tooltip> - </div> - <div - className="text-secondary-700 hover:text-secondary-400 transition-colors duration-300" - onClick={(e) => { - e.preventDefault(); - e.stopPropagation(); - setDbSelectionMenuOpen(false); - if (session.currentSaveState === save.id) { - dispatch(clearQB()); - dispatch(clearSchema()); - } - wsDeleteState(save.id); - dispatch(deleteSaveState(save.id)); - }} - > - <Tooltip> - <TooltipTrigger> - <Delete /> - </TooltipTrigger> - <TooltipContent side={'top'}> - <p>Delete the database</p> - </TooltipContent> - </Tooltip> + {hovered === save.id && ( + <div className="flex items-center ml-2"> + <div + className="text-secondary-700 hover:text-secondary-400 transition-colors duration-300" + onClick={(e) => { + e.preventDefault(); + e.stopPropagation(); + setSettingsMenuOpen('update'); + setSelectedSaveState(save); + }} + > + <Tooltip> + <TooltipTrigger> + <Settings /> + </TooltipTrigger> + <TooltipContent side={'top'}> + <p>Change the connection details</p> + </TooltipContent> + </Tooltip> + </div> + <div + className="text-secondary-700 hover:text-secondary-400 transition-colors duration-300" + onClick={(e) => { + e.preventDefault(); + e.stopPropagation(); + setDbSelectionMenuOpen(false); + if (session.currentSaveState === save.id) { + dispatch(clearQB()); + dispatch(clearSchema()); + } + wsDeleteState(save.id); + dispatch(deleteSaveState(save.id)); + }} + > + <Tooltip> + <TooltipTrigger> + <Delete /> + </TooltipTrigger> + <TooltipContent side={'top'}> + <p>Delete the database</p> + </TooltipContent> + </Tooltip> + </div> </div> - </div> + )} </li> ))} </DropdownItemContainer> diff --git a/apps/web/src/components/navbar/DatabaseManagement/forms/databaseForm.tsx b/apps/web/src/components/navbar/DatabaseManagement/forms/databaseForm.tsx index 142fb97a612016c4c9547dbbf9425231cf844580..db78c47401a7861c44ec01af0120bd69174bc22d 100644 --- a/apps/web/src/components/navbar/DatabaseManagement/forms/databaseForm.tsx +++ b/apps/web/src/components/navbar/DatabaseManagement/forms/databaseForm.tsx @@ -80,7 +80,6 @@ export const DatabaseForm = (props: { data: SaveStateI; onChange: (data: SaveSta <div className="flex w-full gap-2"> <Input type="dropdown" - className="w-full" label="Database Type" required value={databaseNameMapping[formData.db.type]} diff --git a/apps/web/src/components/navbar/DatabaseManagement/forms/settings.tsx b/apps/web/src/components/navbar/DatabaseManagement/forms/settings.tsx index 1c761a6a293617198708186c3b2b5b7b5b294722..bf84e5acfd0279d69be607138e670d517fb05a08 100644 --- a/apps/web/src/components/navbar/DatabaseManagement/forms/settings.tsx +++ b/apps/web/src/components/navbar/DatabaseManagement/forms/settings.tsx @@ -9,7 +9,7 @@ import { nilUUID, } from '@graphpolaris/shared/lib/data-access'; import { ErrorOutline } from '@mui/icons-material'; -import { Dialog, DialogContent } from '@graphpolaris/shared/lib/components/layout'; +import { Dialog } from '@graphpolaris/shared/lib/components/layout'; import { Button } from '@graphpolaris/shared/lib/components/buttons'; import { useImmer } from 'use-immer'; import { addSaveState, testedSaveState } from '@graphpolaris/shared/lib/data-access/store/sessionSlice'; @@ -113,96 +113,87 @@ export const SettingsForm = (props: { onClose(): void; open: 'add' | 'update'; s } return ( - <Dialog - open={!!props.open} - onOpenChange={(ret) => { - if (!ret) props.onClose; - }} - > - <DialogContent className="lg:min-w-[50rem]"> - <div className="flex justify-between align-center"> - <h2 className="text-xl font-bold">{formTitle} Database Connection</h2> - <div> - {sampleDataPanel === true ? ( - <Button variant="outline" label="Go back" onClick={() => setSampleDataPanel(false)} /> - ) : sampleDataPanel === false ? ( - <> - <h1 className="font-light text-xs">No data?</h1> - <p className="font-light text-sm cursor-pointer underline" onClick={() => setSampleDataPanel(true)}> - Try sample data - </p> - </> - ) : ( - '' - )} - </div> - </div> - - <> + <Dialog open={!!props.open} onClose={props.onClose} className="lg:min-w-[50rem]"> + <div className="flex justify-between align-center"> + <h2 className="text-xl font-bold">{formTitle} Database Connection</h2> + <div> {sampleDataPanel === true ? ( - <SampleDatabaseSelector - onClick={(data) => { - setHasError(false); - handleSubmit({ ...data, user_id: auth.userID || '' }); - }} - /> + <Button variant="outline" label="Go back" onClick={() => setSampleDataPanel(false)} /> + ) : sampleDataPanel === false ? ( + <> + <h1 className="font-light text-xs">No data?</h1> + <p className="font-light text-sm cursor-pointer underline" onClick={() => setSampleDataPanel(true)}> + Try sample data + </p> + </> ) : ( - <DatabaseForm - data={formData} - onChange={(data: SaveStateI, error: boolean) => { - setFormData({ ...data, id: formData.id }); - setHasError(error); - }} - /> + '' )} + </div> + </div> - {!(connection.status === null) && ( - <div className={`flex flex-col justify-center items-center`}> - <div className="flex justify-center items-center"> - {connection.verified === false && <ErrorOutline className="text-secondary-400" />} - <p className="font-light text-sm text-secondary-400 ">{connection.status}</p> - </div> - {connection.verified === null && <progress className="progress w-56"></progress>} + <> + {sampleDataPanel === true ? ( + <SampleDatabaseSelector + onClick={(data) => { + setHasError(false); + handleSubmit({ ...data, user_id: auth.userID || '' }); + }} + /> + ) : ( + <DatabaseForm + data={formData} + onChange={(data: SaveStateI, error: boolean) => { + setFormData({ ...data, id: formData.id }); + setHasError(error); + }} + /> + )} + + {!(connection.status === null) && ( + <div className={`flex flex-col justify-center items-center`}> + <div className="flex justify-center items-center"> + {connection.verified === false && <ErrorOutline className="text-secondary-400" />} + <p className="font-light text-sm text-secondary-400 ">{connection.status}</p> </div> - )} + {connection.verified === null && <progress className="progress w-56"></progress>} + </div> + )} - <div - className={`pt-4 flex flex-row gap-3 card-actions w-full justify-stretch items-center ${sampleDataPanel === true && 'hidden'}`} - > + <div className={`flex flex-row gap-3 card-actions w-full justify-stretch items-center ${sampleDataPanel === true && 'hidden'}`}> + <Button + type="primary" + className="flex-grow" + label={connection.updating ? formTitle.slice(0, -1) + 'ing...' : formTitle} + onClick={(event) => { + event.preventDefault(); + handleSubmit(); + }} + disabled={connection.updating || hasError} + /> + {props.open === 'update' && ( <Button - variantType="primary" + type="secondary" className="flex-grow" - label={connection.updating ? formTitle.slice(0, -1) + 'ing...' : formTitle} + label={'Clone'} onClick={(event) => { - event.preventDefault(); - handleSubmit(); + handleSubmit({ ...formData, name: formData.name + ' (copy)', id: nilUUID }, true); }} disabled={connection.updating || hasError} /> - {props.open === 'update' && ( - <Button - variantType="secondary" - className="flex-grow" - label={'Clone'} - onClick={(event) => { - handleSubmit({ ...formData, name: formData.name + ' (copy)', id: nilUUID }, true); - }} - disabled={connection.updating || hasError} - /> - )} - <Button - variant="outline" - className="flex-grow" - label="Cancel" - disabled={props.disableCancel} - onClick={(event) => { - event.preventDefault(); - closeDialog(); - }} - /> - </div> - </> - </DialogContent> + )} + <Button + variant="outline" + className="flex-grow" + label="Cancel" + disabled={props.disableCancel} + onClick={(event) => { + event.preventDefault(); + closeDialog(); + }} + /> + </div> + </> </Dialog> ); }; diff --git a/apps/web/src/components/navbar/navbar.tsx b/apps/web/src/components/navbar/navbar.tsx index d6c6923a71a7b5e705e98abf9efeb90f3385f882..f9c975f77cfa4502628b185ebfd94f72727a0b5c 100644 --- a/apps/web/src/components/navbar/navbar.tsx +++ b/apps/web/src/components/navbar/navbar.tsx @@ -15,7 +15,6 @@ import { useAuthorizationCache, useAuth } from '@graphpolaris/shared/lib/data-ac import DatabaseSelector from './DatabaseManagement/dbConnectionSelector'; import { DropdownItem, DropdownItemContainer } from '@graphpolaris/shared/lib/components/dropdowns'; import GpLogo from './gp-logo'; -import { Popover, PopoverContent, PopoverTrigger } from '@graphpolaris/shared/lib/components/layout/Popover'; export const Navbar = () => { const dropdownRef = useRef<HTMLDivElement>(null); @@ -46,17 +45,15 @@ export const Navbar = () => { <div className="ml-auto"> <div className="w-fit" ref={dropdownRef}> - <Popover> - <PopoverTrigger> - <div - className="relative inline-flex items-center justify-center w-8 h-8 overflow-hidden bg-secondary-500 rounded-full hover:bg-secondary-600 transition-colors duration-150 ease-in-out cursor-pointer" - onClick={() => setMenuOpen(!menuOpen)} - > - <span className="font-medium text-light">{authCache.username?.slice(0, 2).toUpperCase()}</span> - </div> - </PopoverTrigger> + <div + className="relative inline-flex items-center justify-center w-8 h-8 overflow-hidden bg-secondary-500 rounded-full hover:bg-secondary-600 transition-colors duration-150 ease-in-out cursor-pointer" + onClick={() => setMenuOpen(!menuOpen)} + > + <span className="font-medium text-light">{authCache.username?.slice(0, 2).toUpperCase()}</span> + </div> - <PopoverContent className="w-56 z-30 bg-white rounded-sm border-[1px]"> + {menuOpen && ( + <DropdownItemContainer className="w-56 z-30" align="right-3"> <div className="p-2 text-sm border-b"> <h2 className="font-bold">user: {authCache.username}</h2> <h3 className="text-xs break-words">session: {authCache.sessionID}</h3> @@ -70,6 +67,14 @@ export const Navbar = () => { auth.newShareRoom(); }} /> + <DropdownItem + value="Advanced" + submenu={ + <> + <DropdownItem value="TBD" onClick={() => {}} /> + </> + } + /> <DropdownItem value="Settings" onClick={() => {}} /> <DropdownItem value="Log out" onClick={() => {}} /> </> @@ -87,8 +92,8 @@ export const Navbar = () => { <div className="p-2 border-t"> <h3 className="text-xs">Version: {buildInfo}</h3> </div> - </PopoverContent> - </Popover> + </DropdownItemContainer> + )} </div> </div> </nav> diff --git a/apps/web/src/main.css b/apps/web/src/main.css index d4d0780e21e06bcf52273ff6eb6a671f4a8865a2..b05311668417118d4d3585830d420c70004e5f31 100644 --- a/apps/web/src/main.css +++ b/apps/web/src/main.css @@ -24,6 +24,11 @@ body { border: 1px solid hsl(var(--clr-sec--200)); } +.tooltip::before { + @apply z-50; + @apply content-[attr(data-tip)]; +} + /* TODO: Find out if this is being used before removing. .react-grid-layout { diff --git a/libs/shared/lib/components/DesignGuides/styleGuide.mdx b/libs/shared/lib/components/DesignGuides/styleGuide.mdx index 00c29bc5a1683ad01e93e52e651dae0bb23971bb..f840a99e78294418fd6e1421a2b13c7d47c6ef3e 100644 --- a/libs/shared/lib/components/DesignGuides/styleGuide.mdx +++ b/libs/shared/lib/components/DesignGuides/styleGuide.mdx @@ -908,5 +908,3 @@ To add a new component, include the following files: ``` ``` - -variantType diff --git a/libs/shared/lib/components/buttons/Button.tsx b/libs/shared/lib/components/buttons/Button.tsx deleted file mode 100644 index 91aa5b33e1a76e030b4bce41b7a5a5ff53bc48ae..0000000000000000000000000000000000000000 --- a/libs/shared/lib/components/buttons/Button.tsx +++ /dev/null @@ -1,161 +0,0 @@ -import React, { ReactElement, useMemo } from 'react'; -import styles from './buttons.module.scss'; -import Icon, { Sizes } from '../icon'; -import { forwardRef } from 'react'; - -type ButtonProps = { - as?: 'button' | 'a' | 'div'; - variantType?: 'primary' | 'secondary' | 'danger'; - variant?: 'solid' | 'outline' | 'ghost'; - size?: '2xs' | 'xs' | 'sm' | 'md' | 'lg'; - label?: string; - rounded?: boolean; - disabled?: boolean; - block?: boolean; - onClick?: (e: any) => void; - href?: string; - iconComponent?: React.ReactElement; - iconPosition?: 'leading' | 'trailing'; - ariaLabel?: string; - children?: React.ReactNode; - className?: string; -}; - -export const Button = React.forwardRef<HTMLButtonElement | HTMLAnchorElement | HTMLDivElement, ButtonProps>( - ( - { - as = 'button', - variantType = 'secondary', - variant = 'solid', - label, - size = 'md', - rounded = false, - disabled = false, - onClick, - href, - block = false, - iconComponent, - iconPosition = 'leading', - ariaLabel, - className, - children, - ...props - }, - forwardedRef, - ) => { - let typeClass = useMemo(() => { - switch (variantType) { - case 'primary': - return styles['btn-primary']; - case 'secondary': - return styles['btn-secondary']; - case 'danger': - return styles['btn-danger']; - default: - return styles['btn-secondary']; - } - }, [variantType]); - - let variantClass = useMemo(() => { - switch (variant) { - case 'solid': - return styles['btn-solid']; - case 'outline': - return styles['btn-outline']; - case 'ghost': - return styles['btn-ghost']; - default: - return styles['btn-solid']; - } - }, [variant]); - - let sizeClass = useMemo(() => { - switch (size) { - case '2xs': - return styles['btn-2xs']; - case 'xs': - return styles['btn-xs']; - case 'sm': - return styles['btn-sm']; - case 'md': - return styles['btn-md']; - case 'lg': - return styles['btn-lg']; - default: - return styles['btn-md']; - } - }, [size]); - - const iconSize = useMemo(() => { - switch (size) { - case '2xs': - return 12; - case 'xs': - return 16; - case 'sm': - return 20; - case 'md': - return 24; - case 'lg': - return 28; - default: - return 24; - } - }, [size]); - - const blockClass = useMemo(() => (block ? styles['btn-block'] : ''), [block, styles]); - const roundedClass = useMemo(() => (rounded ? styles['btn-rounded'] : ''), [rounded, styles]); - - const icon = useMemo( - () => (iconComponent ? <Icon component={iconComponent} size={iconSize} className="ml-auto" /> : null), - [iconComponent, iconSize], - ); - - const iconOnlyClass = useMemo( - () => (iconComponent && !label && !children ? styles['btn-icon-only'] : ''), - [iconComponent, label, children], - ); - - const ButtonComponent = as; - - const isAnchor = as === 'a'; - - return ( - <ButtonComponent - className={`${styles.btn} ${typeClass} ${variantClass} ${sizeClass} ${blockClass} ${roundedClass} ${iconOnlyClass} ${className}`} - onClick={onClick} - disabled={disabled} - aria-label={ariaLabel} - href={isAnchor ? href : undefined} - ref={forwardedRef as React.RefObject<any>} - {...props} - > - {iconPosition === 'leading' && icon} - {label && <span>{label}</span>} - {children && <span>{children}</span>} - {iconPosition === 'trailing' && icon} - </ButtonComponent> - ); - }, -); - -type ButtonGroupProps = { - children: React.ReactNode; -}; - -export function ButtonGroup({ children }: ButtonGroupProps) { - return <div>{children}</div>; -} - -type ButtonItemProps = { - icon: React.ReactNode; - onClick: () => void; -}; - -export function ButtonGroupItem({ icon, onClick }: ButtonItemProps) { - return ( - <div onClick={onClick} className="rounded-sm bg-secondary-50 p-2"> - <span>{icon}</span> - </div> - ); -} diff --git a/libs/shared/lib/components/buttons/button.stories.tsx b/libs/shared/lib/components/buttons/button.stories.tsx index 69931feb8eba7b7bbb478fe231275b83a20af15e..ba7b835680434706b159f00ce33067c568d8859e 100644 --- a/libs/shared/lib/components/buttons/button.stories.tsx +++ b/libs/shared/lib/components/buttons/button.stories.tsx @@ -48,7 +48,7 @@ type Story = StoryObj<typeof Button>; const BaseStory: Story = { args: { - variantType: 'primary', + type: 'primary', variant: 'solid', label: 'Click me', size: 'md', @@ -63,14 +63,14 @@ export const Primary = { ...BaseStory }; export const Secondary: Story = { args: { ...BaseStory.args, - variantType: 'secondary', + type: 'secondary', }, }; export const Danger: Story = { args: { ...BaseStory.args, - variantType: 'danger', + type: 'danger', }, }; @@ -97,7 +97,7 @@ export const Ghost: Story = { export const IconButton: Story = { args: { - variantType: 'primary', + type: 'primary', variant: 'outline', iconComponent: <ArrowBack />, rounded: true, diff --git a/libs/shared/lib/components/buttons/index.tsx b/libs/shared/lib/components/buttons/index.tsx index 8b166a86e4df1fb59d7102ab602d9fb675ff1ec3..38ea1a0c366475746561e049a3551bb2241da9ac 100644 --- a/libs/shared/lib/components/buttons/index.tsx +++ b/libs/shared/lib/components/buttons/index.tsx @@ -1 +1,161 @@ -export * from './Button'; +import React, { ReactElement, useMemo } from 'react'; +import styles from './buttons.module.scss'; +import Icon, { Sizes } from '../icon'; +import { forwardRef } from 'react'; + +type ButtonProps = { + as?: 'button' | 'a' | 'div'; + type?: 'primary' | 'secondary' | 'danger'; + variant?: 'solid' | 'outline' | 'ghost'; + size?: '2xs' | 'xs' | 'sm' | 'md' | 'lg'; + label?: string; + rounded?: boolean; + disabled?: boolean; + block?: boolean; + onClick?: (e: any) => void; + href?: string; + iconComponent?: React.ReactElement; + iconPosition?: 'leading' | 'trailing'; + ariaLabel?: string; + children?: React.ReactNode; + className?: string; +}; + +export const Button = React.forwardRef<HTMLButtonElement | HTMLAnchorElement | HTMLDivElement, ButtonProps>( + ( + { + as = 'button', + type = 'secondary', + variant = 'solid', + label, + size = 'md', + rounded = false, + disabled = false, + onClick, + href, + block = false, + iconComponent, + iconPosition = 'leading', + ariaLabel, + className, + children, + ...props + }, + forwardedRef, + ) => { + let typeClass = useMemo(() => { + switch (type) { + case 'primary': + return styles['btn-primary']; + case 'secondary': + return styles['btn-secondary']; + case 'danger': + return styles['btn-danger']; + default: + return styles['btn-secondary']; + } + }, [type]); + + let variantClass = useMemo(() => { + switch (variant) { + case 'solid': + return styles['btn-solid']; + case 'outline': + return styles['btn-outline']; + case 'ghost': + return styles['btn-ghost']; + default: + return styles['btn-solid']; + } + }, [variant]); + + let sizeClass = useMemo(() => { + switch (size) { + case '2xs': + return styles['btn-2xs']; + case 'xs': + return styles['btn-xs']; + case 'sm': + return styles['btn-sm']; + case 'md': + return styles['btn-md']; + case 'lg': + return styles['btn-lg']; + default: + return styles['btn-md']; + } + }, [size]); + + const iconSize = useMemo(() => { + switch (size) { + case '2xs': + return 12; + case 'xs': + return 16; + case 'sm': + return 20; + case 'md': + return 24; + case 'lg': + return 28; + default: + return 24; + } + }, [size]); + + const blockClass = useMemo(() => (block ? styles['btn-block'] : ''), [block, styles]); + const roundedClass = useMemo(() => (rounded ? styles['btn-rounded'] : ''), [rounded, styles]); + + const icon = useMemo( + () => (iconComponent ? <Icon component={iconComponent} size={iconSize} className="ml-auto" /> : null), + [iconComponent, iconSize], + ); + + const iconOnlyClass = useMemo( + () => (iconComponent && !label && !children ? styles['btn-icon-only'] : ''), + [iconComponent, label, children], + ); + + const ButtonComponent = as; + + const isAnchor = as === 'a'; + + return ( + <ButtonComponent + className={`${styles.btn} ${typeClass} ${variantClass} ${sizeClass} ${blockClass} ${roundedClass} ${iconOnlyClass} ${className}`} + onClick={onClick} + disabled={disabled} + aria-label={ariaLabel} + href={isAnchor ? href : undefined} + ref={forwardedRef as React.RefObject<any>} + {...props} + > + {iconPosition === 'leading' && icon} + {label && <span>{label}</span>} + {children && <span>{children}</span>} + {iconPosition === 'trailing' && icon} + </ButtonComponent> + ); + }, +); + +type ButtonGroupProps = { + children: React.ReactNode; +}; + +export function ButtonGroup({ children }: ButtonGroupProps) { + return <div>{children}</div>; +} + +type ButtonItemProps = { + icon: React.ReactNode; + onClick: () => void; +}; + +export function ButtonGroupItem({ icon, onClick }: ButtonItemProps) { + return ( + <div onClick={onClick} className="rounded-sm bg-secondary-50 p-2"> + <span>{icon}</span> + </div> + ); +} diff --git a/libs/shared/lib/components/buttons/overview.mdx b/libs/shared/lib/components/buttons/overview.mdx index 810e456830aefded7b1c5981fbb4c3bdd4ee1984..2739cf127245fb97d27209ae8c89c08282178e55 100644 --- a/libs/shared/lib/components/buttons/overview.mdx +++ b/libs/shared/lib/components/buttons/overview.mdx @@ -73,4 +73,3 @@ A button is used a lot in GP. <Button block type="primary" size="md" label="Click me" onClick={() => alert('Button clicked')} /> </div> </div> -variantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantType diff --git a/libs/shared/lib/components/colorComponents/colorDropdown/index.tsx b/libs/shared/lib/components/colorComponents/colorDropdown/index.tsx index 4dcea6e51a452087b9a09b1b86ef08c9506c5d09..a14eaa6cffd4d17fcc94c45f8e80837046ea7d09 100644 --- a/libs/shared/lib/components/colorComponents/colorDropdown/index.tsx +++ b/libs/shared/lib/components/colorComponents/colorDropdown/index.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { DropdownTrigger, DropdownContainer, DropdownItemContainer } from '@graphpolaris/shared/lib/components/dropdowns'; +import { DropdownButton, DropdownContainer, DropdownItemContainer } from '@graphpolaris/shared/lib/components/dropdowns'; import ColorLegend from '../colorLegend/index.js'; import { DimensionType } from '@graphpolaris/shared/lib/schema/index.js'; import { dataColors } from 'config'; @@ -48,6 +48,11 @@ export const DropdownColorLegend = ({ value, onChange, dimension, distribution } const [menuOpen, setMenuOpen] = useState<boolean>(false); const [selectedOption, setSelectedOption] = useState<any>('Select colormap'); + const handleButtonClick = (e: React.MouseEvent<HTMLButtonElement>) => { + e.preventDefault(); + setMenuOpen(!menuOpen); + }; + const handleOptionClick = (option: string) => { setSelectedOption(option); setSelectedColorLegend(colorStructure[option]); @@ -56,8 +61,8 @@ export const DropdownColorLegend = ({ value, onChange, dimension, distribution } return ( <div className="w-200 h-200"> - <DropdownContainer> - <DropdownTrigger + <DropdownContainer className="w-full"> + <DropdownButton title={ <div className="flex items-center h-4"> {selectedColorLegend ? ( @@ -72,20 +77,23 @@ export const DropdownColorLegend = ({ value, onChange, dimension, distribution } )} </div> } + onClick={handleButtonClick} /> - <DropdownItemContainer className="w-60"> - {Object.keys(colorStructure).map((option: any, index) => ( - <li key={index} onClick={() => handleOptionClick(option)} className="cursor-pointer flex items-center ml-2 h-4 m-2"> - <ColorLegend - key={index.toString() + '_colorLegend'} - colors={colorStructure[option].colors} - data={colorStructure[option].data} - name={colorStructure[option].name} - showAxis={colorStructure[option].showAxis} - /> - </li> - ))} - </DropdownItemContainer> + {menuOpen && ( + <DropdownItemContainer align="top-10" className="w-60"> + {Object.keys(colorStructure).map((option: any, index) => ( + <li key={index} onClick={() => handleOptionClick(option)} className="cursor-pointer flex items-center ml-2 h-4 m-2"> + <ColorLegend + key={index.toString() + '_colorLegend'} + colors={colorStructure[option].colors} + data={colorStructure[option].data} + name={colorStructure[option].name} + showAxis={colorStructure[option].showAxis} + /> + </li> + ))} + </DropdownItemContainer> + )} </DropdownContainer> </div> ); diff --git a/libs/shared/lib/components/dropdowns/index.tsx b/libs/shared/lib/components/dropdowns/index.tsx index 7a56352d39aff1b3a8d870826a0100c827b4b518..dbc2ce4b9ec37f14a85c7adf40a9195cb9369e40 100644 --- a/libs/shared/lib/components/dropdowns/index.tsx +++ b/libs/shared/lib/components/dropdowns/index.tsx @@ -2,20 +2,31 @@ import React, { useState, useEffect, useRef, ReactNode } from 'react'; import styles from './dropdowns.module.scss'; import Icon from '../icon'; import { ArrowDropDown } from '@mui/icons-material'; -import { PopoverContent, PopoverTrigger, Popover } from '../layout/Popover'; -export const DropdownContainer = Popover; +type DropdownContainerProps = { + children: ReactNode; + className?: string; +}; + +export const DropdownContainer = React.forwardRef<HTMLDivElement, DropdownContainerProps>( + ({ children, className }, ref: React.ForwardedRef<HTMLDivElement>) => { + return ( + <div className={`relative inline-block text-left ${className && className}`} ref={ref}> + {children} + </div> + ); + }, +); -type DropdownTriggerProps = { +type DropdownButtonProps = { title: string | ReactNode; + onClick: (e: React.MouseEvent<HTMLButtonElement>) => void; size?: 'xs' | 'sm' | 'md' | 'xl'; disabled?: boolean; variant?: 'primary' | 'ghost' | 'outline'; - className?: string; - onClick?: () => void; }; -export function DropdownTrigger({ title, size, disabled, variant, className, onClick }: DropdownTriggerProps) { +export function DropdownButton({ title, onClick, size, disabled, variant }: DropdownButtonProps) { const paddingClass = size === 'xs' ? 'py-0' : size === 'sm' ? 'px-1 py-1' : size === 'md' ? 'px-2 py-1' : 'px-4 py-2'; const textSizeClass = size === 'xs' ? 'text-xs' : size === 'sm' ? 'text-sm' : size === 'md' ? 'text-base' : 'text-lg'; @@ -26,37 +37,38 @@ export function DropdownTrigger({ title, size, disabled, variant, className, onC ? 'bg-transparent shadow-none' : 'border rounded bg-transparent'; return ( - <PopoverTrigger onClick={onClick}> - <div - className={`inline-flex w-full truncate justify-between items-center gap-x-1.5 ${variantClass} ${textSizeClass} ${paddingClass} text-secondary-900 shadow-sm hover:bg-secondary-50 disabled:bg-secondary-100 disabled:cursor-not-allowed disabled:text-secondary-400 pl-1 truncate${className ? ` ${className}` : ''}`} + <> + <button + className={`inline-flex w-full justify-between items-center gap-x-1.5 ${variantClass} ${textSizeClass} ${paddingClass} text-secondary-900 shadow-sm hover:bg-secondary-50 disabled:bg-secondary-100 disabled:cursor-not-allowed disabled:text-secondary-400 pl-1 truncate`} + onClick={onClick} + disabled={disabled} > <span className={`text-${size}`}>{title}</span> <Icon component={<ArrowDropDown />} size={16} /> - </div> - </PopoverTrigger> + </button> + </> ); } type DropdownItemContainerProps = { - // align: string; + align: string; className?: string; children: ReactNode; }; -export const DropdownItemContainer = React.forwardRef<HTMLDivElement, DropdownItemContainerProps>(({ children, className }, ref) => { +export function DropdownItemContainer({ align, className, children }: DropdownItemContainerProps) { return ( - <PopoverContent - ref={ref} - className={`${styles['dropdown-container']} ${className} bg-light`} + <div + className={`${styles['dropdown-container']} ${align} ${className} bg-light`} role="menu" aria-orientation="vertical" aria-labelledby="menu-button" tabIndex={-1} > <ul role="none">{children}</ul> - </PopoverContent> + </div> ); -}); +} type DropdownItemProps = { value: string; @@ -64,10 +76,9 @@ type DropdownItemProps = { className?: string; onClick?: (value: string) => void; submenu?: React.ReactNode; - selected?: boolean; }; -export function DropdownItem({ value, disabled, className, onClick, submenu, selected }: DropdownItemProps) { +export function DropdownItem({ value, disabled, className, onClick, submenu }: DropdownItemProps) { const itemRef = useRef(null); const submenuRef = useRef(null); const [isSubmenuOpen, setIsSubmenuOpen] = useState(false); @@ -75,7 +86,7 @@ export function DropdownItem({ value, disabled, className, onClick, submenu, sel return ( <li ref={itemRef} - className={`${styles['dropdown-item']} ${className && className} hover:bg-primary-100 ${selected ? 'bg-primary text-white hover:text-black' : ''}`} + className={`${styles['dropdown-item']} ${className && className} hover:bg-primary-100`} onClick={() => { !disabled && onClick && onClick(value); }} @@ -99,3 +110,49 @@ export const DropdownSubmenuContainer = React.forwardRef<HTMLDivElement, Dropdow </div> ); }); + +type DropdownProps = { + title: string; + options: Record<string, () => void>; + align: 'left-0' | 'right-0'; + closeOnClick?: boolean; + size?: 'xs' | 'sm' | 'md' | 'xl'; +}; + +export function MenuDropdown({ title, options, align = 'left-0', closeOnClick = true, size = 'sm' }: DropdownProps) { + const dropdownRef = useRef<HTMLDivElement>(null); + const [isDropdownOpen, setIsDropdownOpen] = useState<boolean>(false); + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { + setIsDropdownOpen(false); + } + }; + if (isDropdownOpen) document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [isDropdownOpen]); + + return ( + <DropdownContainer ref={dropdownRef}> + <DropdownButton title={title} onClick={(e) => setIsDropdownOpen(!isDropdownOpen)} size={size} /> + {isDropdownOpen && ( + <DropdownItemContainer align={align}> + {options && + Object.keys(options).map((key, index) => ( + <DropdownItem + key={index} + value={key} + onClick={() => { + options[key](); + closeOnClick && setIsDropdownOpen(false); + }} + /> + ))} + </DropdownItemContainer> + )} + </DropdownContainer> + ); +} diff --git a/libs/shared/lib/components/dropdowns/menudropdown.stories.tsx b/libs/shared/lib/components/dropdowns/menudropdown.stories.tsx index 8e7481d90ce0002473c6516f64d813ac71ddd186..5f51fd829691947b73341762425425b120dc02c9 100644 --- a/libs/shared/lib/components/dropdowns/menudropdown.stories.tsx +++ b/libs/shared/lib/components/dropdowns/menudropdown.stories.tsx @@ -1,15 +1,15 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; -// import { MenuDropdown } from '.'; +import { MenuDropdown } from '.'; -// const Component: Meta<typeof MenuDropdown> = { -// title: 'Components/Menu', -// component: MenuDropdown, -// decorators: [(Story) => <div className="m-5">{Story()}</div>], -// }; +const Component: Meta<typeof MenuDropdown> = { + title: 'Components/Menu', + component: MenuDropdown, + decorators: [(Story) => <div className="m-5">{Story()}</div>], +}; -// export default Component; -// type Story = StoryObj<typeof Component>; +export default Component; +type Story = StoryObj<typeof Component>; // export const Dropdown: Story = { // args: { diff --git a/libs/shared/lib/components/forms/index.tsx b/libs/shared/lib/components/forms/index.tsx index 366b045d1249d5fab4932fb7e48a7d52d9821fbb..a4bb743278f6c96fe45302628733d1699d10b7fd 100644 --- a/libs/shared/lib/components/forms/index.tsx +++ b/libs/shared/lib/components/forms/index.tsx @@ -2,7 +2,6 @@ import React, { PropsWithChildren } from 'react'; import { Button } from '../buttons'; import { Close } from '@mui/icons-material'; -/** @deprecated */ export const FormDiv = React.forwardRef<HTMLDivElement, PropsWithChildren<{ className?: string; hAnchor?: string; offset?: string }>>( (props, ref) => { const dialogRef = React.useRef<HTMLDivElement | null>(null); @@ -76,13 +75,13 @@ export const FormBody = ({ children, ...props }: PropsWithChildren<React.DetailedHTMLProps<React.FormHTMLAttributes<HTMLFormElement>, HTMLFormElement>>) => ( - <form className="px-0 w-72 py-2" {...props}> + <form className="card-body px-0 w-72 py-0" {...props}> {children} </form> ); export const FormTitle = ({ children, title, onClose }: PropsWithChildren<{ title: string; onClose?: () => void }>) => { return ( - <div className="font-semibold p-5 py-0 flex w-full"> + <div className="card-title p-5 py-0 mt-2 flex w-full"> <h2 className="w-full">{title}</h2> {onClose && <Button rounded variant="ghost" iconComponent={<Close />} onClick={() => onClose()} />} </div> @@ -95,7 +94,7 @@ export const FormActions = (props: { onClose?: () => void; onApply?: () => void {props.onClose && ( <div className="grid grid-cols-2 px-5 gap-2 mb-2"> <Button - variantType="secondary" + type="secondary" variant="outline" label="Cancel" onClick={(e) => { @@ -104,7 +103,7 @@ export const FormActions = (props: { onClose?: () => void; onApply?: () => void }} /> <Button - variantType="primary" + type="primary" label="Apply" onClick={() => { if (props.onApply) props.onApply(); @@ -115,7 +114,7 @@ export const FormActions = (props: { onClose?: () => void; onApply?: () => void )} {!props.onClose && ( <Button - variantType="primary" + type="primary" label="Apply" onClick={() => { if (props.onApply) props.onApply(); diff --git a/libs/shared/lib/components/info/index.tsx b/libs/shared/lib/components/info/index.tsx index 6bb08d1234fbf3a2b9b37cb6b976903daf62dc45..d99e13ecb3156c65507d92bebf4cee7244ad0300 100644 --- a/libs/shared/lib/components/info/index.tsx +++ b/libs/shared/lib/components/info/index.tsx @@ -1,6 +1,6 @@ import React from 'react'; import Icon from '../icon'; -import { Tooltip, TooltipContent, TooltipTrigger } from '../tooltip'; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../tooltip'; import { InfoOutlined } from '@mui/icons-material'; type Props = { @@ -10,13 +10,15 @@ type Props = { export default function Info({ tooltip, side = 'left' }: Props) { return ( - <Tooltip> - <TooltipTrigger> - <Icon component={<InfoOutlined />} size={14} /> - </TooltipTrigger> - <TooltipContent side={side}> - <p>{tooltip}</p> - </TooltipContent> - </Tooltip> + <TooltipProvider delayDuration={0}> + <Tooltip> + <TooltipTrigger> + <Icon component={<InfoOutlined />} size={14} /> + </TooltipTrigger> + <TooltipContent side={side}> + <p>{tooltip}</p> + </TooltipContent> + </Tooltip> + </TooltipProvider> ); } diff --git a/libs/shared/lib/components/inputs/index.tsx b/libs/shared/lib/components/inputs/index.tsx index b2160102c90443eccff3262de542aada1f23a60d..86d440b596b246f47cb4f33b2e97cf8e6504ce1d 100644 --- a/libs/shared/lib/components/inputs/index.tsx +++ b/libs/shared/lib/components/inputs/index.tsx @@ -1,9 +1,7 @@ import React from 'react'; import styles from './inputs.module.scss'; -import { DropdownTrigger, DropdownContainer, DropdownItem, DropdownItemContainer } from '../dropdowns'; +import { DropdownButton, DropdownContainer, DropdownItem, DropdownItemContainer } from '../dropdowns'; import Info from '../info'; -import { Tooltip, TooltipContent, TooltipTrigger } from '../tooltip'; -import { Popover } from '../layout/Popover'; type SliderProps = { label: string; @@ -125,36 +123,31 @@ export const Input = (props: InputProps) => { export const SliderInput = ({ label, value, min, max, step, unit, showValue = true, onChange, tooltip }: SliderProps) => { return ( - <Tooltip> - <TooltipTrigger> - <div className={styles['slider']}> - <label className="label flex flex-row justify-between items-end"> - <span className="label-text">{label}</span> - {showValue ? ( - <div className="label-text"> - {value} - {unit} - </div> - ) : null} - </label> + <div data-tip={tooltip || null} className={styles['slider'] + (tooltip ? ' tooltip' : '')}> + <label className="label flex flex-row justify-between items-end"> + <span className="label-text">{label}</span> + {showValue ? ( + <div className="label-text"> + {value} + {unit} + </div> + ) : null} + </label> - <input - type="range" - min={min} - max={max} - step={step} - value={value} - onChange={(e) => { - if (onChange) { - onChange(parseFloat(e.target.value)); - } - }} - aria-labelledby="input-slider" - /> - </div> - </TooltipTrigger> - {tooltip && <TooltipContent side={'top'}>{tooltip}</TooltipContent>} - </Tooltip> + <input + type="range" + min={min} + max={max} + step={step} + value={value} + onChange={(e) => { + if (onChange) { + onChange(parseFloat(e.target.value)); + } + }} + aria-labelledby="input-slider" + /> + </div> ); }; @@ -178,42 +171,44 @@ export const TextInput = ({ if (!tooltip && inline) tooltip = label; return ( - <Tooltip> - <TooltipTrigger className={styles['input'] + ' form-control w-full' + (inline ? ' grid grid-cols-2 items-center gap-0.5' : '')}> - {label && ( - <label className="label p-0"> - <span - className={`text-sm font-medium text-secondary-700 ${required && "after:content-['*'] after:ml-0.5 after:text-danger-500"}`} - > - {label} - </span> - {required && isValid ? null : <span className="label-text-alt text-error">{errorText}</span>} - {info && <Info tooltip={info} side={'left'} />} - </label> - )} - <input - type={visible ? 'text' : 'password'} - placeholder={placeholder} - className={ - `${size} bg-light border border-secondary-300 placeholder-secondary-400 focus:outline-none block w-full focus:ring-1 ${ - isValid ? '' : 'input-error' - }` + (className ? ` ${className}` : '') + <div + data-tip={tooltip || null} + className={ + styles['input'] + ' form-control w-full' + (inline ? ' grid grid-cols-2 items-center gap-0.5' : '') + (tooltip ? ' tooltip' : '') + } + > + {label && ( + <label className="label p-0"> + <span + className={`text-sm font-medium text-secondary-700 ${required && "after:content-['*'] after:ml-0.5 after:text-danger-500"}`} + > + {label} + </span> + {required && isValid ? null : <span className="label-text-alt text-error">{errorText}</span>} + {info && <Info tooltip={info} side={'left'} />} + </label> + )} + <input + type={visible ? 'text' : 'password'} + placeholder={placeholder} + className={ + `${size} bg-light border border-secondary-300 placeholder-secondary-400 focus:outline-none block w-full focus:ring-1 ${ + isValid ? '' : 'input-error' + }` + (className ? ` ${className}` : '') + } + value={value.toString()} + onChange={(e) => { + if (required && validate) { + setIsValid(validate(e.target.value)); } - value={value.toString()} - onChange={(e) => { - if (required && validate) { - setIsValid(validate(e.target.value)); - } - if (onChange) { - onChange(e.target.value); - } - }} - required={required} - disabled={disabled} - /> - </TooltipTrigger> - {tooltip && <TooltipContent side={'top'}>{tooltip}</TooltipContent>} - </Tooltip> + if (onChange) { + onChange(e.target.value); + } + }} + required={required} + disabled={disabled} + /> + </div> ); }; @@ -239,135 +234,128 @@ export const NumberInput = ({ if (!tooltip && inline) tooltip = label; return ( - <Tooltip> - <TooltipTrigger className={styles['input'] + ' form-control w-full' + (inline ? ' grid grid-cols-2 items-center gap-0.5' : '')}> - <label className="label p-0"> - <span - className={`text-sm text-left truncate font-medium text-secondary-700 ${required && "after:content-['*'] after:ml-0.5 after:text-danger-500"}`} - > - {label} - </span> - {required && isValid ? null : <span className="label-text-alt text-error">{errorText}</span>} - {info && <Info tooltip={info} side={'left'} />} - </label> - <input - type="number" - placeholder={placeholder} - className={`${size} bg-light border border-secondary-300 placeholder-secondary-400 focus:outline-none block w-full sm:text-sm focus:ring-1 ${ - isValid ? '' : 'input-error' - }`} - value={value.toString()} - onChange={(e) => { - if (required && validate) { - setIsValid(validate(e.target.value)); - } - if (onChange) { - onChange(Number(e.target.value)); - } - }} - required={required} - disabled={disabled} - onKeyDown={onKeyDown} - max={max} - min={min} - /> - </TooltipTrigger> - {tooltip && <TooltipContent side={'top'}>{tooltip}</TooltipContent>} - </Tooltip> + <div + data-tip={tooltip || null} + className={ + styles['input'] + ' form-control w-full' + (inline ? ' grid grid-cols-2 items-center gap-0.5' : '') + (tooltip ? ' tooltip' : '') + } + > + <label className="label p-0"> + <span + className={`text-sm text-left truncate font-medium text-secondary-700 ${required && "after:content-['*'] after:ml-0.5 after:text-danger-500"}`} + > + {label} + </span> + {required && isValid ? null : <span className="label-text-alt text-error">{errorText}</span>} + {info && <Info tooltip={info} side={'left'} />} + </label> + <input + type="number" + placeholder={placeholder} + className={`${size} bg-light border border-secondary-300 placeholder-secondary-400 focus:outline-none block w-full sm:text-sm focus:ring-1 ${ + isValid ? '' : 'input-error' + }`} + value={value.toString()} + onChange={(e) => { + if (required && validate) { + setIsValid(validate(e.target.value)); + } + if (onChange) { + onChange(Number(e.target.value)); + } + }} + required={required} + disabled={disabled} + onKeyDown={onKeyDown} + max={max} + min={min} + /> + </div> ); }; export const RadioInput = ({ label, value, options, onChange, tooltip }: RadioProps) => { return ( - <Tooltip> - <TooltipTrigger> - <label className="label p-0"> - <span className="label-text">{label}</span> + <div data-tip={tooltip || null} className={tooltip ? 'tooltip' : ''}> + <label className="label p-0"> + <span className="label-text">{label}</span> + </label> + {options.map((option, index) => ( + <label key={index} className="label cursor-pointer w-fit gap-2 px-0 py-1"> + <input + type="radio" + name={option} + checked={value === option} + onChange={() => { + if (onChange) { + onChange(option); + } + }} + className="radio radio-xs radio-primary" + /> + <span className="label-text">{option}</span> </label> - {options.map((option, index) => ( - <label key={index} className="label cursor-pointer w-fit gap-2 px-0 py-1"> - <input - type="radio" - name={option} - checked={value === option} - onChange={() => { - if (onChange) { - onChange(option); - } - }} - className="radio radio-xs radio-primary" - /> - <span className="label-text">{option}</span> - </label> - ))} - </TooltipTrigger> - {tooltip && <TooltipContent side={'top'}>{tooltip}</TooltipContent>} - </Tooltip> + ))} + </div> ); }; export const CheckboxInput = ({ label, value, options, onChange, tooltip }: CheckboxProps) => { return ( - <Tooltip> - <TooltipTrigger> - {label && ( - <label className="label p-0"> - <span className="label-text">{label}</span> - </label> - )} - {options.map((option, index) => ( - <label key={index} className="label cursor-pointer w-fit gap-2 px-0 py-1"> - <input - type="checkbox" - name={option} - checked={Array.isArray(value) && value.includes(option)} - onClick={(event) => { - if (event.ctrlKey) { - const updatedValue = (event.target as any).checked ? [option] : value.filter((val) => val !== option); - if (onChange) { - onChange(updatedValue); - } - } else { - const updatedValue = (event.target as any).checked ? [...value, option] : value.filter((val) => val !== option); - if (onChange) { - onChange(updatedValue); - } - } - }} - onChange={() => { - // to remove warning - }} - className="checkbox checkbox-xs" - /> - <span className="label-text">{option}</span> - </label> - ))} - </TooltipTrigger> - {tooltip && <TooltipContent side={'top'}>{tooltip}</TooltipContent>} - </Tooltip> - ); -}; - -export const BooleanInput = ({ label, value, onChange, tooltip }: BooleanProps) => { - return ( - <Tooltip> - <TooltipTrigger> - <label className={`label cursor-pointer w-fit gap-2 px-0 py-1`}> - <span className="text-sm">{label}</span> + <div data-tip={tooltip || null} className={tooltip ? 'tooltip' : ''}> + {label && ( + <label className="label p-0"> + <span className="label-text">{label}</span> + </label> + )} + {options.map((option, index) => ( + <label key={index} className="label cursor-pointer w-fit gap-2 px-0 py-1"> <input type="checkbox" - checked={value} - onChange={(event) => { - if (onChange) { - onChange(event.target.checked); + name={option} + checked={Array.isArray(value) && value.includes(option)} + onClick={(event) => { + if (event.ctrlKey) { + const updatedValue = (event.target as any).checked ? [option] : value.filter((val) => val !== option); + if (onChange) { + onChange(updatedValue); + } + } else { + const updatedValue = (event.target as any).checked ? [...value, option] : value.filter((val) => val !== option); + if (onChange) { + onChange(updatedValue); + } } }} + onChange={() => { + // to remove warning + }} className="checkbox checkbox-xs" /> + <span className="label-text">{option}</span> </label> - </TooltipTrigger> - {tooltip && <TooltipContent side={'top'}>{tooltip}</TooltipContent>} - </Tooltip> + ))} + </div> + ); +}; + +export const BooleanInput = ({ label, value, onChange, tooltip }: BooleanProps) => { + return ( + <div data-tip={tooltip || null} className={tooltip ? 'tooltip' : ''}> + <label className={`label cursor-pointer w-fit gap-2 px-0 py-1`}> + <span className="text-sm">{label}</span> + <input + type="checkbox" + checked={value} + onChange={(event) => { + if (onChange) { + onChange(event.target.checked); + } + }} + className="checkbox checkbox-xs" + /> + </label> + </div> ); }; @@ -380,67 +368,74 @@ export const DropDownInput = ({ required = false, tooltip, size = 'sm', - inline = true, + inline = false, disabled = false, buttonVariant = 'primary', className = '', info, }: DropdownProps) => { + const dropdownRef = React.useRef<HTMLDivElement>(null); const [isDropdownOpen, setIsDropdownOpen] = React.useState<boolean>(false); if (!tooltip && inline) tooltip = label; + React.useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { + setIsDropdownOpen(false); + } + }; + if (isDropdownOpen) document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [isDropdownOpen]); return ( - <Tooltip> - <TooltipTrigger className={className + ' w-full' + (inline ? ' grid grid-cols-2 items-center gap-0.5' : '')}> - {label && ( - <label className="label p-0"> - <span - className={`text-sm text-left truncate font-medium text-secondary-700 ${required && "after:content-['*'] after:ml-0.5 after:text-danger-500"}`} - > - {label} - </span> - {info && <Info tooltip={info} />} - </label> - )} - <DropdownContainer - open={isDropdownOpen} - onOpenChange={(ref) => { - setIsDropdownOpen(ref); + <div + data-tip={tooltip || null} + className={className + ' w-full' + (inline ? ' grid grid-cols-2 items-center gap-0.5' : '') + (tooltip ? ' tooltip' : '')} + > + {label && ( + <label className="label p-0"> + <span + className={`text-sm text-left truncate font-medium text-secondary-700 ${required && "after:content-['*'] after:ml-0.5 after:text-danger-500"}`} + > + {label} + </span> + {info && <Info tooltip={info} />} + </label> + )} + <DropdownContainer className="w-full right-0 left-auto" ref={dropdownRef}> + <DropdownButton + variant={buttonVariant} + title={overrideRender || value} + size={size} + disabled={disabled} + onClick={(e) => { + e.stopPropagation(); + e.preventDefault(); + setIsDropdownOpen(!isDropdownOpen); }} - > - <DropdownTrigger - variant={buttonVariant} - title={overrideRender || value} - size={size} - className="" - disabled={disabled} - onClick={() => { - setIsDropdownOpen(!isDropdownOpen); - }} - /> - {isDropdownOpen && ( - <DropdownItemContainer className="w-fit"> - {options && - options.map((item: any, index: number) => ( - <DropdownItem - key={index} - value={item.toString()} - selected={value === item} - onClick={() => { - const parsedValue = typeof item === 'number' ? item.toString() : item; - if (onChange) { - onChange(parsedValue); - } - setIsDropdownOpen(false); - }} - /> - ))} - </DropdownItemContainer> - )} - </DropdownContainer> - </TooltipTrigger> - {tooltip && <TooltipContent side={'top'}>{tooltip}</TooltipContent>} - </Tooltip> + /> + {isDropdownOpen && ( + <DropdownItemContainer align="left-0"> + {options && + options.map((item: any, index: number) => ( + <DropdownItem + key={index} + value={item.toString()} + onClick={() => { + const parsedValue = typeof item === 'number' ? item.toString() : item; + if (onChange) { + onChange(parsedValue); + } + setIsDropdownOpen(false); + }} + /> + ))} + </DropdownItemContainer> + )} + </DropdownContainer> + </div> ); }; diff --git a/libs/shared/lib/components/layout/Dialog.tsx b/libs/shared/lib/components/layout/Dialog.tsx index 5166cc1361f4c3293cec7e344810bb375f99fb2e..75781e135187155ae552d737041d0b0aa9609768 100644 --- a/libs/shared/lib/components/layout/Dialog.tsx +++ b/libs/shared/lib/components/layout/Dialog.tsx @@ -1,210 +1,25 @@ -import * as React from 'react'; - import { useEffect, useRef } from 'react'; -import { - useFloating, - useClick, - useDismiss, - useRole, - useInteractions, - useMergeRefs, - FloatingPortal, - FloatingFocusManager, - FloatingOverlay, - useId, -} from '@floating-ui/react'; -import { Button } from '../buttons'; - -interface DialogOptions { - initialOpen?: boolean; - open?: boolean; - onOpenChange?: (open: boolean) => void; -} -export function useDialog({ initialOpen = false, open: controlledOpen, onOpenChange: setControlledOpen }: DialogOptions = {}): { +export type DialogProps = { + onClose: () => void; open: boolean; - setOpen: (open: boolean) => void; - interactions: ReturnType<typeof useInteractions>; - data: ReturnType<typeof useFloating>; - floatingContext: ReturnType<typeof useFloating>['context']; - labelId: string | undefined; - descriptionId: string | undefined; - setLabelId: React.Dispatch<React.SetStateAction<string | undefined>>; - setDescriptionId: React.Dispatch<React.SetStateAction<string | undefined>>; -} { - const [uncontrolledOpen, setUncontrolledOpen] = React.useState(initialOpen); - const [labelId, setLabelId] = React.useState<string | undefined>(); - const [descriptionId, setDescriptionId] = React.useState<string | undefined>(); - - const open = controlledOpen ?? uncontrolledOpen; - const setOpen = setControlledOpen ?? setUncontrolledOpen; - - const data = useFloating({ - open, - onOpenChange: setOpen, - }); - - const context = data.context; - - const click = useClick(context, { - enabled: controlledOpen == null, - }); - const dismiss = useDismiss(context, { outsidePressEvent: 'mousedown' }); - const role = useRole(context); - - const interactions = useInteractions([click, dismiss, role]); - - return React.useMemo( - () => ({ - open, - setOpen, - interactions: interactions, - data: data, - floatingContext: context, - labelId, - descriptionId, - setLabelId, - setDescriptionId, - }), - [open, setOpen, interactions, data, labelId, descriptionId], - ); -} - -type ContextType = ReturnType<typeof useDialog> & { - setLabelId: React.Dispatch<React.SetStateAction<string | undefined>>; - setDescriptionId: React.Dispatch<React.SetStateAction<string | undefined>>; -}; - -const DialogContext = React.createContext<ContextType | null>(null); - -export const useDialogContext = (): ContextType => { - const context = React.useContext(DialogContext); - - if (context == null) { - throw new Error('Dialog components must be wrapped in <Dialog />'); - } - - return context; + children?: React.ReactNode; + className?: string; }; -export function Dialog({ - children, - ...options -}: { - children: React.ReactNode; -} & DialogOptions) { - const dialog = useDialog(options); - return <DialogContext.Provider value={dialog}>{children}</DialogContext.Provider>; -} - -interface DialogTriggerProps { - children: React.ReactNode; - asChild?: boolean; -} - -export const DialogTrigger = React.forwardRef<HTMLElement, React.HTMLProps<HTMLElement> & DialogTriggerProps>(function DialogTrigger( - { children, asChild = false, ...props }, - propRef, -) { - const context = useDialogContext(); - const childrenRef = (children as any).ref; - const ref = useMergeRefs([context.data.refs.setReference, propRef, childrenRef]); +export const Dialog = (props: DialogProps) => { + const ref = useRef<HTMLDialogElement>(null); - // `asChild` allows the user to pass any element as the anchor - if (asChild && React.isValidElement(children)) { - return React.cloneElement( - children, - context.interactions.getReferenceProps({ - ref, - ...props, - ...children.props, - 'data-state': context.open ? 'open' : 'closed', - }), - ); - } + useEffect(() => { + if (props.open) ref.current?.showModal(); + else ref.current?.close(); + }, [props.open]); return ( - <button - ref={ref} - // The user can style the trigger based on the state - data-state={context.open ? 'open' : 'closed'} - {...context.interactions.getReferenceProps(props)} - > - {children} - </button> + <dialog className={'fixed inset-0 z-10 overflow-y-auto rounded p-4 bg-light border'} ref={ref} onClose={() => props.onClose()}> + <form method="dialog" className={'flex flex-col gap-4 ' + (props?.className ? props?.className : '')}> + {props.children} + </form> + </dialog> ); -}); - -export const DialogContent = React.forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement>>(function DialogContent(props, propRef) { - const context = useDialogContext(); - const ref = useMergeRefs([context.data.refs.setFloating, propRef]); - - if (!context.open) return null; - - return ( - <FloatingPortal> - <FloatingOverlay className="grid place-items-center" lockScroll style={{ backgroundColor: 'rgba(0, 0, 0, 0.4)' }}> - <FloatingFocusManager context={context.floatingContext}> - <div - ref={ref} - aria-labelledby={context.labelId} - aria-describedby={context.descriptionId} - {...context.interactions.getFloatingProps(props)} - className={`overflow-y-auto rounded p-4 bg-light border border-gray-300${props.className ? ` ${props.className}` : ''}`} - > - {props.children} - </div> - </FloatingFocusManager> - </FloatingOverlay> - </FloatingPortal> - ); -}); - -export const DialogHeading = React.forwardRef<HTMLHeadingElement, React.HTMLProps<HTMLHeadingElement>>(function DialogHeading( - { children, ...props }, - ref, -) { - const { setLabelId } = useDialogContext(); - const id = useId(); - - // Only sets `aria-labelledby` on the Dialog root element - // if this component is mounted inside it. - React.useLayoutEffect(() => { - setLabelId(id); - return () => setLabelId(undefined); - }, [id, setLabelId]); - - return ( - <h2 {...props} ref={ref} id={id}> - {children} - </h2> - ); -}); - -export const DialogDescription = React.forwardRef<HTMLParagraphElement, React.HTMLProps<HTMLParagraphElement>>(function DialogDescription( - { children, ...props }, - ref, -) { - const { setDescriptionId } = useDialogContext(); - const id = useId(); - - // Only sets `aria-describedby` on the Dialog root element - // if this component is mounted inside it. - React.useLayoutEffect(() => { - setDescriptionId(id); - return () => setDescriptionId(undefined); - }, [id, setDescriptionId]); - - return ( - <p {...props} ref={ref} id={id}> - {children} - </p> - ); -}); - -export const DialogClose = React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttributes<HTMLButtonElement>>( - function DialogClose(props, ref) { - const { setOpen } = useDialogContext(); - return <Button variant="solid" className="w-full" {...props} ref={ref} onClick={() => setOpen(false)} />; - }, -); +}; diff --git a/libs/shared/lib/components/layout/Popover.tsx b/libs/shared/lib/components/layout/Popover.tsx deleted file mode 100644 index 4a4cf7a8a589c3d7371543cb7c5e20b1336518d1..0000000000000000000000000000000000000000 --- a/libs/shared/lib/components/layout/Popover.tsx +++ /dev/null @@ -1,244 +0,0 @@ -import * as React from 'react'; -import { - useFloating, - autoUpdate, - offset, - flip, - shift, - useClick, - useDismiss, - useRole, - useInteractions, - useMergeRefs, - Placement, - FloatingPortal, - FloatingFocusManager, - useId, -} from '@floating-ui/react'; - -interface PopoverOptions { - initialOpen?: boolean; - placement?: Placement; - modal?: boolean; - open?: boolean; - onOpenChange?: (open: boolean) => void; -} - -export function usePopover({ - initialOpen = false, - placement = 'bottom', - modal, - open: controlledOpen, - onOpenChange: setControlledOpen, -}: PopoverOptions = {}): { - open: boolean; - setOpen: (open: boolean) => void; - interactions: ReturnType<typeof useInteractions>; - data: ReturnType<typeof useFloating>; - floatingContext: ReturnType<typeof useFloating>['context']; - labelId: string | undefined; - descriptionId: string | undefined; - setLabelId: React.Dispatch<React.SetStateAction<string | undefined>>; - setDescriptionId: React.Dispatch<React.SetStateAction<string | undefined>>; - modal: boolean; -} { - const [uncontrolledOpen, setUncontrolledOpen] = React.useState(initialOpen); - const [labelId, setLabelId] = React.useState<string | undefined>(); - const [descriptionId, setDescriptionId] = React.useState<string | undefined>(); - - const open = controlledOpen ?? uncontrolledOpen; - const setOpen = setControlledOpen ?? setUncontrolledOpen; - - const data = useFloating({ - placement, - open, - onOpenChange: setOpen, - whileElementsMounted: autoUpdate, - middleware: [ - offset(5), - flip({ - crossAxis: placement.includes('-'), - fallbackAxisSideDirection: 'end', - padding: 5, - }), - shift({ padding: 5 }), - ], - }); - - const context = data.context; - - const click = useClick(context, { - enabled: controlledOpen == null, - }); - const dismiss = useDismiss(context); - const role = useRole(context); - - const interactions = useInteractions([click, dismiss, role]); - - return React.useMemo( - () => ({ - open, - setOpen, - interactions: interactions, - data: data, - floatingContext: context, - modal: modal || false, - labelId, - descriptionId, - setLabelId, - setDescriptionId, - }), - [open, setOpen, interactions, data, modal, labelId, descriptionId], - ); -} - -type ContextType = - | (ReturnType<typeof usePopover> & { - setLabelId: React.Dispatch<React.SetStateAction<string | undefined>>; - setDescriptionId: React.Dispatch<React.SetStateAction<string | undefined>>; - }) - | null; - -const PopoverContext = React.createContext<ContextType>(null); - -export const usePopoverContext = () => { - const context = React.useContext(PopoverContext); - - if (context == null) { - throw new Error('Popover components must be wrapped in <Popover />'); - } - - return context; -}; - -export function Popover({ - children, - modal = false, - ...restOptions -}: { - children: React.ReactNode; -} & PopoverOptions) { - // This can accept any props as options, e.g. `placement`, - // or other positioning options. - const popover = usePopover({ modal, ...restOptions }); - return <PopoverContext.Provider value={popover}>{children}</PopoverContext.Provider>; -} - -interface PopoverTriggerProps { - children: React.ReactNode; - asChild?: boolean; -} - -export const PopoverTrigger = React.forwardRef<HTMLElement, React.HTMLProps<HTMLElement> & PopoverTriggerProps>(function PopoverTrigger( - { children, asChild = false, ...props }, - propRef, -) { - const context = usePopoverContext(); - const childrenRef = (children as any).ref; - const ref = useMergeRefs([context.data.refs.setReference, propRef, childrenRef]); - - // `asChild` allows the user to pass any element as the anchor - if (asChild && React.isValidElement(children)) { - return React.cloneElement( - children, - context.interactions.getReferenceProps({ - ref, - ...props, - ...children.props, - 'data-state': context.open ? 'open' : 'closed', - }), - ); - } - - return ( - <button - ref={ref} - type="button" - // The user can style the trigger based on the state - data-state={context.open ? 'open' : 'closed'} - {...context.interactions.getReferenceProps(props)} - > - {children} - </button> - ); -}); - -export const PopoverContent = React.forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement>>(function PopoverContent( - { style, className, ...props }, - propRef, -) { - const context = usePopoverContext(); - const ref = useMergeRefs([context.data.refs.setFloating, propRef]); - - if (!context.floatingContext.open) return null; - - return ( - <FloatingPortal> - <FloatingFocusManager context={context.floatingContext} modal={context.modal}> - <div - ref={ref} - style={{ ...context.data.floatingStyles, ...style }} - aria-labelledby={context.labelId} - aria-describedby={context.descriptionId} - {...context.interactions.getFloatingProps(props)} - className={`w-fit ${className || ''}`} - > - {props.children} - </div> - </FloatingFocusManager> - </FloatingPortal> - ); -}); - -export const PopoverHeading = React.forwardRef<HTMLHeadingElement, React.HTMLProps<HTMLHeadingElement>>( - function PopoverHeading(props, ref) { - const { setLabelId } = usePopoverContext(); - const id = useId(); - - // Only sets `aria-labelledby` on the Popover root element - // if this component is mounted inside it. - React.useLayoutEffect(() => { - setLabelId(id); - return () => setLabelId(undefined); - }, [id, setLabelId]); - - return ( - <h2 {...props} ref={ref} id={id}> - {props.children} - </h2> - ); - }, -); - -export const PopoverDescription = React.forwardRef<HTMLParagraphElement, React.HTMLProps<HTMLParagraphElement>>( - function PopoverDescription(props, ref) { - const { setDescriptionId } = usePopoverContext(); - const id = useId(); - - // Only sets `aria-describedby` on the Popover root element - // if this component is mounted inside it. - React.useLayoutEffect(() => { - setDescriptionId(id); - return () => setDescriptionId(undefined); - }, [id, setDescriptionId]); - - return <p {...props} ref={ref} id={id} />; - }, -); - -export const PopoverClose = React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttributes<HTMLButtonElement>>( - function PopoverClose(props, ref) { - const { setOpen } = usePopoverContext(); - return ( - <button - type="button" - ref={ref} - {...props} - onClick={(event) => { - props.onClick?.(event); - setOpen(false); - }} - /> - ); - }, -); diff --git a/libs/shared/lib/components/pills/Pill.tsx b/libs/shared/lib/components/pills/Pill.tsx index 2cf653552b8d5b29ff83fc61cd828fe3b268c1af..aea0755762a58d04c981e421f225847ba3d17453 100644 --- a/libs/shared/lib/components/pills/Pill.tsx +++ b/libs/shared/lib/components/pills/Pill.tsx @@ -17,7 +17,6 @@ export type PillI = { handleLeft?: React.ReactNode; handleRight?: React.ReactNode; className?: string; - draggable?: boolean; }; export const Pill = React.memo((props: PillI) => { @@ -60,27 +59,23 @@ export const Pill = React.memo((props: PillI) => { const onDragStart = (event: React.DragEvent<HTMLDivElement>) => { const pill = event.target as HTMLDivElement; const dragImage = pill.cloneNode(true) as HTMLDivElement; - dragImage.style.transform = 'translate(0, 0)'; // Removes the background from drag image in Chrome + dragImage.style.transform = 'translate(0, 0)'; // Removes the background from drag image in Chrome document.body.appendChild(dragImage); const mouse_x = event.clientX - pill.getBoundingClientRect().left; const mouse_y = event.clientY - pill.getBoundingClientRect().top; event.dataTransfer.setDragImage(dragImage, mouse_x, mouse_y); - event.dataTransfer.setData('mouse_x', String(mouse_x)); - event.dataTransfer.setData('mouse_y', String(mouse_y)); - + event.dataTransfer.setData('mouse_x', String(mouse_x)) + event.dataTransfer.setData('mouse_y', String(mouse_y)) + setTimeout(() => { dragImage.remove(); }, 1); - }; + } return ( - <div - draggable={props.draggable || false} - onDragStart={!!props.draggable ? onDragStart : undefined} - className={(props.className ? props.className + ' ' : '') + 'flex flex-row flex-grow-0 text-xs text-justify'} - > + <div draggable="true" onDragStart={onDragStart} className={(props.className ? props.className + ' ' : '') + 'flex flex-row flex-grow-0 text-xs text-justify'}> <div className={'bg-secondary-200 ' + (corner !== 'square' ? 'rounded' : '')} style={{ diff --git a/libs/shared/lib/components/tabs/Tab.tsx b/libs/shared/lib/components/tabs/Tab.tsx index 9b044371c3b0782d4a9a84fe9a954748e9dd3af6..855da1029f65bc4c47c461c59624ae4f3226c269 100644 --- a/libs/shared/lib/components/tabs/Tab.tsx +++ b/libs/shared/lib/components/tabs/Tab.tsx @@ -8,21 +8,21 @@ export const Tabs = (props: { children: React.ReactNode }) => { ); }; -export const Tab = ({ - activeTab, - text, - ...props -}: React.ButtonHTMLAttributes<HTMLDivElement> & { - activeTab: boolean; - children: React.ReactNode; - text: string; -}) => { +export const Tab = ( + props: React.ButtonHTMLAttributes<HTMLDivElement> & { + active: boolean; + children: React.ReactNode; + text: string; + key?: string; + }, +) => { return ( <div - className={`flex items-center pl-2 pr-1 gap-1 cursor-pointer relative border-secondary-200 before:content-[''] before:absolute before:left-0 before:bottom-0 before:h-[2px] before:w-full ${activeTab ? 'before:bg-primary-500' : 'before:bg-transparent hover:before:bg-secondary-300 hover:bg-secondary-200'}`} + key={props.key} + className={`flex items-center pl-2 pr-1 gap-1 cursor-pointer relative border-secondary-200 before:content-[''] before:absolute before:left-0 before:bottom-0 before:h-[2px] before:w-full ${props.active ? 'before:bg-primary-500' : 'before:bg-transparent hover:before:bg-secondary-300 hover:bg-secondary-200'}`} {...props} > - <p className={`text-xs text-secondary-500 font-semibold ${activeTab && 'text-secondary-950'}`}>{text}</p> + <p className={`text-xs text-secondary-500 font-semibold ${props.active && 'text-secondary-950'}`}>{props.text}</p> {props.children} </div> ); diff --git a/libs/shared/lib/components/tooltip/Tooltip.tsx b/libs/shared/lib/components/tooltip/Tooltip.tsx deleted file mode 100644 index 19ca660cfbcf173470a8e424ccf9c0d3e710de6e..0000000000000000000000000000000000000000 --- a/libs/shared/lib/components/tooltip/Tooltip.tsx +++ /dev/null @@ -1,165 +0,0 @@ -import * as React from 'react'; -import { - useFloating, - autoUpdate, - offset, - flip, - shift, - useHover, - useFocus, - useDismiss, - useRole, - useInteractions, - useMergeRefs, - FloatingPortal, -} from '@floating-ui/react'; -import type { Placement } from '@floating-ui/react'; -import { FloatingDelayGroup } from '@floating-ui/react'; - -interface TooltipOptions { - initialOpen?: boolean; - placement?: Placement; - open?: boolean; - onOpenChange?: (open: boolean) => void; -} - -export function useTooltip({ - initialOpen = false, - placement = 'top', - open: controlledOpen, - onOpenChange: setControlledOpen, -}: TooltipOptions = {}): { - open: boolean; - setOpen: (open: boolean) => void; - interactions: ReturnType<typeof useInteractions>; - data: ReturnType<typeof useFloating>; -} { - const [uncontrolledOpen, setUncontrolledOpen] = React.useState(initialOpen); - - const open = controlledOpen ?? uncontrolledOpen; - const setOpen = setControlledOpen ?? setUncontrolledOpen; - - const data = useFloating({ - placement, - open, - onOpenChange: setOpen, - whileElementsMounted: autoUpdate, - middleware: [ - offset(5), - flip({ - crossAxis: placement.includes('-'), - fallbackAxisSideDirection: 'start', - padding: 5, - }), - shift({ padding: 5 }), - ], - }); - - const context = data.context; - - const hover = useHover(context, { - move: false, - enabled: controlledOpen == null, - }); - const focus = useFocus(context, { - enabled: controlledOpen == null, - }); - const dismiss = useDismiss(context); - const role = useRole(context, { role: 'tooltip' }); - - const interactions = useInteractions([hover, focus, dismiss, role]); - - return React.useMemo( - () => ({ - open, - setOpen, - interactions: interactions, - data: data, - }), - [open, setOpen, interactions, data], - ); -} - -type ContextType = ReturnType<typeof useTooltip> | null; - -const TooltipContext = React.createContext<ContextType>(null); - -export const useTooltipContext = () => { - const context = React.useContext(TooltipContext); - - if (context == null) { - throw new Error('Tooltip components must be wrapped in <Tooltip />'); - } - - return context; -}; - -export function Tooltip({ children, ...options }: { children: React.ReactNode } & TooltipOptions) { - // This can accept any props as options, e.g. `placement`, - // or other positioning options. - const tooltip = useTooltip(options); - return <TooltipContext.Provider value={tooltip}>{children}</TooltipContext.Provider>; -} - -export const TooltipTrigger = React.forwardRef<HTMLElement, React.HTMLProps<HTMLElement> & { asChild?: boolean }>(function TooltipTrigger( - { children, asChild = false, ...props }, - propRef, -) { - const context = useTooltipContext(); - const childrenRef = (children as any).ref; - const ref = useMergeRefs([context.data.refs.setReference, propRef, childrenRef]); - - // `asChild` allows the user to pass any element as the anchor - if (asChild && React.isValidElement(children)) { - return React.cloneElement( - children, - context.interactions.getReferenceProps({ - ref, - ...props, - ...children.props, - 'data-state': context.open ? 'open' : 'closed', - }), - ); - } - - return ( - <div - ref={ref} - // The user can style the trigger based on the state - data-state={context.open ? 'open' : 'closed'} - {...context.interactions.getReferenceProps(props)} - > - {children} - </div> - ); -}); - -export const TooltipContent = React.forwardRef< - HTMLDivElement, - React.HTMLProps<HTMLDivElement> & { - side?: string; - } ->(function TooltipContent({ style, className, ...props }, propRef) { - const context = useTooltipContext(); - const ref = useMergeRefs([context.data.refs.setFloating, propRef]); - - if (!context.open) return null; - - return ( - <FloatingPortal> - <div - ref={ref} - className={`z-50 max-w-64 overflow-hidden rounded bg-light px-2 py-1 shadow text-xs border border-secondary-200 text-dark animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2${className ? ` ${className}` : ''}`} - style={{ - ...context.data.floatingStyles, - ...style, - }} - {...context.interactions.getFloatingProps(props)} - /> - </FloatingPortal> - ); -}); - -export const TooltipProvider = (props: { delayDuration: number; children: React.ReactNode }) => { - return <FloatingDelayGroup delay={props.delayDuration}>{props.children}</FloatingDelayGroup>; -}; diff --git a/libs/shared/lib/components/tooltip/index.tsx b/libs/shared/lib/components/tooltip/index.tsx index 4024bdf57383ddf0e3e779e8934318af0654613e..6c5a62d3514ae42afa899f797937ce90246a0102 100644 --- a/libs/shared/lib/components/tooltip/index.tsx +++ b/libs/shared/lib/components/tooltip/index.tsx @@ -1,6 +1,7 @@ // https://www.radix-ui.com/primitives/docs/components/tooltip -export * from './Tooltip'; +import React, { ReactNode } from 'react'; +import * as TooltipPrimitive from '@radix-ui/react-tooltip'; export interface BarTooltipProps { x: number; @@ -18,3 +19,42 @@ export const BarPlotTooltip = ({ x, y, children }: BarTooltipProps) => { </div> ); }; + +const TooltipProvider = TooltipPrimitive.Provider; +const TooltipTrigger = TooltipPrimitive.Trigger; + +export type TooltipProps = { + children: ReactNode; + disabled?: boolean; +}; + +const Tooltip: React.FC<TooltipProps> = ({ disabled, children }) => { + if (disabled) { + return null; + } + + return <TooltipPrimitive.Root>{children}</TooltipPrimitive.Root>; +}; + +const TooltipContent = React.forwardRef< + React.ElementRef<typeof TooltipPrimitive.Content>, + React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> & TooltipProps +>(({ className, sideOffset = 4, disabled = false, ...props }, ref) => { + if (disabled) { + return null; + } + + return ( + <TooltipPrimitive.Content + ref={ref} + sideOffset={sideOffset} + className={ + 'z-50 overflow-hidden rounded bg-light px-2 py-1 shadow text-xs border border-secondary-200 text-dark animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2' + } + {...props} + /> + ); +}); +TooltipContent.displayName = TooltipPrimitive.Content.displayName; + +export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; diff --git a/libs/shared/lib/components/tooltip/tooltip.stories.tsx b/libs/shared/lib/components/tooltip/tooltip.stories.tsx index 523a9a13511ebcc7f1a8a8dd8cf3ad907130efb2..1335dde4ae0813ee421cc0c2eddd7cab327708c5 100644 --- a/libs/shared/lib/components/tooltip/tooltip.stories.tsx +++ b/libs/shared/lib/components/tooltip/tooltip.stories.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { Meta } from '@storybook/react'; import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from './index'; +import { delay } from 'lodash-es'; export default { title: 'Components/Tooltip', @@ -39,8 +40,7 @@ TooltipStory.args = { side: 'bottom', }; -export const TooltipPosition = { - args: { - side: 'bottom', - }, +export const TooltipPosition = TooltipStory.bind({}); +TooltipPosition.args = { + side: 'bottom', }; diff --git a/libs/shared/lib/inspector/InspectorPanel.tsx b/libs/shared/lib/inspector/InspectorPanel.tsx index 48c07f40ba0dfc9629c143217c07f204372a4c8c..703af6cee516cd7415ad83b0fcb00f2a161df3e0 100644 --- a/libs/shared/lib/inspector/InspectorPanel.tsx +++ b/libs/shared/lib/inspector/InspectorPanel.tsx @@ -56,7 +56,7 @@ export function InspectorPanel(props: { children?: React.ReactNode }) { {buildInfo === 'dev' && ( <div className="mt-auto p-2 bg-light"> <Button - variantType="primary" + type="primary" variant="outline" size="xs" label="Report an issue" diff --git a/libs/shared/lib/querybuilder/panel/QueryBuilder.tsx b/libs/shared/lib/querybuilder/panel/QueryBuilder.tsx index 3f3ac4618a77ccd7198fbff624c513e5b5e30209..858066c2483588c2419e7d54573899cccf488d8c 100644 --- a/libs/shared/lib/querybuilder/panel/QueryBuilder.tsx +++ b/libs/shared/lib/querybuilder/panel/QueryBuilder.tsx @@ -24,7 +24,7 @@ import ReactFlow, { isNode, useReactFlow, } from 'reactflow'; -import { Dialog, DialogClose, DialogContent } from '../../components/layout/Dialog'; +import { Dialog } from '../../components/layout/Dialog'; import { Button } from '../../components/buttons'; import { ControlContainer } from '../../components/controls'; import { addError } from '../../data-access/store/configSlice'; @@ -43,7 +43,6 @@ import { CameraAlt, Cached, Difference, ImportExport, Lightbulb, Settings, Fulls import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../components/tooltip'; import { resultSetFocus } from '../../data-access/store/interactionSlice'; import { QueryBuilderDispatcherContext } from './QueryBuilderDispatcher'; -import { Popover, PopoverContent, PopoverTrigger } from '../../components/layout/Popover'; export type QueryBuilderProps = { onRunQuery?: () => void; @@ -450,6 +449,8 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => { }} > <div ref={reactFlowWrapper} className="h-full w-full flex flex-col"> + <QueryMLDialog open={toggleSettings === 'ml'} onClose={() => setToggleSettings(undefined)} /> + <div className="sticky shrink-0 top-0 flex items-stretch justify-between h-7 bg-secondary-100 border-b border-secondary-200 max-w-full"> <div className="flex items-center"> <h1 className="text-xs font-semibold text-secondary-600 px-2 truncate">Query builder</h1> @@ -459,7 +460,7 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => { <TooltipProvider delayDuration={0}> <Tooltip> <TooltipTrigger asChild> - <Button variantType="secondary" variant="ghost" size="xs" iconComponent={<Fullscreen />} onClick={fitView} /> + <Button type="secondary" variant="ghost" size="xs" iconComponent={<Fullscreen />} onClick={fitView} /> </TooltipTrigger> <TooltipContent side={'top'}> <p>Fit to screen</p> @@ -467,7 +468,7 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => { </Tooltip> <Tooltip> <TooltipTrigger asChild> - <Button variantType="secondary" variant="ghost" size="xs" iconComponent={<Delete />} onClick={() => clearAllNodes()} /> + <Button type="secondary" variant="ghost" size="xs" iconComponent={<Delete />} onClick={() => clearAllNodes()} /> </TooltipTrigger> <TooltipContent side={'top'}> <p>Clear query panel</p> @@ -476,7 +477,7 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => { <Tooltip> <TooltipTrigger asChild> <Button - variantType="secondary" + type="secondary" variant="ghost" size="xs" iconComponent={<CameraAlt />} @@ -492,7 +493,7 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => { <Tooltip> <TooltipTrigger asChild> <Button - variantType="secondary" + type="secondary" variant="ghost" size="xs" iconComponent={<ImportExport />} @@ -509,7 +510,7 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => { <Tooltip> <TooltipTrigger asChild> <Button - variantType="secondary" + type="secondary" variant="ghost" size="xs" iconComponent={<Settings />} @@ -528,7 +529,7 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => { <Tooltip> <TooltipTrigger asChild> <Button - variantType="secondary" + type="secondary" variant="ghost" size="xs" iconComponent={<Cached />} @@ -545,7 +546,7 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => { <Tooltip> <TooltipTrigger asChild> <Button - variantType="secondary" + type="secondary" variant="ghost" size="xs" iconComponent={<Difference />} @@ -560,31 +561,24 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => { <p>Logic settings</p> </TooltipContent> </Tooltip> - <Popover> - <PopoverTrigger> - <Tooltip> - <TooltipTrigger> - <Button - variantType="secondary" - variant="ghost" - size="xs" - iconComponent={<Lightbulb />} - onClick={(event) => { - // event.stopPropagation(); - // if (toggleSettings === 'ml') setToggleSettings(undefined); - // else setToggleSettings('ml'); - }} - /> - </TooltipTrigger> - <TooltipContent side={'top'} disabled={toggleSettings === 'ml'}> - <p>Machine learning</p> - </TooltipContent> - </Tooltip> - </PopoverTrigger> - <PopoverContent> - <QueryMLDialog /> - </PopoverContent> - </Popover> + <Tooltip> + <TooltipTrigger asChild> + <Button + type="secondary" + variant="ghost" + size="xs" + iconComponent={<Lightbulb />} + onClick={(event) => { + event.stopPropagation(); + if (toggleSettings === 'ml') setToggleSettings(undefined); + else setToggleSettings('ml'); + }} + /> + </TooltipTrigger> + <TooltipContent side={'top'} disabled={toggleSettings === 'ml'}> + <p>Machine learning</p> + </TooltipContent> + </Tooltip> </TooltipProvider> </ControlContainer> </div> @@ -592,45 +586,40 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => { <Dialog open={toggleSettings === 'logic'} - onOpenChange={(ret) => { - if (!ret) setToggleSettings(undefined); + onClose={() => { + setToggleSettings(undefined); }} > - <DialogContent> - <QueryBuilderLogicPillsPanel - onClick={(v) => { - connectingNodeId.current = null; - editLogicNode.current = undefined; - setToggleSettings(undefined); - }} - reactFlowWrapper={reactFlowWrapper.current} - title="Logic Pills usable by the node" - className="min-h-[75vh] max-h-[75vh]" - onDrag={() => {}} - connection={connectingNodeId?.current} - editNode={editLogicNode.current} - /> - <DialogClose>Cancel</DialogClose> - </DialogContent> + <QueryBuilderLogicPillsPanel + onClick={(v) => { + connectingNodeId.current = null; + editLogicNode.current = undefined; + setToggleSettings(undefined); + }} + reactFlowWrapper={reactFlowWrapper.current} + title="Logic Pills usable by the node" + className="min-h-[75vh] max-h-[75vh]" + onDrag={() => {}} + connection={connectingNodeId?.current} + editNode={editLogicNode.current} + /> </Dialog> <Dialog open={toggleSettings === 'relatedNodes'} - onOpenChange={(ret) => { - if (!ret) setToggleSettings(undefined); + onClose={() => { + setToggleSettings(undefined); }} > - <DialogContent> - <QueryBuilderRelatedNodesPanel - onFinished={() => { - connectingNodeId.current = null; - setToggleSettings(undefined); - }} - reactFlowWrapper={reactFlowWrapper.current} - title="Related nodes available to add to the query" - className="min-h-[75vh] max-h-[75vh]" - connection={connectingNodeId?.current} - /> - </DialogContent> + <QueryBuilderRelatedNodesPanel + onFinished={() => { + connectingNodeId.current = null; + setToggleSettings(undefined); + }} + reactFlowWrapper={reactFlowWrapper.current} + title="Related nodes available to add to the query" + className="min-h-[75vh] max-h-[75vh]" + connection={connectingNodeId?.current} + /> </Dialog> <svg height={0}> <defs> diff --git a/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderLogicPillsPanel.tsx b/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderLogicPillsPanel.tsx index 041acb8dfad4987c3d2863f57333983d0243ecde..39426ce74fa3ea6ed1f01749788f4d90afc22865 100644 --- a/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderLogicPillsPanel.tsx +++ b/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderLogicPillsPanel.tsx @@ -12,7 +12,7 @@ import { ConnectingNodeDataI } from '../utils/connectorDrop'; import { useQuerybuilderGraph } from '@graphpolaris/shared/lib/data-access'; import { toQuerybuilderGraphology, setQuerybuilderGraphology } from '@graphpolaris/shared/lib/data-access/store/querybuilderSlice'; import { useDispatch } from 'react-redux'; -import { Button, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../..'; +import { Button } from '../../..'; export const QueryBuilderLogicPillsPanel = (props: { reactFlowWrapper: HTMLDivElement | null; @@ -163,24 +163,19 @@ export const QueryBuilderLogicPillsPanel = (props: { <div className={props.className + ' card'}> {props.title && <h1 className="card-title mb-7">{props.title}</h1>} <div className="gap-1 flex"> - <TooltipProvider delayDuration={50}> - {dataOps.map((item, index) => ( - <Tooltip key={item.title}> - <TooltipContent>{item.description}</TooltipContent> - <TooltipTrigger> - <Button - iconComponent={item.icon} - size="sm" - variant={selectedOp === index ? 'solid' : 'outline'} - onClick={(e) => { - e.preventDefault(); - index === selectedOp ? setSelectedOp(-1) : setSelectedOp(index); - }} - ></Button> - </TooltipTrigger> - </Tooltip> - ))} - </TooltipProvider> + {dataOps.map((item, index) => ( + <div key={item.title} data-tip={item.description} className="tooltip tooltip-top m-0 p-0"> + <Button + iconComponent={item.icon} + size="sm" + variant={selectedOp === index ? 'solid' : 'outline'} + onClick={(e) => { + e.preventDefault(); + index === selectedOp ? setSelectedOp(-1) : setSelectedOp(index); + }} + ></Button> + </div> + ))} <div className="w-2" /> {dataTypes.map((item, index) => ( <div key={item.title} data-tip={item.description} className="tooltip tooltip-top m-0 p-0"> diff --git a/libs/shared/lib/querybuilder/panel/querysidepanel/queryMLDialog.tsx b/libs/shared/lib/querybuilder/panel/querysidepanel/queryMLDialog.tsx index 213807e6b3ef233141a41e3cff883573b363b606..ff724e1cae41cdaeffba45e78eb207c2fee22d14 100644 --- a/libs/shared/lib/querybuilder/panel/querysidepanel/queryMLDialog.tsx +++ b/libs/shared/lib/querybuilder/panel/querysidepanel/queryMLDialog.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { DialogProps } from '@graphpolaris/shared/lib/components/layout'; import { useAppDispatch, useML } from '@graphpolaris/shared/lib/data-access'; import { setCentralityEnabled, @@ -8,72 +9,77 @@ import { } from '@graphpolaris/shared/lib/data-access/store/mlSlice'; import { FormDiv, FormCard, FormBody, FormTitle, FormHBar } from '@graphpolaris/shared/lib/components/forms'; import { Input } from '@graphpolaris/shared/lib/components/inputs'; -import { PopoverTrigger } from '@graphpolaris/shared/lib/components/layout/Popover'; -export const QueryMLDialog = () => { +type QueryMLDialogProps = DialogProps; + +export const QueryMLDialog = React.forwardRef<HTMLDivElement, QueryMLDialogProps>((props, ref) => { const dispatch = useAppDispatch(); const ml = useML(); return ( - <div> - <FormCard> - <FormBody - onSubmit={(e) => { - e.preventDefault(); - }} - > - <FormTitle title="Machine Learning Options" /> - <FormHBar /> + <> + {props.open && ( + <FormDiv ref={ref} className="" hAnchor="right"> + <FormCard> + <FormBody + onSubmit={(e) => { + e.preventDefault(); + }} + > + <FormTitle title="Machine Learning Options" onClose={props.onClose} /> + <FormHBar /> - <div className="px-5"> - <Input - type="boolean" - label="Link Prediction" - value={ml.linkPrediction.enabled} - onChange={() => dispatch(setLinkPredictionEnabled(!ml.linkPrediction.enabled))} - /> - {ml.linkPrediction.enabled && ml.linkPrediction.result && <span># of predictions: {ml.linkPrediction.result.length}</span>} - {ml.linkPrediction.enabled && !ml.linkPrediction.result && <span>Loading...</span>} + <div className="px-5"> + <Input + type="boolean" + label="Link Prediction" + value={ml.linkPrediction.enabled} + onChange={() => dispatch(setLinkPredictionEnabled(!ml.linkPrediction.enabled))} + /> + {ml.linkPrediction.enabled && ml.linkPrediction.result && <span># of predictions: {ml.linkPrediction.result.length}</span>} + {ml.linkPrediction.enabled && !ml.linkPrediction.result && <span>Loading...</span>} - <Input - type="boolean" - label="Centrality" - value={ml.centrality.enabled} - onChange={() => dispatch(setCentralityEnabled(!ml.centrality.enabled))} - /> - {ml.centrality.enabled && Object.values(ml.centrality.result).length > 0 && ( - <span> - sum of centers: - {Object.values(ml.centrality.result) - .reduce((a, b) => b + a) - .toFixed(2)} - </span> - )} - {ml.centrality.enabled && Object.values(ml.centrality.result).length === 0 && <span>No Centers Found</span>} + <Input + type="boolean" + label="Centrality" + value={ml.centrality.enabled} + onChange={() => dispatch(setCentralityEnabled(!ml.centrality.enabled))} + /> + {ml.centrality.enabled && Object.values(ml.centrality.result).length > 0 && ( + <span> + sum of centers: + {Object.values(ml.centrality.result) + .reduce((a, b) => b + a) + .toFixed(2)} + </span> + )} + {ml.centrality.enabled && Object.values(ml.centrality.result).length === 0 && <span>No Centers Found</span>} - <Input - type="boolean" - label="Community detection" - value={ml.communityDetection.enabled} - onChange={() => dispatch(setCommunityDetectionEnabled(!ml.communityDetection.enabled))} - /> - {ml.communityDetection.enabled && ml.communityDetection.result && ( - <span># of communities: {ml.communityDetection.result.length}</span> - )} - {ml.communityDetection.enabled && !ml.communityDetection.result && <span>Loading...</span>} + <Input + type="boolean" + label="Community detection" + value={ml.communityDetection.enabled} + onChange={() => dispatch(setCommunityDetectionEnabled(!ml.communityDetection.enabled))} + /> + {ml.communityDetection.enabled && ml.communityDetection.result && ( + <span># of communities: {ml.communityDetection.result.length}</span> + )} + {ml.communityDetection.enabled && !ml.communityDetection.result && <span>Loading...</span>} - <Input - type="boolean" - label="Shortest path" - value={ml.shortestPath.enabled} - onChange={() => dispatch(setShortestPathEnabled(!ml.shortestPath.enabled))} - /> - {ml.shortestPath.enabled && ml.shortestPath.result?.length > 0 && <span># of hops: {ml.shortestPath.result.length}</span>} - {ml.shortestPath.enabled && !ml.shortestPath.srcNode && <span>Please select source node</span>} - {ml.shortestPath.enabled && ml.shortestPath.srcNode && !ml.shortestPath.trtNode && <span>Please select target node</span>} - </div> - </FormBody> - </FormCard> - </div> + <Input + type="boolean" + label="Shortest path" + value={ml.shortestPath.enabled} + onChange={() => dispatch(setShortestPathEnabled(!ml.shortestPath.enabled))} + /> + {ml.shortestPath.enabled && ml.shortestPath.result?.length > 0 && <span># of hops: {ml.shortestPath.result.length}</span>} + {ml.shortestPath.enabled && !ml.shortestPath.srcNode && <span>Please select source node</span>} + {ml.shortestPath.enabled && ml.shortestPath.srcNode && !ml.shortestPath.trtNode && <span>Please select target node</span>} + </div> + </FormBody> + </FormCard> + </FormDiv> + )} + </> ); -}; +}); diff --git a/libs/shared/lib/querybuilder/pills/customFlowPills/logicpill/QueryLogicPill.tsx b/libs/shared/lib/querybuilder/pills/customFlowPills/logicpill/QueryLogicPill.tsx index 09a9e534b0130cb7208c9133abf6dc4ccaea5682..2c2f75c77a02c49aa1722e8abb6e724bba7b8ff7 100644 --- a/libs/shared/lib/querybuilder/pills/customFlowPills/logicpill/QueryLogicPill.tsx +++ b/libs/shared/lib/querybuilder/pills/customFlowPills/logicpill/QueryLogicPill.tsx @@ -6,7 +6,7 @@ import { GeneralDescription, InputNode, InputNodeTypeTypes } from '../../../mode import { styleHandleMap } from '../../utils'; import { setQuerybuilderGraphology, toQuerybuilderGraphology } from '@graphpolaris/shared/lib/data-access/store/querybuilderSlice'; import { LogicInput } from './LogicInput'; -import { Button, DropdownTrigger, Input, LogicPill } from '@graphpolaris/shared/lib/components'; +import { Button, DropdownButton, Input, LogicPill } from '@graphpolaris/shared/lib/components'; import { ArrowDropDown } from '@mui/icons-material'; import { QueryBuilderDispatcherContext } from '../../../panel/QueryBuilderDispatcher'; @@ -73,7 +73,7 @@ export function QueryLogicPill(node: SchemaReactflowLogicNode) { > <div className={`py-1 h-fit border-[1px] border-secondary-200 ${data.selected ? 'bg-secondary-400' : 'bg-secondary-100'}`}> {/* <div className="m-1 mx-2 text-left">{output.name}</div> */} - <DropdownTrigger + <DropdownButton title={output.name} variant="ghost" size="xs" diff --git a/libs/shared/lib/schema/panel/Schema.tsx b/libs/shared/lib/schema/panel/Schema.tsx index 20d12776e7b4e449e24a84640f4833458928e1e4..bb9a9c409ab827f3167975889e4631a4949a5431 100644 --- a/libs/shared/lib/schema/panel/Schema.tsx +++ b/libs/shared/lib/schema/panel/Schema.tsx @@ -14,8 +14,7 @@ import { ContentCopy, FitScreen, Fullscreen, KeyboardArrowDown, KeyboardArrowRig import { AlgorithmToLayoutProvider, AllLayoutAlgorithms, LayoutFactory } from '../../graph-layout'; import { ConnectionLine, ConnectionDragLine } from '../../querybuilder'; import { schemaExpandRelation, schemaGraphology2Reactflow } from '../schema-utils'; -import { Panel } from '../../components'; -import { Tooltip, TooltipContent, TooltipTrigger } from '../../components/tooltip/Tooltip'; +import { Panel, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../components'; import { resultSetFocus } from '../../data-access/store/interactionSlice'; import { useDispatch } from 'react-redux'; @@ -117,11 +116,11 @@ export const Schema = (props: Props) => { <Panel title="Schema" tooltips={ - <> + <TooltipProvider delayDuration={10}> <Tooltip> - <TooltipTrigger> + <TooltipTrigger asChild> <Button - variantType="secondary" + type="secondary" variant="ghost" size="xs" iconComponent={<Remove />} @@ -135,9 +134,9 @@ export const Schema = (props: Props) => { </TooltipContent> </Tooltip> <Tooltip> - <TooltipTrigger> + <TooltipTrigger asChild> <Button - variantType="secondary" + type="secondary" variant="ghost" size="xs" iconComponent={<ContentCopy />} @@ -152,14 +151,14 @@ export const Schema = (props: Props) => { </TooltipContent> </Tooltip> <Tooltip> - <TooltipTrigger> - <Button variantType="secondary" variant="ghost" size="xs" iconComponent={<FitScreen />} onClick={() => {}} /> + <TooltipTrigger asChild> + <Button type="secondary" variant="ghost" size="xs" iconComponent={<FitScreen />} onClick={() => {}} /> </TooltipTrigger> <TooltipContent side={'top'}> <p>Fit to screen</p> </TooltipContent> </Tooltip> - </> + </TooltipProvider> } > <div className="schema-panel w-full h-full flex flex-col justify-between" ref={reactFlowRef}> diff --git a/libs/shared/lib/schema/panel/SchemaSettings.tsx b/libs/shared/lib/schema/panel/SchemaSettings.tsx index 0d3c0fa5560e012a32c8e9bc8d3fcaf0cd694191..270cb50d47b24b1fc7d47cd454f51bfa5edbf32e 100644 --- a/libs/shared/lib/schema/panel/SchemaSettings.tsx +++ b/libs/shared/lib/schema/panel/SchemaSettings.tsx @@ -1,8 +1,11 @@ +import { useEffect, useState } from 'react'; +import { Dialog, DialogProps } from '../../components/layout/Dialog'; import React from 'react'; import { useAppDispatch, useSchemaSettings } from '../../data-access'; -import { SchemaConnectionTypes, schemaConnectionTypeArray, setSchemaSettings } from '../../data-access/store/schemaSlice'; -import { Input } from '../../components/inputs'; +import { SchemaConnectionTypes, SchemaSettings, schemaConnectionTypeArray, setSchemaSettings } from '../../data-access/store/schemaSlice'; +import { FormActions, FormBody, FormCard, FormControl, FormHBar, FormTitle, FormDiv } from '../../components/forms'; import { Layouts } from '../../graph-layout'; +import { Input } from '../../components/inputs'; export const SchemaDialog = () => { const settings = useSchemaSettings(); diff --git a/libs/shared/lib/schema/pills/nodes/entity/SchemaEntityPill.tsx b/libs/shared/lib/schema/pills/nodes/entity/SchemaEntityPill.tsx index d3bfe7ef250ae4162b7bde3582995eb899707f4b..3afed3f5e2796be843e7a13b2d854f88547b515c 100644 --- a/libs/shared/lib/schema/pills/nodes/entity/SchemaEntityPill.tsx +++ b/libs/shared/lib/schema/pills/nodes/entity/SchemaEntityPill.tsx @@ -59,7 +59,6 @@ export const SchemaEntityPill = React.memo(({ id, selected, data }: NodeProps<Sc draggable > <EntityPill - draggable title={id} withHandles="vertical" handleUp={ diff --git a/libs/shared/lib/schema/pills/nodes/relation/SchemaRelationPill.tsx b/libs/shared/lib/schema/pills/nodes/relation/SchemaRelationPill.tsx index 86cdfcdb88cbc70895c6a3c6632eb8f781531f88..c7a79c38a0927f9f71f67db74e0cb0bcaaede703 100644 --- a/libs/shared/lib/schema/pills/nodes/relation/SchemaRelationPill.tsx +++ b/libs/shared/lib/schema/pills/nodes/relation/SchemaRelationPill.tsx @@ -64,7 +64,6 @@ export const SchemaRelationPill = React.memo(({ id, selected, data, ...props }: draggable > <RelationPill - draggable title={data.collection} withHandles="vertical" handleUp={ diff --git a/libs/shared/lib/sidebar/index.tsx b/libs/shared/lib/sidebar/index.tsx index 6648d219525d217f4ce0968ea5c3359ac1997d3f..8f92890cf5d537fc222169c66ffb2017c11678f1 100644 --- a/libs/shared/lib/sidebar/index.tsx +++ b/libs/shared/lib/sidebar/index.tsx @@ -24,7 +24,7 @@ export function Sidebar({ onTab, tab }: { onTab: (tab: SideNavTab) => void; tab: <Tooltip key={t.name}> <TooltipTrigger asChild> <Button - variantType="secondary" + type="secondary" variant="ghost" size="sm" iconComponent={t.icon} diff --git a/libs/shared/lib/sidebar/search/SearchBar.tsx b/libs/shared/lib/sidebar/search/SearchBar.tsx index c8bdae4516695574320527ef4c867dbaf3fde055..04e24282f92ea0b24b57d4aa75823761669d37c3 100644 --- a/libs/shared/lib/sidebar/search/SearchBar.tsx +++ b/libs/shared/lib/sidebar/search/SearchBar.tsx @@ -116,7 +116,7 @@ export function SearchBar(props: { onRemove?: () => void }) { <Tooltip> <TooltipTrigger asChild> <Button - variantType="secondary" + type="secondary" variant="ghost" size="xs" iconComponent={<Remove />} @@ -131,7 +131,7 @@ export function SearchBar(props: { onRemove?: () => void }) { </Tooltip> <Tooltip> <TooltipTrigger asChild> - <Button variantType="secondary" variant="ghost" size="xs" iconComponent={<Fullscreen />} onClick={() => {}} /> + <Button type="secondary" variant="ghost" size="xs" iconComponent={<Fullscreen />} onClick={() => {}} /> </TooltipTrigger> <TooltipContent side={'top'}> <p>Mock icon</p> diff --git a/libs/shared/lib/vis/components/bar.tsx b/libs/shared/lib/vis/components/bar.tsx index fe25a8bc0cf2894e87249bb35c749858fadaa405..76cca247925f555cef1e4da560865bb60a9488ba 100644 --- a/libs/shared/lib/vis/components/bar.tsx +++ b/libs/shared/lib/vis/components/bar.tsx @@ -1,12 +1,12 @@ import React from 'react'; -import { Button, DropdownTrigger, DropdownItemContainer, DropdownItem, Icon, DropdownContainer } from '../../components'; +import { Button, Icon } from '../../components'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../components/tooltip'; +import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; import { Add, Close, Fullscreen } from '@mui/icons-material'; import { ControlContainer } from '../../components/controls'; import { Visualizations } from '../manager'; import { VisualizationManagerType } from '../manager'; import { Tabs, Tab } from '../../components/tabs'; -import { Popover, PopoverContent, PopoverTrigger } from '../../components/layout/Popover'; type Props = { manager: VisualizationManagerType; @@ -14,8 +14,6 @@ type Props = { }; export default function VisualizationBar({ manager, fullSize }: Props) { - const [open, setOpen] = React.useState(false); - const handleDragStart = (e: React.DragEvent<HTMLDivElement>, visId: string) => { e.dataTransfer.setData('text/plain', visId); }; @@ -37,35 +35,35 @@ export default function VisualizationBar({ manager, fullSize }: Props) { <h1 className="text-xs font-semibold text-secondary-600 px-2 truncate">Visualization</h1> </div> <div className="items-center shrink-0 px-0.5"> - <TooltipProvider delayDuration={0}> - <Tooltip> - <TooltipTrigger> - <Popover open={open} onOpenChange={setOpen}> - <PopoverTrigger onClick={() => setOpen((v) => !v)}> - <Button as={'a'} variantType="secondary" variant="ghost" size="xs" iconComponent={<Add />} onClick={() => {}} /> - </PopoverTrigger> - <PopoverContent> - <div className="bg-light p-1 rounded border"> - {Object.keys(Visualizations).map((key) => ( - <DropdownItem - value={key} - key={key} - className="text-sm px-2 py-1 rounded cursor-pointer hover:bg-secondary-200" - onClick={(e) => { - manager.changeActive(key); - setOpen(false); - }} - ></DropdownItem> - ))} - </div> - </PopoverContent> - </Popover> - </TooltipTrigger> - <TooltipContent side={'top'}> - <p>Add visualization</p> - </TooltipContent> - </Tooltip> - </TooltipProvider> + <DropdownMenu.Root> + <DropdownMenu.Trigger> + <TooltipProvider delayDuration={0}> + <Tooltip> + <TooltipTrigger asChild> + <Button as={'a'} type="secondary" variant="ghost" size="xs" iconComponent={<Add />} onClick={() => {}} /> + </TooltipTrigger> + <TooltipContent side={'top'}> + <p>Add visualization</p> + </TooltipContent> + </Tooltip> + </TooltipProvider> + </DropdownMenu.Trigger> + <DropdownMenu.Portal> + <DropdownMenu.Content className="bg-light p-1 rounded border"> + {Object.keys(Visualizations).map((key) => ( + <DropdownMenu.Item + key={key} + className="text-sm px-2 py-1 rounded cursor-pointer hover:bg-secondary-200" + onClick={(e) => { + manager.changeActive(key); + }} + > + {key} + </DropdownMenu.Item> + ))} + </DropdownMenu.Content> + </DropdownMenu.Portal> + </DropdownMenu.Root> </div> <Tabs> {manager.tabs.map((visId: string) => { @@ -73,7 +71,7 @@ export default function VisualizationBar({ manager, fullSize }: Props) { return ( <Tab key={visId} - activeTab={isActive} + active={isActive} text={visId} onClick={() => manager.changeActive(visId)} onDragStart={(e) => handleDragStart(e, visId)} @@ -82,7 +80,7 @@ export default function VisualizationBar({ manager, fullSize }: Props) { draggable > <Button - variantType="secondary" + type="secondary" variant="ghost" rounded size="2xs" @@ -101,7 +99,7 @@ export default function VisualizationBar({ manager, fullSize }: Props) { <TooltipProvider delayDuration={0}> <Tooltip> <TooltipTrigger asChild> - <Button variantType="secondary" variant="ghost" size="xs" iconComponent={<Fullscreen />} onClick={fullSize} /> + <Button type="secondary" variant="ghost" size="xs" iconComponent={<Fullscreen />} onClick={fullSize} /> </TooltipTrigger> <TooltipContent side={'top'}> <p>Full screen</p> diff --git a/libs/shared/lib/vis/components/config/ActiveVisualizationConfig.tsx b/libs/shared/lib/vis/components/config/ActiveVisualizationConfig.tsx index 38fe19fa94807f36e69f90b0c5092540ee62ea93..88ed5de608d618f5e211a43b574d4b0c5fbd1e4f 100644 --- a/libs/shared/lib/vis/components/config/ActiveVisualizationConfig.tsx +++ b/libs/shared/lib/vis/components/config/ActiveVisualizationConfig.tsx @@ -13,7 +13,7 @@ export const ActiveVisualizationConfig = ({ manager }: Props) => { <div className="flex justify-between items-center px-4 py-2"> <span className="text-xs font-bold">Visualization</span> <Button - variantType="secondary" + type="secondary" variant="ghost" size="xs" iconComponent={<Delete />} diff --git a/libs/shared/lib/vis/components/config/SelectionConfig.tsx b/libs/shared/lib/vis/components/config/SelectionConfig.tsx index 496bad2c7546aff1f47da9fed9365138e84ed0d1..08dcadd7736db9583d2aedfd89607b0dede8bba6 100644 --- a/libs/shared/lib/vis/components/config/SelectionConfig.tsx +++ b/libs/shared/lib/vis/components/config/SelectionConfig.tsx @@ -16,7 +16,7 @@ export const SelectionConfig = () => { <div className="flex justify-between items-center px-4 py-2"> <span className="text-xs font-bold">Selection</span> <Button - variantType="secondary" + type="secondary" variant="ghost" size="xs" iconComponent={<Delete />} diff --git a/libs/shared/lib/vis/views/noData.tsx b/libs/shared/lib/vis/views/noData.tsx index dc63c70bcc7241f5cd8490410c85f9cd203c5c7d..fafa7b810ea8114ae28dc383b1bf29901ab6a516 100644 --- a/libs/shared/lib/vis/views/noData.tsx +++ b/libs/shared/lib/vis/views/noData.tsx @@ -15,7 +15,7 @@ export function NoData({ dataAvailable }: Props) { <div> <p>Query for data to visualize</p> <Button - variantType="primary" + type="primary" variant="outline" label="Learn how to query data" size="sm" diff --git a/libs/shared/lib/vis/visualizations/paohvis/paohvis.tsx b/libs/shared/lib/vis/visualizations/paohvis/paohvis.tsx index 9a848bd69a6c3258bc44855a8d4032793c6282eb..2b16589f2f6232b3b5b163e7862518d089ea2f8c 100644 --- a/libs/shared/lib/vis/visualizations/paohvis/paohvis.tsx +++ b/libs/shared/lib/vis/visualizations/paohvis/paohvis.tsx @@ -954,7 +954,7 @@ const PaohSettings = ({ </div> <Button className="w-full text-justify justify-start" - variantType="secondary" + type="secondary" variant="ghost" size="sm" onClick={toggleCollapseAttrRows} @@ -989,7 +989,7 @@ const PaohSettings = ({ <Button className="w-full text-justify justify-start" - variantType="secondary" + type="secondary" variant="ghost" size="sm" onClick={toggleCollapseAttrColumns} diff --git a/libs/shared/lib/vis/visualizations/semanticsubstratesvis/components/ConfigPanel.tsx b/libs/shared/lib/vis/visualizations/semanticsubstratesvis/components/ConfigPanel.tsx index 3aadfdeeef1292248c889e421d1043888a1de9e1..449218b011d11fdf536ba793595ba0f8bdb3ab71 100644 --- a/libs/shared/lib/vis/visualizations/semanticsubstratesvis/components/ConfigPanel.tsx +++ b/libs/shared/lib/vis/visualizations/semanticsubstratesvis/components/ConfigPanel.tsx @@ -229,7 +229,7 @@ const ConfigPanel: React.FC<ConfigPanelProps> = ({ data, onUpdateData }) => { <Button label="Make" - variantType="secondary" + type="secondary" variant="solid" disabled={!state.isButtonEnabled || (!state.orderNameXaxis && !state.orderNameYaxis)} onClick={onClickMakeButton} diff --git a/libs/shared/lib/vis/visualizations/tablevis/tablevis.tsx b/libs/shared/lib/vis/visualizations/tablevis/tablevis.tsx index d2070b3f071c16a2ab18f01f4b95fef1b1f402e5..b1ed34e9bfd375276ba9bfcd10cd159d1a7ea6df 100644 --- a/libs/shared/lib/vis/visualizations/tablevis/tablevis.tsx +++ b/libs/shared/lib/vis/visualizations/tablevis/tablevis.tsx @@ -134,7 +134,7 @@ const TableSettings = ({ <span className="text-sm">Attributes to display:</span> <Button className="w-full text-justify justify-start" - variantType="secondary" + type="secondary" variant="ghost" size="sm" onClick={toggleCollapseAttr} diff --git a/libs/shared/package.json b/libs/shared/package.json index 2559e751dfbc0b3ace14d945cefb9b884fbf63e3..166ef8ea4a4f99e1a6077d4793cc2902ee91bdee 100644 --- a/libs/shared/package.json +++ b/libs/shared/package.json @@ -21,9 +21,10 @@ "@deck.gl/react": "^9.0.12", "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.0", - "@floating-ui/react": "^0.26.16", "@mui/icons-material": "^5.15.13", "@pixi-essentials/cull": "^2.0.0", + "@radix-ui/react-dropdown-menu": "^2.0.6", + "@radix-ui/react-tooltip": "^1.0.7", "@reactflow/node-resizer": "^2.2.9", "@reduxjs/toolkit": "^2.2.1", "@tisoap/react-flow-smart-edge": "^3.0.0", diff --git a/libs/storybook/src/stories/Button.stories.ts b/libs/storybook/src/stories/Button.stories.ts new file mode 100644 index 0000000000000000000000000000000000000000..af4e0c31023900be3aefa72d51324cb90f3c566f --- /dev/null +++ b/libs/storybook/src/stories/Button.stories.ts @@ -0,0 +1,44 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { Button } from './Button'; + +// More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction +const meta = { + title: 'Example/Button', + component: Button, + tags: ['autodocs'], + argTypes: { + backgroundColor: { control: 'color' }, + }, +} satisfies Meta<typeof Button>; + +export default meta; +type Story = StoryObj<typeof meta>; + +// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args +export const Primary: Story = { + args: { + primary: true, + label: 'Button', + }, +}; + +export const Secondary: Story = { + args: { + label: 'Button', + }, +}; + +export const Large: Story = { + args: { + size: 'large', + label: 'Button', + }, +}; + +export const Small: Story = { + args: { + size: 'small', + label: 'Button', + }, +}; diff --git a/libs/storybook/src/stories/Button.tsx b/libs/storybook/src/stories/Button.tsx new file mode 100644 index 0000000000000000000000000000000000000000..66f8fd32c60e0a356e7860b428054088027f7b0e --- /dev/null +++ b/libs/storybook/src/stories/Button.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import './button.css'; + +interface ButtonProps { + /** + * Is this the principal call to action on the page? + */ + primary?: boolean; + /** + * What background color to use + */ + backgroundColor?: string; + /** + * How large should the button be? + */ + size?: 'small' | 'medium' | 'large'; + /** + * Button contents + */ + label: string; + /** + * Optional click handler + */ + onClick?: () => void; +} + +/** + * Primary UI component for user interaction + */ +export const Button = ({ primary = false, size = 'medium', backgroundColor, label, ...props }: ButtonProps) => { + const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; + return ( + <button + type="button" + className={['storybook-button', `storybook-button--${size}`, mode].join(' ')} + style={{ backgroundColor }} + {...props} + > + {label} + </button> + ); +}; diff --git a/libs/storybook/src/stories/button.css b/libs/storybook/src/stories/button.css new file mode 100644 index 0000000000000000000000000000000000000000..dc91dc76370b78ec277e634f8615b67ca55a5145 --- /dev/null +++ b/libs/storybook/src/stories/button.css @@ -0,0 +1,30 @@ +.storybook-button { + font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-weight: 700; + border: 0; + border-radius: 3em; + cursor: pointer; + display: inline-block; + line-height: 1; +} +.storybook-button--primary { + color: white; + background-color: #1ea7fd; +} +.storybook-button--secondary { + color: #333; + background-color: transparent; + box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset; +} +.storybook-button--small { + font-size: 12px; + padding: 10px 16px; +} +.storybook-button--medium { + font-size: 14px; + padding: 11px 20px; +} +.storybook-button--large { + font-size: 16px; + padding: 12px 24px; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a88e3a1d09fa6336607a1cdf9f4dd0abb3c4a1cd..e5a659daf44ff8b51e30663154798a4ef46ac156 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -123,7 +123,7 @@ importers: version: 0.5.1(@import-meta-env/cli@0.6.8)(dotenv@16.4.5) '@tailwindcss/typography': specifier: ^0.5.10 - version: 0.5.10(tailwindcss@3.4.1(ts-node@10.9.2(@types/node@20.11.27)(typescript@5.4.2))) + version: 0.5.10(tailwindcss@3.4.1(ts-node@10.9.2(@swc/core@1.4.2(@swc/helpers@0.5.2))(@types/node@20.11.27)(typescript@5.4.2))) '@testing-library/react': specifier: 14.2.1 version: 14.2.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -192,7 +192,7 @@ importers: devDependencies: '@tailwindcss/typography': specifier: ^0.5.10 - version: 0.5.10(tailwindcss@3.4.1(ts-node@10.9.2(@types/node@20.11.27)(typescript@5.4.2))) + version: 0.5.10(tailwindcss@3.4.1(ts-node@10.9.2(@swc/core@1.4.2(@swc/helpers@0.5.2))(@types/node@20.11.27)(typescript@5.4.2))) daisyui: specifier: ^4.7.3 version: 4.7.3(postcss@8.4.35) @@ -223,15 +223,18 @@ importers: '@emotion/styled': specifier: ^11.11.0 version: 11.11.0(@emotion/react@11.11.4(@types/react@18.2.65)(react@18.2.0))(@types/react@18.2.65)(react@18.2.0) - '@floating-ui/react': - specifier: ^0.26.16 - version: 0.26.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@mui/icons-material': specifier: ^5.15.13 version: 5.15.13(@mui/material@5.15.13(@emotion/react@11.11.4(@types/react@18.2.65)(react@18.2.0))(@emotion/styled@11.11.0(@emotion/react@11.11.4(@types/react@18.2.65)(react@18.2.0))(@types/react@18.2.65)(react@18.2.0))(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@types/react@18.2.65)(react@18.2.0) '@pixi-essentials/cull': specifier: ^2.0.0 version: 2.0.0(@pixi/display@7.4.2(@pixi/core@7.4.2))(@pixi/math@7.4.2) + '@radix-ui/react-dropdown-menu': + specifier: ^2.0.6 + version: 2.0.6(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-tooltip': + specifier: ^1.0.7 + version: 1.0.7(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@reactflow/node-resizer': specifier: ^2.2.9 version: 2.2.9(@types/react@18.2.65)(immer@10.0.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -608,7 +611,7 @@ importers: version: 8.0.6(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/preset-scss': specifier: ^1.0.3 - version: 1.0.3(css-loader@6.10.0(webpack@5.90.3(esbuild@0.19.12)))(sass-loader@14.1.1(sass@1.72.0)(webpack@5.90.3(esbuild@0.19.12)))(style-loader@3.3.4(webpack@5.90.3(esbuild@0.19.12))) + version: 1.0.3(css-loader@6.10.0(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12)))(sass-loader@14.1.1(sass@1.72.0)(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12)))(style-loader@3.3.4(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12))) '@storybook/react': specifier: ^8.0.6 version: 8.0.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.2) @@ -656,7 +659,7 @@ importers: version: 1.72.0 sass-loader: specifier: ^14.1.1 - version: 14.1.1(sass@1.72.0)(webpack@5.90.3(esbuild@0.19.12)) + version: 14.1.1(sass@1.72.0)(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12)) storybook: specifier: ^8.0.6 version: 8.0.6(@babel/preset-env@7.24.0(@babel/core@7.24.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -1809,14 +1812,8 @@ packages: '@floating-ui/dom@1.6.3': resolution: {integrity: sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==} - '@floating-ui/react-dom@2.1.0': - resolution: {integrity: sha512-lNzj5EQmEKn5FFKc04+zasr09h/uX8RtJRNj5gUXsSQIXHVWTVh+hVAg1vOMCexkX8EgvemMvIFpQfkosnVNyA==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@floating-ui/react@0.26.16': - resolution: {integrity: sha512-HEf43zxZNAI/E781QIVpYSF3K2VH4TTYZpqecjdsFkjsaU1EbaWcM++kw0HXFffj7gDUcBFevX8s0rQGQpxkow==} + '@floating-ui/react-dom@2.0.8': + resolution: {integrity: sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' @@ -2526,6 +2523,35 @@ packages: '@probe.gl/stats@4.0.9': resolution: {integrity: sha512-Q9Xt/sJUQaMsbjRKjOscv2t7wXIymTrOEJ4a3da4FTCn7bkKvcdxdyFAQySCrtPxE+YZ5I5lXpWPgv9BwmpE1g==} + '@radix-ui/primitive@1.0.1': + resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} + + '@radix-ui/react-arrow@1.0.3': + resolution: {integrity: sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.0.3': + resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + 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: @@ -2535,6 +2561,159 @@ packages: '@types/react': optional: true + '@radix-ui/react-context@1.0.1': + resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-direction@1.0.1': + resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.0.5': + resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-dropdown-menu@2.0.6': + resolution: {integrity: sha512-i6TuFOoWmLWq+M/eCLGd/bQ2HfAX1RJgvrBQ6AQLmzfvsLdefxbWu8G9zczcPFfcSPehz9GcpF6K9QYreFV8hA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.0.1': + resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.0.4': + resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + 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: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-menu@2.0.6': + resolution: {integrity: sha512-BVkFLS+bUC8HcImkRKPSiVumA1VPOOEC5WBMiT+QAVsPzW1FJzI9KnqgGxVDPBcql5xXrHkD3JOVoXWEXD8SYA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.1.3': + resolution: {integrity: sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.0.4': + resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.0.1': + resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@1.0.3': + resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + 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: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-slot@1.0.2': resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} peerDependencies: @@ -2544,6 +2723,89 @@ packages: '@types/react': optional: true + '@radix-ui/react-tooltip@1.0.7': + resolution: {integrity: sha512-lPh5iKNFVQ/jav/j6ZrWq3blfDJ0OH9R6FlNUHPMqdLuQ9vwDgFsRxvl8b7Asuy5c8xmoojHUxKHQSOAvMHxyw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-callback-ref@1.0.1': + resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.0.1': + resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.0.3': + resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.0.1': + resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.0.1': + resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.0.1': + resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.0.3': + resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/rect@1.0.1': + resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} + '@reactflow/background@11.3.9': resolution: {integrity: sha512-byj/G9pEC8tN0wT/ptcl/LkEP/BBfa33/SvBkqE4XwyofckqF87lKp573qGlisfnsijwAbpDlf81PuFL41So4Q==} peerDependencies: @@ -3882,6 +4144,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-hidden@1.2.3: + resolution: {integrity: sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==} + engines: {node: '>=10'} + aria-query@5.1.3: resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} @@ -4762,6 +5028,9 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + detect-package-manager@2.0.1: resolution: {integrity: sha512-j/lJHyoLlWi6G1LDdLgvUtz60Zo5GEj+sVYtTVXnYLDPuzgC3llMxonXym9zIwhhUII8vjdw0LXxavpLqTbl1A==} engines: {node: '>=12'} @@ -5326,6 +5595,10 @@ packages: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + get-npm-tarball-url@2.1.0: resolution: {integrity: sha512-ro+DiMu5DXgRBabqXupW38h7WPZ9+Ad8UjwhvsmmN8w1sU7ab0nzAXvVZ4kqYg57OrqomRtJvepX5/xvFKNtjA==} engines: {node: '>=12.17'} @@ -5686,6 +5959,9 @@ packages: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} engines: {node: '>=12'} + invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + ip@2.0.1: resolution: {integrity: sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==} @@ -7123,6 +7399,27 @@ packages: resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} engines: {node: '>=0.10.0'} + react-remove-scroll-bar@2.3.5: + resolution: {integrity: sha512-3cqjOqg6s0XbOjWvmasmqHch+RLxIEk2r/70rzGXuz3iIGQsQheEQyqYCBb5EECoD01Vo2SIbDqW4paLeLTASw==} + engines: {node: '>=10'} + deprecated: please update to the following version as this contains a bug (https://github.com/theKashey/react-remove-scroll-bar/issues/57) + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.5.5: + resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + react-resizable@3.0.5: resolution: {integrity: sha512-vKpeHhI5OZvYn82kXOs1bC8aOXktGU5AmKAgaZS4F5JPburCtbmDPqE7Pzp+1kN4+Wb81LlF33VpGwWwtXem+w==} peerDependencies: @@ -7146,6 +7443,16 @@ packages: peerDependencies: react: ^16.0.0 || ^17.0.0 || ^18.0.0 + react-style-singleton@2.2.1: + resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + react-test-renderer@18.2.0: resolution: {integrity: sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA==} peerDependencies: @@ -8137,6 +8444,16 @@ packages: url@0.11.3: resolution: {integrity: sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==} + use-callback-ref@1.3.1: + resolution: {integrity: sha512-Lg4Vx1XZQauB42Hw3kK7JM6yjVjgFmFC5/Ab797s79aARomD2nEErc4mCgM8EZrARLmmbWpi5DGCadmK50DcAQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + use-composed-ref@1.3.0: resolution: {integrity: sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==} peerDependencies: @@ -8166,6 +8483,16 @@ packages: '@types/react': optional: true + use-sidecar@1.1.2: + resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + use-sync-external-store@1.2.0: resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} peerDependencies: @@ -9853,20 +10180,12 @@ snapshots: '@floating-ui/core': 1.6.0 '@floating-ui/utils': 0.2.1 - '@floating-ui/react-dom@2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@floating-ui/react-dom@2.0.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@floating-ui/dom': 1.6.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@floating-ui/react@0.26.16(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': - dependencies: - '@floating-ui/react-dom': 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@floating-ui/utils': 0.2.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - tabbable: 6.2.0 - '@floating-ui/utils@0.2.1': {} '@gilbarbara/deep-equal@0.1.2': {} @@ -10299,7 +10618,7 @@ snapshots: '@mui/base@5.0.0-beta.39(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.24.0 - '@floating-ui/react-dom': 2.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@floating-ui/react-dom': 2.0.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@mui/types': 7.2.13(@types/react@18.2.65) '@mui/utils': 5.15.13(@types/react@18.2.65)(react@18.2.0) '@popperjs/core': 2.11.8 @@ -10656,6 +10975,33 @@ snapshots: '@probe.gl/stats@4.0.9': {} + '@radix-ui/primitive@1.0.1': + dependencies: + '@babel/runtime': 7.24.0 + + '@radix-ui/react-arrow@1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(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': 18.2.65 + '@types/react-dom': 18.2.22 + + '@radix-ui/react-collection@1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.65)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.65 + '@types/react-dom': 18.2.22 + '@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.65)(react@18.2.0)': dependencies: '@babel/runtime': 7.24.0 @@ -10663,6 +11009,172 @@ snapshots: optionalDependencies: '@types/react': 18.2.65 + '@radix-ui/react-context@1.0.1(@types/react@18.2.65)(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.65 + + '@radix-ui/react-direction@1.0.1(@types/react@18.2.65)(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.65 + + '@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.2.65)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.65 + '@types/react-dom': 18.2.22 + + '@radix-ui/react-dropdown-menu@2.0.6(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-menu': 2.0.6(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.65)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.65 + '@types/react-dom': 18.2.22 + + '@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.65)(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.65 + + '@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.65)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.65 + '@types/react-dom': 18.2.22 + + '@radix-ui/react-id@1.0.1(@types/react@18.2.65)(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.65)(react@18.2.0) + react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.65 + + '@radix-ui/react-menu@2.0.6(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.65)(react@18.2.0) + aria-hidden: 1.2.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-remove-scroll: 2.5.5(@types/react@18.2.65)(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.65 + '@types/react-dom': 18.2.22 + + '@radix-ui/react-popper@1.1.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + '@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.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-use-rect': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/rect': 1.0.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.65 + '@types/react-dom': 18.2.22 + + '@radix-ui/react-portal@1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(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': 18.2.65 + '@types/react-dom': 18.2.22 + + '@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.65)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.65 + '@types/react-dom': 18.2.22 + + '@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.65)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.65 + '@types/react-dom': 18.2.22 + + '@radix-ui/react-roving-focus@1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.65)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.65 + '@types/react-dom': 18.2.22 + '@radix-ui/react-slot@1.0.2(@types/react@18.2.65)(react@18.2.0)': dependencies: '@babel/runtime': 7.24.0 @@ -10671,6 +11183,87 @@ snapshots: optionalDependencies: '@types/react': 18.2.65 + '@radix-ui/react-tooltip@1.0.7(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.65)(react@18.2.0) + '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(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': 18.2.65 + '@types/react-dom': 18.2.22 + + '@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.65)(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.65 + + '@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.65)(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.65)(react@18.2.0) + react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.65 + + '@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.65)(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.65)(react@18.2.0) + react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.65 + + '@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.65)(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.65 + + '@radix-ui/react-use-rect@1.0.1(@types/react@18.2.65)(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + '@radix-ui/rect': 1.0.1 + react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.65 + + '@radix-ui/react-use-size@1.0.1(@types/react@18.2.65)(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.65)(react@18.2.0) + react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.65 + + '@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.0 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(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': 18.2.65 + '@types/react-dom': 18.2.22 + + '@radix-ui/rect@1.0.1': + dependencies: + '@babel/runtime': 7.24.0 + '@reactflow/background@11.3.9(@types/react@18.2.65)(immer@10.0.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@reactflow/core': 11.10.4(@types/react@18.2.65)(immer@10.0.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -11307,18 +11900,18 @@ snapshots: '@storybook/node-logger@8.0.6': {} + '@storybook/preset-scss@1.0.3(css-loader@6.10.0(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12)))(sass-loader@14.1.1(sass@1.72.0)(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12)))(style-loader@3.3.4(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12)))': + dependencies: + css-loader: 6.10.0(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12)) + sass-loader: 14.1.1(sass@1.72.0)(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12)) + style-loader: 3.3.4(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12)) + '@storybook/preset-scss@1.0.3(css-loader@6.10.0(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))))(sass-loader@14.1.1(sass@1.72.0)(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))))(style-loader@3.3.4(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))))': dependencies: css-loader: 6.10.0(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))) sass-loader: 14.1.1(sass@1.72.0)(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))) style-loader: 3.3.4(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))) - '@storybook/preset-scss@1.0.3(css-loader@6.10.0(webpack@5.90.3(esbuild@0.19.12)))(sass-loader@14.1.1(sass@1.72.0)(webpack@5.90.3(esbuild@0.19.12)))(style-loader@3.3.4(webpack@5.90.3(esbuild@0.19.12)))': - dependencies: - css-loader: 6.10.0(webpack@5.90.3(esbuild@0.19.12)) - sass-loader: 14.1.1(sass@1.72.0)(webpack@5.90.3(esbuild@0.19.12)) - style-loader: 3.3.4(webpack@5.90.3(esbuild@0.19.12)) - '@storybook/preview-api@8.0.6': dependencies: '@storybook/channels': 8.0.6 @@ -11508,7 +12101,7 @@ snapshots: '@swc/types@0.1.5': {} - '@tailwindcss/typography@0.5.10(tailwindcss@3.4.1(ts-node@10.9.2(@types/node@20.11.27)(typescript@5.4.2)))': + '@tailwindcss/typography@0.5.10(tailwindcss@3.4.1(ts-node@10.9.2(@swc/core@1.4.2(@swc/helpers@0.5.2))(@types/node@20.11.27)(typescript@5.4.2)))': dependencies: lodash.castarray: 4.4.0 lodash.isplainobject: 4.0.6 @@ -12725,6 +13318,10 @@ snapshots: argparse@2.0.1: {} + aria-hidden@1.2.3: + dependencies: + tslib: 2.6.2 + aria-query@5.1.3: dependencies: deep-equal: 2.2.3 @@ -13307,7 +13904,7 @@ snapshots: utrie: 1.0.2 optional: true - css-loader@6.10.0(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))): + css-loader@6.10.0(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12)): dependencies: icss-utils: 5.1.0(postcss@8.4.35) postcss: 8.4.35 @@ -13318,9 +13915,9 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.6.0 optionalDependencies: - webpack: 5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2)) + webpack: 5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12) - css-loader@6.10.0(webpack@5.90.3(esbuild@0.19.12)): + css-loader@6.10.0(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))): dependencies: icss-utils: 5.1.0(postcss@8.4.35) postcss: 8.4.35 @@ -13331,7 +13928,7 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.6.0 optionalDependencies: - webpack: 5.90.3(esbuild@0.19.12) + webpack: 5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2)) css-selector-tokenizer@0.8.0: dependencies: @@ -13712,6 +14309,8 @@ snapshots: detect-indent@6.1.0: {} + detect-node-es@1.1.0: {} + detect-package-manager@2.0.1: dependencies: execa: 5.1.1 @@ -14577,6 +15176,8 @@ snapshots: has-symbols: 1.0.3 hasown: 2.0.1 + get-nonce@1.0.1: {} + get-npm-tarball-url@2.1.0: {} get-stream@6.0.1: {} @@ -14940,6 +15541,10 @@ snapshots: internmap@2.0.3: {} + invariant@2.2.4: + dependencies: + loose-envify: 1.4.0 + ip@2.0.1: {} ipaddr.js@1.9.1: {} @@ -16307,6 +16912,25 @@ snapshots: react-refresh@0.14.0: {} + react-remove-scroll-bar@2.3.5(@types/react@18.2.65)(react@18.2.0): + dependencies: + react: 18.2.0 + react-style-singleton: 2.2.1(@types/react@18.2.65)(react@18.2.0) + tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.2.65 + + react-remove-scroll@2.5.5(@types/react@18.2.65)(react@18.2.0): + dependencies: + react: 18.2.0 + react-remove-scroll-bar: 2.3.5(@types/react@18.2.65)(react@18.2.0) + react-style-singleton: 2.2.1(@types/react@18.2.65)(react@18.2.0) + tslib: 2.6.2 + use-callback-ref: 1.3.1(@types/react@18.2.65)(react@18.2.0) + use-sidecar: 1.1.2(@types/react@18.2.65)(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.65 + react-resizable@3.0.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: prop-types: 15.8.1 @@ -16333,6 +16957,15 @@ snapshots: react: 18.2.0 react-is: 18.2.0 + react-style-singleton@2.2.1(@types/react@18.2.65)(react@18.2.0): + dependencies: + get-nonce: 1.0.1 + invariant: 2.2.4 + react: 18.2.0 + tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.2.65 + react-test-renderer@18.2.0(react@18.2.0): dependencies: react: 18.2.0 @@ -16627,19 +17260,19 @@ snapshots: safer-buffer@2.1.2: {} - sass-loader@14.1.1(sass@1.72.0)(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))): + sass-loader@14.1.1(sass@1.72.0)(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12)): dependencies: neo-async: 2.6.2 optionalDependencies: sass: 1.72.0 - webpack: 5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2)) + webpack: 5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12) - sass-loader@14.1.1(sass@1.72.0)(webpack@5.90.3(esbuild@0.19.12)): + sass-loader@14.1.1(sass@1.72.0)(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))): dependencies: neo-async: 2.6.2 optionalDependencies: sass: 1.72.0 - webpack: 5.90.3(esbuild@0.19.12) + webpack: 5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2)) sass@1.72.0: dependencies: @@ -16934,13 +17567,13 @@ snapshots: strnum@1.0.5: {} - style-loader@3.3.4(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))): + style-loader@3.3.4(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12)): dependencies: - webpack: 5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2)) + webpack: 5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12) - style-loader@3.3.4(webpack@5.90.3(esbuild@0.19.12)): + style-loader@3.3.4(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))): dependencies: - webpack: 5.90.3(esbuild@0.19.12) + webpack: 5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2)) styled-components@6.1.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: @@ -17073,27 +17706,28 @@ snapshots: type-fest: 0.16.0 unique-string: 2.0.0 - terser-webpack-plugin@5.3.10(@swc/core@1.4.2(@swc/helpers@0.5.2))(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))): + terser-webpack-plugin@5.3.10(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12)(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.29.2 - webpack: 5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2)) + webpack: 5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12) optionalDependencies: '@swc/core': 1.4.2(@swc/helpers@0.5.2) + esbuild: 0.19.12 - terser-webpack-plugin@5.3.10(esbuild@0.19.12)(webpack@5.90.3(esbuild@0.19.12)): + terser-webpack-plugin@5.3.10(@swc/core@1.4.2(@swc/helpers@0.5.2))(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.29.2 - webpack: 5.90.3(esbuild@0.19.12) + webpack: 5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2)) optionalDependencies: - esbuild: 0.19.12 + '@swc/core': 1.4.2(@swc/helpers@0.5.2) terser@5.29.2: dependencies: @@ -17428,6 +18062,13 @@ snapshots: punycode: 1.4.1 qs: 6.11.2 + use-callback-ref@1.3.1(@types/react@18.2.65)(react@18.2.0): + dependencies: + react: 18.2.0 + tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.2.65 + use-composed-ref@1.3.0(react@18.2.0): dependencies: react: 18.2.0 @@ -17450,6 +18091,14 @@ snapshots: optionalDependencies: '@types/react': 18.2.65 + use-sidecar@1.1.2(@types/react@18.2.65)(react@18.2.0): + dependencies: + detect-node-es: 1.1.0 + react: 18.2.0 + tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.2.65 + use-sync-external-store@1.2.0(react@18.2.0): dependencies: react: 18.2.0 @@ -17654,7 +18303,7 @@ snapshots: - esbuild - uglify-js - webpack@5.90.3(esbuild@0.19.12): + webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.5 @@ -17677,7 +18326,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(esbuild@0.19.12)(webpack@5.90.3(esbuild@0.19.12)) + terser-webpack-plugin: 5.3.10(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12)(webpack@5.90.3(@swc/core@1.4.2(@swc/helpers@0.5.2))(esbuild@0.19.12)) watchpack: 2.4.1 webpack-sources: 3.2.3 transitivePeerDependencies: