fix(ui): tooltip stays open on hover [EE-3445] (#8051)

pull/8160/head
Prabhat Khera 2022-12-05 09:47:43 +13:00 committed by GitHub
parent c173888b64
commit cbaba43842
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 191 additions and 177 deletions

View File

@ -398,3 +398,50 @@ input:-webkit-autofill {
border-bottom-right-radius: 8px; border-bottom-right-radius: 8px;
padding: 5px; padding: 5px;
} }
/* Tippy */
/* For triangle arrow (Sharp) */
/* Tippy */
/* For triangle arrow (Sharp) */
.tippy-box[data-placement^='top'] > .tippy-arrow:before {
border-top: 8px solid var(--bg-tooltip-color);
}
.tippy-box[data-placement^='bottom'] > .tippy-arrow:before {
border-bottom: 8px solid var(--bg-tooltip-color);
}
.tippy-box[data-placement^='right'] > .tippy-arrow:before {
border-right: 8px solid var(--bg-tooltip-color);
}
.tippy-box[data-placement^='left'] > .tippy-arrow:before {
border-left: 8px solid var(--bg-tooltip-color);
}
/* Sidebar */
.sidebar .tippy-box {
font-size: 12px;
}
.sidebar .tippy-box[data-placement^='right'] > .tippy-arrow {
width: 12px;
height: 12px;
}
.sidebar .tippy-box[data-placement^='right'] > .tippy-arrow:before {
border-right: 8px solid var(--ui-gray-9);
border-width: 6px 8px 6px 0;
}
[theme='dark'] .sidebar .tippy-box[data-placement^='right'] > .tippy-arrow:before {
border-right: 8px solid var(--ui-gray-true-9);
}
.sidebar .tippy-content {
white-space: nowrap;
}
.tippy-content {
padding: 0;
}

View File

@ -14,15 +14,17 @@ export function YAMLReplace({ featureId }: Props) {
BEFeatureID={featureId} BEFeatureID={featureId}
message="Applies any changes that you make in the YAML editor by calling the Kubernetes API to patch the relevant resources. Any resource removals or unexpected resource additions that you make in the YAML will be ignored. Note that editing is disabled for resources in namespaces marked as system." message="Applies any changes that you make in the YAML editor by calling the Kubernetes API to patch the relevant resources. Any resource removals or unexpected resource additions that you make in the YAML will be ignored. Note that editing is disabled for resources in namespaces marked as system."
> >
<Button <div className="float-right">
type="button" <Button
color="warninglight" type="button"
size="small" color="warninglight"
onClick={() => {}} size="small"
disabled onClick={() => {}}
> disabled
Apply changes >
</Button> Apply changes
</Button>
</div>
</TooltipWithChildren> </TooltipWithChildren>
); );
} }

View File

@ -1,6 +1,7 @@
import clsx from 'clsx'; import clsx from 'clsx';
import { PropsWithChildren } from 'react'; import { PropsWithChildren } from 'react';
import ReactTooltip from 'react-tooltip';
import { Tooltip } from '@@/Tip/Tooltip';
import './BoxSelectorItem.css'; import './BoxSelectorItem.css';
@ -28,16 +29,8 @@ export function BoxOption<T extends number | string>({
type = 'radio', type = 'radio',
children, children,
}: PropsWithChildren<Props<T>>) { }: PropsWithChildren<Props<T>>) {
const tooltipId = `box-option-${radioName}-${option.id}`;
return ( return (
<div <div className={clsx('box-selector-item', className)}>
className={clsx('box-selector-item', className)}
data-tip
data-for={tooltipId}
tooltip-append-to-body="true"
tooltip-placement="bottom"
tooltip-class="portainer-tooltip"
>
<input <input
type={type} type={type}
name={radioName} name={radioName}
@ -52,13 +45,11 @@ export function BoxOption<T extends number | string>({
{children} {children}
</label> </label>
{tooltip && ( {tooltip && (
<ReactTooltip <Tooltip
place="bottom" position="bottom"
className="portainer-tooltip" className="portainer-tooltip"
id={tooltipId} message={tooltip}
> />
{tooltip}
</ReactTooltip>
)} )}
</div> </div>
); );

View File

@ -1,8 +1,9 @@
import ReactTooltip from 'react-tooltip';
import { HelpCircle } from 'lucide-react'; import { HelpCircle } from 'lucide-react';
import clsx from 'clsx';
import { FeatureId } from '@/react/portainer/feature-flags/enums'; import { FeatureId } from '@/react/portainer/feature-flags/enums';
import { TooltipWithChildren } from '@@/Tip/TooltipWithChildren';
import { getFeatureDetails } from '@@/BEFeatureIndicator/utils'; import { getFeatureDetails } from '@@/BEFeatureIndicator/utils';
interface Props { interface Props {
@ -10,35 +11,24 @@ interface Props {
featureId?: FeatureId; featureId?: FeatureId;
} }
export function LimitedToBeIndicator({ tooltipId, featureId }: Props) { export function LimitedToBeIndicator({ featureId, tooltipId }: Props) {
const { url } = getFeatureDetails(featureId); const { url } = getFeatureDetails(featureId);
return ( return (
<> <div className="absolute left-0 top-0 w-full">
<div className="absolute left-0 top-0 w-full"> <div className="mx-auto max-w-fit bg-warning-4 rounded-b-lg py-1 px-3 flex gap-1 text-sm items-center">
<div className="mx-auto max-w-fit bg-warning-4 rounded-b-lg py-1 px-3 flex gap-1 text-sm items-center"> <a href={url} target="_blank" rel="noopener noreferrer">
<a href={url} target="_blank" rel="noopener noreferrer"> <span className="text-warning-9">Pro Feature</span>
<span className="text-warning-9">Pro Feature</span> </a>
</a> <TooltipWithChildren
<HelpCircle position="bottom"
className="lucide !text-warning-7" className={clsx(tooltipId, 'portainer-tooltip')}
data-tip heading="Business Edition feature."
data-for={tooltipId} message="This feature is currently limited to Business Edition users only."
tooltip-append-to-body="true" >
tooltip-placement="top" <HelpCircle className="ml-1 !text-warning-7" aria-hidden="true" />
tooltip-class="portainer-tooltip" </TooltipWithChildren>
/>
</div>
</div> </div>
<ReactTooltip </div>
className="portainer-tooltip"
id={tooltipId}
place="top"
delayHide={1000}
>
Business Edition feature. <br />
This feature is currently limited to Business Edition users only.
</ReactTooltip>
</>
); );
} }

View File

@ -1,25 +0,0 @@
:global(portainer-tooltip) {
@apply inline-flex;
}
.tooltip-wrapper {
display: inline-block;
position: relative;
}
.tooltip {
background-color: var(--bg-tooltip-color) !important;
padding: 0.833em 1em !important;
color: var(--text-tooltip-color) !important;
border-radius: 10px !important;
box-shadow: 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15) !important;
max-width: 400px;
text-align: center;
font-size: 12px !important;
font-weight: 400;
}
.icon {
margin-left: 5px;
cursor: pointer;
}

View File

@ -1,11 +1,6 @@
import ReactTooltip from 'react-tooltip';
import { HelpCircle } from 'lucide-react'; import { HelpCircle } from 'lucide-react';
import clsx from 'clsx';
import _ from 'lodash';
import styles from './Tooltip.module.css'; import { TooltipWithChildren, Position } from '../TooltipWithChildren';
type Position = 'top' | 'right' | 'bottom' | 'left';
export interface Props { export interface Props {
position?: Position; position?: Position;
@ -14,24 +9,15 @@ export interface Props {
} }
export function Tooltip({ message, position = 'bottom', className }: Props) { export function Tooltip({ message, position = 'bottom', className }: Props) {
const id = _.uniqueId('tooltip-');
return ( return (
<span <TooltipWithChildren
data-tip={message} message={message}
data-for={id} position={position}
className={clsx(styles.icon, 'inline-flex text-base')} className={className}
> >
<HelpCircle className="lucide" aria-hidden="true" /> <span className="inline-flex text-base">
<ReactTooltip <HelpCircle className="lucide ml-1" aria-hidden="true" />
id={id} </span>
multiline </TooltipWithChildren>
type="info"
place={position}
effect="solid"
className={clsx(styles.tooltip, className)}
arrowColor="transparent"
/>
</span>
); );
} }

View File

@ -2,20 +2,14 @@
@apply inline-flex; @apply inline-flex;
} }
.tooltip-wrapper {
display: inline-block;
position: relative;
}
.tooltip { .tooltip {
background-color: var(--bg-tooltip-color) !important; background-color: var(--bg-tooltip-color) !important;
padding: 0.833em 1em !important;
color: var(--text-tooltip-color) !important; color: var(--text-tooltip-color) !important;
border-radius: 10px !important; border-radius: 10px !important;
box-shadow: 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15) !important; box-shadow: 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15) !important;
max-width: 400px; min-width: 300px;
font-size: 1rem !important;
text-align: left; text-align: left;
font-size: 12px !important;
font-weight: 400; font-weight: 400;
} }
@ -26,6 +20,8 @@
.tooltip-container { .tooltip-container {
line-height: 18px; line-height: 18px;
padding: 8px 10px !important;
font-size: 12px !important;
} }
.tooltip-heading { .tooltip-heading {

View File

@ -1,7 +1,9 @@
import ReactTooltip from 'react-tooltip'; import React, { MouseEvent } from 'react';
import Tippy from '@tippyjs/react';
import clsx from 'clsx'; import clsx from 'clsx';
import _ from 'lodash'; import _ from 'lodash';
import ReactDOMServer from 'react-dom/server';
import 'tippy.js/dist/tippy.css';
import { FeatureId } from '@/react/portainer/feature-flags/enums'; import { FeatureId } from '@/react/portainer/feature-flags/enums';
@ -9,13 +11,13 @@ import { getFeatureDetails } from '@@/BEFeatureIndicator/utils';
import styles from './TooltipWithChildren.module.css'; import styles from './TooltipWithChildren.module.css';
type Position = 'top' | 'right' | 'bottom' | 'left'; export type Position = 'top' | 'right' | 'bottom' | 'left';
export interface Props { export interface Props {
position?: Position; position?: Position;
message: string; message: string;
className?: string; className?: string;
children: React.ReactNode; children: React.ReactElement;
heading?: string; heading?: string;
BEFeatureID?: FeatureId; BEFeatureID?: FeatureId;
} }
@ -35,49 +37,53 @@ export function TooltipWithChildren({
: { url: '', limitedToBE: false }; : { url: '', limitedToBE: false };
const messageHTML = ( const messageHTML = (
<div className={styles.tooltipContainer}> // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
<div <div className={styles.tooltipContainer} onClick={onClickHandler}>
className={clsx( {(heading || (BEFeatureID && limitedToBE)) && (
'w-full mb-2 inline-flex justify-between', <div className="w-full mb-3 inline-flex justify-between">
styles.tooltipHeading <span>{heading}</span>
)} {BEFeatureID && limitedToBE && (
> <a
{heading && <span>{heading}</span>} href={url}
{BEFeatureID && limitedToBE && ( target="_blank"
<a rel="noreferrer"
href={url} className={styles.tooltipBeteaser}
target="_blank" >
rel="noreferrer" Business Edition Only
className={styles.tooltipBeteaser} </a>
> )}
Business Edition Only </div>
</a> )}
)}
</div>
<div>{message}</div> <div>{message}</div>
</div> </div>
); );
return ( return (
<span <Tippy
data-html className={clsx(id, styles.tooltip, className)}
data-multiline content={messageHTML}
data-tip={ReactDOMServer.renderToString(messageHTML)} delay={[50, 500]} // 50ms to open, 500ms to hide
data-for={id} zIndex={1000}
className={clsx(styles.icon, 'inline-flex text-base')} placement={position}
maxWidth={400}
arrow
allowHTML
interactive
> >
{children} {children}
<ReactTooltip </Tippy>
id={id}
multiline
type="info"
place={position}
effect="solid"
className={clsx(styles.tooltip, className)}
arrowColor="var(--bg-tooltip-color)"
delayHide={400}
clickable
/>
</span>
); );
} }
// Preventing click bubbling to the parent as it is affecting
// mainly toggles when full row is clickable.
function onClickHandler(e: MouseEvent) {
const target = e.target as HTMLInputElement;
if (target.tagName.toLowerCase() === 'a') {
const url = target.getAttribute('href');
if (url) {
window.open(url, '_blank');
}
}
e.preventDefault();
}

View File

@ -1 +1,2 @@
export { TooltipWithChildren } from './TooltipWithChildren'; export { TooltipWithChildren } from './TooltipWithChildren';
export type { Position } from './TooltipWithChildren';

View File

@ -30,7 +30,7 @@ export function Sidebar() {
return ( return (
/* in the future (when we remove r2a) this should wrap the whole app - to change root styles */ /* in the future (when we remove r2a) this should wrap the whole app - to change root styles */
<SidebarProvider> <SidebarProvider>
<div className={clsx(styles.root, 'flex flex-col')}> <div className={clsx(styles.root, 'sidebar flex flex-col')}>
<UpgradeBEBanner /> <UpgradeBEBanner />
<nav <nav
className={clsx( className={clsx(

View File

@ -5,10 +5,11 @@ import {
} from '@uirouter/react'; } from '@uirouter/react';
import clsx from 'clsx'; import clsx from 'clsx';
import { ComponentProps } from 'react'; import { ComponentProps } from 'react';
import ReactTooltip from 'react-tooltip'; import Tippy from '@tippyjs/react';
import { AutomationTestingProps } from '@/types'; import { AutomationTestingProps } from '@/types';
import 'tippy.js/dist/tippy.css';
import { Link } from '@@/Link'; import { Link } from '@@/Link';
import { IconProps, Icon } from '@@/Icon'; import { IconProps, Icon } from '@@/Icon';
@ -40,7 +41,7 @@ export function Head({
ignorePaths ignorePaths
); );
return ( const anchor = (
<a <a
href={anchorProps.href} href={anchorProps.href}
onClick={anchorProps.onClick} onClick={anchorProps.onClick}
@ -54,22 +55,30 @@ export function Head({
'justify-center w-8': !isOpen, 'justify-center w-8': !isOpen,
} }
)} )}
data-tip={label}
data-cy={dataCy} data-cy={dataCy}
> >
{!!icon && <Icon icon={icon} className={clsx('flex [&>svg]:w-4')} />} {!!icon && <Icon icon={icon} className={clsx('flex [&>svg]:w-4')} />}
{isOpen && <span>{label}</span>} {isOpen && <span>{label}</span>}
<ReactTooltip
type="info"
place="right"
effect="solid"
className="!opacity-100 bg-blue-9 be:bg-gray-9 !rounded-md !py-1 !px-2"
arrowColor="transparent"
disable={isOpen}
/>
</a> </a>
); );
if (isOpen) return anchor;
return (
<Tippy
className="!opacity-100 bg-blue-9 be:bg-gray-9 th-dark:bg-gray-true-9 !rounded-md !py-2 !px-3"
content={label}
delay={[0, 0]}
duration={[0, 0]}
zIndex={1000}
placement="right"
arrow
allowHTML
interactive
>
{anchor}
</Tippy>
);
} }
function useSrefActive( function useSrefActive(

View File

@ -33,6 +33,10 @@ export function Menu({
const CollapseButtonIcon = isOpen ? ChevronUp : ChevronDown; const CollapseButtonIcon = isOpen ? ChevronUp : ChevronDown;
if (!isSidebarOpen) {
return head as JSX.Element;
}
return ( return (
<div className="flex-1"> <div className="flex-1">
<div className="flex w-full justify-between items-center relative "> <div className="flex w-full justify-between items-center relative ">

View File

@ -39,7 +39,7 @@ export function SidebarItem({
); );
return ( return (
<Wrapper label={label}> <Wrapper label={label} className="sidebar">
{children ? ( {children ? (
<Menu head={head} openOnPaths={[...openOnPaths, ...childrenPath]}> <Menu head={head} openOnPaths={[...openOnPaths, ...childrenPath]}>
{children} {children}

View File

@ -71,6 +71,7 @@
"@open-amt-cloud-toolkit/ui-toolkit-react": "2.0.0", "@open-amt-cloud-toolkit/ui-toolkit-react": "2.0.0",
"@reach/dialog": "^0.17.0", "@reach/dialog": "^0.17.0",
"@reach/menu-button": "^0.16.1", "@reach/menu-button": "^0.16.1",
"@tippyjs/react": "^4.2.6",
"@uirouter/angularjs": "1.0.11", "@uirouter/angularjs": "1.0.11",
"@uirouter/react": "^1.0.7", "@uirouter/react": "^1.0.7",
"@uirouter/react-hybrid": "^1.0.4", "@uirouter/react-hybrid": "^1.0.4",
@ -131,12 +132,12 @@
"react-query": "^3.33.4", "react-query": "^3.33.4",
"react-select": "^5.2.1", "react-select": "^5.2.1",
"react-table": "^7.7.0", "react-table": "^7.7.0",
"react-tooltip": "^4.2.21",
"sanitize-html": "^2.5.3", "sanitize-html": "^2.5.3",
"semver-compare": "^1.0.0", "semver-compare": "^1.0.0",
"spinkit": "^2.0.1", "spinkit": "^2.0.1",
"splitargs": "github:deviantony/splitargs#semver:~0.2.0", "splitargs": "github:deviantony/splitargs#semver:~0.2.0",
"strip-ansi": "^6.0.0", "strip-ansi": "^6.0.0",
"tippy.js": "^6.3.7",
"toastr": "^2.1.4", "toastr": "^2.1.4",
"uuid": "^3.3.2", "uuid": "^3.3.2",
"xterm": "^3.8.0", "xterm": "^3.8.0",

View File

@ -3068,6 +3068,11 @@
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1"
integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==
"@popperjs/core@^2.9.0":
version "2.11.6"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45"
integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==
"@reach/auto-id@0.16.0": "@reach/auto-id@0.16.0":
version "0.16.0" version "0.16.0"
resolved "https://registry.yarnpkg.com/@reach/auto-id/-/auto-id-0.16.0.tgz#dfabc3227844e8c04f8e6e45203a8e14a8edbaed" resolved "https://registry.yarnpkg.com/@reach/auto-id/-/auto-id-0.16.0.tgz#dfabc3227844e8c04f8e6e45203a8e14a8edbaed"
@ -4382,6 +4387,13 @@
dependencies: dependencies:
"@babel/runtime" "^7.12.5" "@babel/runtime" "^7.12.5"
"@tippyjs/react@^4.2.6":
version "4.2.6"
resolved "https://registry.yarnpkg.com/@tippyjs/react/-/react-4.2.6.tgz#971677a599bf663f20bb1c60a62b9555b749cc71"
integrity sha512-91RicDR+H7oDSyPycI13q3b7o4O60wa2oRbjlz2fyRLmHImc4vyDwuUP8NtZaN0VARJY5hybvDYrFzhY9+Lbyw==
dependencies:
tippy.js "^6.3.1"
"@tootallnate/once@1": "@tootallnate/once@1":
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
@ -15684,14 +15696,6 @@ react-time-picker@^4.5.0:
react-fit "^1.4.0" react-fit "^1.4.0"
update-input-width "^1.2.2" update-input-width "^1.2.2"
react-tooltip@^4.2.21:
version "4.2.21"
resolved "https://registry.yarnpkg.com/react-tooltip/-/react-tooltip-4.2.21.tgz#840123ed86cf33d50ddde8ec8813b2960bfded7f"
integrity sha512-zSLprMymBDowknr0KVDiJ05IjZn9mQhhg4PRsqln0OZtURAJ1snt1xi5daZfagsh6vfsziZrc9pErPTDY1ACig==
dependencies:
prop-types "^15.7.2"
uuid "^7.0.3"
react-transition-group@^4.3.0: react-transition-group@^4.3.0:
version "4.4.2" version "4.4.2"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470"
@ -17707,6 +17711,13 @@ tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3:
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
tippy.js@^6.3.1, tippy.js@^6.3.7:
version "6.3.7"
resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.3.7.tgz#8ccfb651d642010ed9a32ff29b0e9e19c5b8c61c"
integrity sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==
dependencies:
"@popperjs/core" "^2.9.0"
title-case@^2.1.0: title-case@^2.1.0:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/title-case/-/title-case-2.1.1.tgz#3e127216da58d2bc5becf137ab91dae3a7cd8faa" resolved "https://registry.yarnpkg.com/title-case/-/title-case-2.1.1.tgz#3e127216da58d2bc5becf137ab91dae3a7cd8faa"
@ -18332,11 +18343,6 @@ uuid@^3.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
uuid@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b"
integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==
uuid@^8.3.0, uuid@^8.3.2: uuid@^8.3.0, uuid@^8.3.2:
version "8.3.2" version "8.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"