✨(react) add Tooltip component
This component will allow to provide contextual information on any DOM node. Closes #239
This commit is contained in:
5
.changeset/shiny-days-notice.md
Normal file
5
.changeset/shiny-days-notice.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@openfun/cunningham-react": minor
|
||||
---
|
||||
|
||||
add Tooltip component
|
||||
@@ -56,7 +56,9 @@
|
||||
"downshift": "8.4.0",
|
||||
"react": "18.2.0",
|
||||
"react-aria": "3.32.1",
|
||||
"react-dom": "18.2.0"
|
||||
"react-aria-components": "1.1.1",
|
||||
"react-dom": "18.2.0",
|
||||
"react-stately": "3.30.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
|
||||
91
packages/react/src/components/Tooltip/_index.scss
Normal file
91
packages/react/src/components/Tooltip/_index.scss
Normal file
@@ -0,0 +1,91 @@
|
||||
.c__tooltip {
|
||||
border-radius: var(--c--components--tooltip--border-radius);
|
||||
background: var(--c--components--tooltip--background-color);
|
||||
color: var(--c--components--tooltip--color);
|
||||
font-size: var(--c--components--tooltip--font-size);
|
||||
forced-color-adjust: none;
|
||||
outline: none;
|
||||
padding: var(--c--components--tooltip--padding);
|
||||
max-width: var(--c--components--tooltip--max-width);
|
||||
display: flex;
|
||||
/* fixes FF gap */
|
||||
transform: translate3d(0, 0, 0);
|
||||
--animation-duration: 200ms;
|
||||
|
||||
&[data-placement=top] {
|
||||
margin-bottom: 8px;
|
||||
--origin: translateY(4px);
|
||||
|
||||
.react-aria-OverlayArrow {
|
||||
left: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
&[data-placement=bottom] {
|
||||
margin-top: 8px;
|
||||
--origin: translateY(-4px);
|
||||
|
||||
.react-aria-OverlayArrow {
|
||||
left: 50%;
|
||||
|
||||
svg {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&[data-placement=right] {
|
||||
margin-left: 8px;
|
||||
--origin: translateX(-4px);
|
||||
|
||||
.react-aria-OverlayArrow {
|
||||
top: 50%;
|
||||
|
||||
svg {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&[data-placement=left] {
|
||||
margin-right: 8px;
|
||||
--origin: translateX(4px);
|
||||
|
||||
.react-aria-OverlayArrow {
|
||||
top: 50%;
|
||||
|
||||
svg {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& .react-aria-OverlayArrow svg {
|
||||
display: block;
|
||||
fill: var(--c--components--tooltip--background-color);
|
||||
}
|
||||
|
||||
&--entering {
|
||||
animation: slide var(--animation-duration);
|
||||
}
|
||||
|
||||
&--exiting {
|
||||
animation: slide var(--animation-duration) reverse forwards;
|
||||
}
|
||||
|
||||
&__content {
|
||||
overflow: scroll;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide {
|
||||
from {
|
||||
transform: var(--origin);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
58
packages/react/src/components/Tooltip/index.mdx
Normal file
58
packages/react/src/components/Tooltip/index.mdx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { Canvas, Meta, Story, Source, ArgTypes } from '@storybook/blocks';
|
||||
import * as Stories from './index.stories';
|
||||
import { Tooltip } from './index';
|
||||
|
||||
<Meta of={Stories}/>
|
||||
|
||||
# Tooltip
|
||||
|
||||
Cunningham provides a tooltip component for displaying any kind of additional information.
|
||||
|
||||
<Canvas sourceState="shown" of={Stories.Default}/>
|
||||
|
||||
|
||||
## Content
|
||||
|
||||
The content of the tooltip can either be a string or any React Element.
|
||||
|
||||
### Plain text
|
||||
|
||||
<Canvas sourceState="shown" of={Stories.OverflowingText}/>
|
||||
|
||||
### HTML
|
||||
|
||||
<Canvas sourceState="shown" of={Stories.WithHtml}/>
|
||||
|
||||
## Trigger element
|
||||
|
||||
As you can see in the examples above, the tooltip can be triggered by any kind of element which
|
||||
must be passed as children to the `Tooltip` component.
|
||||
|
||||
Here is a more complex example with a more advanced component
|
||||
|
||||
<Canvas sourceState="hidden" of={Stories.WithElements}/>
|
||||
|
||||
## Placement
|
||||
|
||||
The tooltip can be placed in different positions relative to the trigger element using `placement` props. The available positions are: `top`, `right`, `bottom`, `left`.
|
||||
|
||||
<Canvas sourceState="hidden" of={Stories.Placements}/>
|
||||
|
||||
## Props
|
||||
|
||||
These are the props of `Tooltip`.
|
||||
|
||||
<ArgTypes of={Tooltip} />
|
||||
|
||||
## Design tokens
|
||||
|
||||
Here a the custom design tokens defined by the Tooltip.
|
||||
|
||||
| Token | Description |
|
||||
|--------------- |----------------------------- |
|
||||
| border-radius | Border radius of the tooltip |
|
||||
| background-color | Background color of the tooltip |
|
||||
| color | Text color of the tooltip |
|
||||
| font-size | Font size of the tooltip content |
|
||||
| padding | Padding of the tooltip content |
|
||||
| max-width | Max width of the tooltip |
|
||||
149
packages/react/src/components/Tooltip/index.spec.tsx
Normal file
149
packages/react/src/components/Tooltip/index.spec.tsx
Normal file
@@ -0,0 +1,149 @@
|
||||
import {
|
||||
render,
|
||||
screen,
|
||||
waitFor,
|
||||
waitForElementToBeRemoved,
|
||||
} from "@testing-library/react";
|
||||
import React from "react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { fireEvent } from "@testing-library/dom";
|
||||
import { Tooltip } from ":/components/Tooltip/index";
|
||||
import { Button } from ":/components/Button";
|
||||
|
||||
describe("<Tooltip />", () => {
|
||||
it("appear on button hover and then disappear", async () => {
|
||||
render(
|
||||
<Tooltip content="Hi there" closeDelay={0}>
|
||||
<Button size="nano" color="tertiary-text">
|
||||
⬅️
|
||||
</Button>
|
||||
</Tooltip>,
|
||||
);
|
||||
|
||||
const button = screen.getByRole("button");
|
||||
expect(screen.queryByText("Hi there")).not.toBeInTheDocument();
|
||||
const user = userEvent.setup();
|
||||
fireEvent.mouseMove(document.body);
|
||||
await user.hover(button);
|
||||
expect(await screen.findByText("Hi there")).toBeInTheDocument();
|
||||
|
||||
await user.unhover(button);
|
||||
await waitForElementToBeRemoved(screen.queryByText("Hi there"));
|
||||
});
|
||||
it("appear on button focus and then disappear", async () => {
|
||||
render(
|
||||
<Tooltip content="Hi there" closeDelay={0}>
|
||||
<Button size="nano" color="tertiary-text">
|
||||
⬅️
|
||||
</Button>
|
||||
</Tooltip>,
|
||||
);
|
||||
|
||||
expect(screen.queryByText("Hi there")).not.toBeInTheDocument();
|
||||
const user = userEvent.setup();
|
||||
|
||||
await user.tab();
|
||||
expect(await screen.findByText("Hi there")).toBeInTheDocument();
|
||||
|
||||
await user.tab();
|
||||
await waitForElementToBeRemoved(screen.queryByText("Hi there"));
|
||||
});
|
||||
it("sets entering and exiting class", async () => {
|
||||
render(
|
||||
<Tooltip content="Hi there" closeDelay={0}>
|
||||
<Button size="nano" color="tertiary-text">
|
||||
⬅️
|
||||
</Button>
|
||||
</Tooltip>,
|
||||
);
|
||||
|
||||
expect(screen.queryByText("Hi there")).not.toBeInTheDocument();
|
||||
const user = userEvent.setup();
|
||||
|
||||
const button = screen.getByRole("button");
|
||||
|
||||
fireEvent.mouseMove(document.body);
|
||||
await user.hover(button);
|
||||
|
||||
// Make sure the tooltip is entering.
|
||||
await waitFor(() => {
|
||||
const tooltip = document.querySelector(".c__tooltip");
|
||||
expect(tooltip).toHaveClass("c__tooltip--entering");
|
||||
expect(tooltip).not.toHaveClass("c__tooltip--exiting");
|
||||
});
|
||||
|
||||
// Make sure the entering class is removed and the exiting class is not added yet.
|
||||
await waitFor(() => {
|
||||
const tooltip = document.querySelector(".c__tooltip");
|
||||
expect(tooltip).not.toHaveClass("c__tooltip--entering");
|
||||
expect(tooltip).not.toHaveClass("c__tooltip--exiting");
|
||||
});
|
||||
|
||||
await user.unhover(button);
|
||||
|
||||
// Make sure the tooltip is exiting.
|
||||
await waitFor(() => {
|
||||
const tooltip = document.querySelector(".c__tooltip");
|
||||
expect(tooltip).not.toHaveClass("c__tooltip--entering");
|
||||
expect(tooltip).toHaveClass("c__tooltip--exiting");
|
||||
});
|
||||
|
||||
// Make sure the tooltip is removed.
|
||||
await waitForElementToBeRemoved(document.querySelector(".c__tooltip"));
|
||||
});
|
||||
it("works with HTML", async () => {
|
||||
render(
|
||||
<Tooltip
|
||||
content={
|
||||
<>
|
||||
<h1>Title</h1>
|
||||
<p>Description</p>
|
||||
</>
|
||||
}
|
||||
closeDelay={0}
|
||||
>
|
||||
<Button size="nano" color="tertiary-text">
|
||||
⬅️
|
||||
</Button>
|
||||
</Tooltip>,
|
||||
);
|
||||
|
||||
const button = screen.getByRole("button");
|
||||
expect(screen.queryByText("Hi there")).not.toBeInTheDocument();
|
||||
const user = userEvent.setup();
|
||||
fireEvent.mouseMove(document.body);
|
||||
await user.hover(button);
|
||||
await screen.findByRole("heading", { name: "Title" });
|
||||
await screen.findByText("Description");
|
||||
});
|
||||
it("renders with className", async () => {
|
||||
render(
|
||||
<Tooltip
|
||||
content={
|
||||
<>
|
||||
<h1>Title</h1>
|
||||
<p>Description</p>
|
||||
</>
|
||||
}
|
||||
closeDelay={0}
|
||||
className="my-custom-class"
|
||||
>
|
||||
<Button size="nano" color="tertiary-text">
|
||||
⬅️
|
||||
</Button>
|
||||
</Tooltip>,
|
||||
);
|
||||
|
||||
const button = screen.getByRole("button");
|
||||
expect(screen.queryByText("Hi there")).not.toBeInTheDocument();
|
||||
|
||||
const user = userEvent.setup();
|
||||
fireEvent.mouseMove(document.body);
|
||||
await user.hover(button);
|
||||
|
||||
await waitFor(() => {
|
||||
const tooltip = document.querySelector(".c__tooltip");
|
||||
expect(tooltip).toHaveClass("my-custom-class");
|
||||
});
|
||||
});
|
||||
});
|
||||
147
packages/react/src/components/Tooltip/index.stories.tsx
Normal file
147
packages/react/src/components/Tooltip/index.stories.tsx
Normal file
@@ -0,0 +1,147 @@
|
||||
import React from "react";
|
||||
import { Meta } from "@storybook/react";
|
||||
import { Tooltip } from ":/components/Tooltip";
|
||||
import { Button } from ":/components/Button";
|
||||
|
||||
export default {
|
||||
title: "Components/Tooltip",
|
||||
component: Tooltip,
|
||||
decorators: [
|
||||
(Story) => {
|
||||
return (
|
||||
<div style={{ padding: "8rem", position: "relative" }}>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "4rem" }}>
|
||||
<Story />
|
||||
<div>⬅️ Hover it</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
],
|
||||
} as Meta<typeof Tooltip>;
|
||||
|
||||
export const Default = {
|
||||
args: {
|
||||
children: (
|
||||
<Button
|
||||
size="small"
|
||||
icon={<span className="material-icons">info</span>}
|
||||
color="tertiary-text"
|
||||
/>
|
||||
),
|
||||
content:
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
},
|
||||
};
|
||||
|
||||
export const Placements = {
|
||||
render: () => {
|
||||
return (
|
||||
<div>
|
||||
<Tooltip placement="left" content="Hi there">
|
||||
<Button size="nano" color="tertiary-text">
|
||||
⬅️
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip placement="bottom" content="Hi there">
|
||||
<Button size="nano" color="tertiary-text">
|
||||
⬇️
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip placement="top" content="Hi there">
|
||||
<Button size="nano" color="tertiary-text">
|
||||
⬆️
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip placement="right" content="Hi there">
|
||||
<Button size="nano" color="tertiary-text">
|
||||
➡️
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
const lorem =
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sit amet quam sed nunc commodo consequat. Vestibulum cursus venenatis massa et tempor.";
|
||||
export const OverflowingText = {
|
||||
args: {
|
||||
children: (
|
||||
<p
|
||||
style={{
|
||||
width: "100px",
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
}}
|
||||
>
|
||||
{lorem}
|
||||
</p>
|
||||
),
|
||||
content: lorem,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithElements = {
|
||||
args: {
|
||||
content: lorem,
|
||||
placement: "bottom",
|
||||
children: (
|
||||
<div
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "8px",
|
||||
backgroundColor: "var(--c--theme--colors--greyscale-300)",
|
||||
padding: "1rem",
|
||||
display: "flex",
|
||||
gap: "1rem",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: "32px",
|
||||
height: "32px",
|
||||
borderRadius: "100%",
|
||||
backgroundColor: "var(--c--theme--colors--greyscale-600)",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
width: "150px",
|
||||
height: "32px",
|
||||
borderRadius: "4px",
|
||||
backgroundColor: "var(--c--theme--colors--greyscale-400)",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
export const WithHtml = {
|
||||
args: {
|
||||
children: (
|
||||
<Button
|
||||
size="small"
|
||||
icon={<span className="material-icons">info</span>}
|
||||
color="tertiary-text"
|
||||
/>
|
||||
),
|
||||
placement: "right",
|
||||
content: (
|
||||
<div>
|
||||
<h3>Heading</h3>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
</p>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
};
|
||||
109
packages/react/src/components/Tooltip/index.tsx
Normal file
109
packages/react/src/components/Tooltip/index.tsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import React, { PropsWithChildren, ReactElement, ReactNode } from "react";
|
||||
import { OverlayArrow } from "react-aria-components";
|
||||
import {
|
||||
mergeProps,
|
||||
useOverlayPosition,
|
||||
useTooltip,
|
||||
useTooltipTrigger,
|
||||
} from "react-aria";
|
||||
import { useTooltipTriggerState } from "react-stately";
|
||||
import classNames from "classnames";
|
||||
|
||||
const ANIMATION_DURATION = 200;
|
||||
|
||||
export interface TooltipProps extends PropsWithChildren {
|
||||
placement?: "top" | "bottom" | "left" | "right";
|
||||
content: ReactNode;
|
||||
closeDelay?: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const Tooltip = ({
|
||||
placement = "bottom",
|
||||
content,
|
||||
closeDelay = 150,
|
||||
className,
|
||||
...props
|
||||
}: TooltipProps) => {
|
||||
const ref = React.useRef(null);
|
||||
const overlayRef = React.useRef(null);
|
||||
const [isExiting, setIsExiting] = React.useState(false);
|
||||
const [isEntering, setIsEntering] = React.useState(false);
|
||||
const state = useTooltipTriggerState({
|
||||
delay: 0,
|
||||
closeDelay,
|
||||
onOpenChange: (isOpen) => {
|
||||
if (isOpen) {
|
||||
setIsEntering(true);
|
||||
setTimeout(() => {
|
||||
setIsEntering(false);
|
||||
}, ANIMATION_DURATION);
|
||||
} else {
|
||||
setIsExiting(true);
|
||||
setTimeout(() => {
|
||||
setIsExiting(false);
|
||||
}, ANIMATION_DURATION);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Get props for the trigger and its tooltip
|
||||
const useTooltipTriggerRes = useTooltipTrigger({}, state, ref);
|
||||
|
||||
// overlayPosition.placement can be difference than placement, based on available screen space.
|
||||
const overlayPosition = useOverlayPosition({
|
||||
targetRef: ref,
|
||||
overlayRef,
|
||||
placement,
|
||||
isOpen: state.isOpen,
|
||||
});
|
||||
|
||||
const { tooltipProps: tooltipProps2 } = useTooltip(
|
||||
useTooltipTriggerRes.tooltipProps,
|
||||
state,
|
||||
);
|
||||
|
||||
const arrowProps = {
|
||||
placement: overlayPosition.placement,
|
||||
};
|
||||
|
||||
const showTooltip = state.isOpen || isExiting;
|
||||
|
||||
return (
|
||||
<>
|
||||
{React.cloneElement(
|
||||
React.Children.toArray(props.children)[0] as ReactElement,
|
||||
{
|
||||
ref,
|
||||
...useTooltipTriggerRes.triggerProps,
|
||||
},
|
||||
)}
|
||||
|
||||
{showTooltip && (
|
||||
<span
|
||||
className={classNames(
|
||||
"c__tooltip",
|
||||
{
|
||||
"c__tooltip--exiting": isExiting,
|
||||
"c__tooltip--entering": isEntering,
|
||||
},
|
||||
className,
|
||||
)}
|
||||
data-placement={overlayPosition.placement}
|
||||
ref={overlayRef}
|
||||
style={{
|
||||
...overlayPosition.overlayProps.style,
|
||||
}}
|
||||
{...mergeProps(props, tooltipProps2)}
|
||||
>
|
||||
<OverlayArrow {...arrowProps}>
|
||||
<svg width={16} height={16} viewBox="0 0 16 16">
|
||||
<path d="M0 0 L8 8 L16 0" />
|
||||
</svg>
|
||||
</OverlayArrow>
|
||||
<span className="c__tooltip__content">{content}</span>
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
12
packages/react/src/components/Tooltip/tokens.ts
Normal file
12
packages/react/src/components/Tooltip/tokens.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { DefaultTokens } from "@openfun/cunningham-tokens";
|
||||
|
||||
export const tokens = (defaults: DefaultTokens) => {
|
||||
return {
|
||||
"border-radius": "0.5rem",
|
||||
"background-color": defaults.theme.colors["greyscale-900"],
|
||||
color: defaults.theme.colors["greyscale-000"],
|
||||
"font-size": defaults.theme.font.sizes.s,
|
||||
padding: "1rem",
|
||||
"max-width": "150px",
|
||||
};
|
||||
};
|
||||
@@ -112,6 +112,12 @@
|
||||
--c--theme--breakpoints--lg: 992px;
|
||||
--c--theme--breakpoints--xl: 1200px;
|
||||
--c--theme--breakpoints--xxl: 1400px;
|
||||
--c--components--tooltip--border-radius: 0.5rem;
|
||||
--c--components--tooltip--background-color: var(--c--theme--colors--greyscale-900);
|
||||
--c--components--tooltip--color: var(--c--theme--colors--greyscale-000);
|
||||
--c--components--tooltip--font-size: var(--c--theme--font--sizes--s);
|
||||
--c--components--tooltip--padding: 1rem;
|
||||
--c--components--tooltip--max-width: 150px;
|
||||
--c--components--toast--slide-in-duration: 1000ms;
|
||||
--c--components--toast--slide-out-duration: 300ms;
|
||||
--c--components--toast--background-color: var(--c--theme--colors--greyscale-100);
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -134,6 +134,14 @@ $themes: (
|
||||
)
|
||||
),
|
||||
'components': (
|
||||
'tooltip': (
|
||||
'border-radius': 0.5rem,
|
||||
'background-color': #0C1A2B,
|
||||
'color': #FFFFFF,
|
||||
'font-size': 0.6875rem,
|
||||
'padding': 1rem,
|
||||
'max-width': 150px
|
||||
),
|
||||
'toast': (
|
||||
'slide-in-duration': 1000ms,
|
||||
'slide-out-duration': 300ms,
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -23,6 +23,7 @@
|
||||
@use "./components/Pagination";
|
||||
@use "./components/Popover";
|
||||
@use "./components/Toast";
|
||||
@use "./components/Tooltip";
|
||||
|
||||
body {
|
||||
font-family: var(--c--theme--font--families--base);
|
||||
|
||||
@@ -27,6 +27,7 @@ export * from "./components/Popover";
|
||||
export * from "./components/Provider";
|
||||
export * from "./components/Toast";
|
||||
export * from "./components/Toast/ToastProvider";
|
||||
export * from "./components/Tooltip";
|
||||
export * from "./utils/VariantUtils";
|
||||
|
||||
export type DefaultTokens = PartialNested<typeof tokens.themes.default>;
|
||||
|
||||
92
yarn.lock
92
yarn.lock
@@ -3982,6 +3982,17 @@
|
||||
"@react-types/checkbox" "^3.7.1"
|
||||
"@swc/helpers" "^0.5.0"
|
||||
|
||||
"@react-aria/toolbar@3.0.0-beta.3":
|
||||
version "3.0.0-beta.3"
|
||||
resolved "https://registry.yarnpkg.com/@react-aria/toolbar/-/toolbar-3.0.0-beta.3.tgz#7b4a0e1da137cb84a65b38e0a4802984759e3d9f"
|
||||
integrity sha512-tPIEPRsZI/6Mb0tAW/GBTt3wBk7dfJg/eUnTloY8NHialvDa+cMUQyUVzPyLWGpErhYeBeutBmw1e2seMjmu+A==
|
||||
dependencies:
|
||||
"@react-aria/focus" "^3.16.2"
|
||||
"@react-aria/i18n" "^3.10.2"
|
||||
"@react-aria/utils" "^3.23.2"
|
||||
"@react-types/shared" "^3.22.1"
|
||||
"@swc/helpers" "^0.5.0"
|
||||
|
||||
"@react-aria/tooltip@^3.7.2":
|
||||
version "3.7.2"
|
||||
resolved "https://registry.yarnpkg.com/@react-aria/tooltip/-/tooltip-3.7.2.tgz#ccbcef4efcb27486cd845a734794d541696e3692"
|
||||
@@ -4061,6 +4072,14 @@
|
||||
"@react-types/shared" "^3.22.1"
|
||||
"@swc/helpers" "^0.5.0"
|
||||
|
||||
"@react-stately/data@^3.11.2":
|
||||
version "3.11.2"
|
||||
resolved "https://registry.yarnpkg.com/@react-stately/data/-/data-3.11.2.tgz#835c9a90eaeb832dbaac4c96f1aa91008913efb8"
|
||||
integrity sha512-yhK2upk2WbJeiLBRWHrh/4G2CvmmozCzoivLaRAPYu53m1J3MyzVGCLJgnZMbMZvAbNcYWZK6IzO6VqZ2y1fOw==
|
||||
dependencies:
|
||||
"@react-types/shared" "^3.22.1"
|
||||
"@swc/helpers" "^0.5.0"
|
||||
|
||||
"@react-stately/datepicker@3.9.2", "@react-stately/datepicker@^3.9.2":
|
||||
version "3.9.2"
|
||||
resolved "https://registry.yarnpkg.com/@react-stately/datepicker/-/datepicker-3.9.2.tgz#a160d174c4c5a67b15e70a893071d948f5ad347d"
|
||||
@@ -4328,6 +4347,13 @@
|
||||
"@react-types/overlays" "^3.8.5"
|
||||
"@react-types/shared" "^3.22.1"
|
||||
|
||||
"@react-types/form@^3.7.2":
|
||||
version "3.7.2"
|
||||
resolved "https://registry.yarnpkg.com/@react-types/form/-/form-3.7.2.tgz#bfa8aef2f6e1ee579ab2f9a1f40556ae24f72d32"
|
||||
integrity sha512-6/isEJY4PsYoHdMaGQtqQyquXGTwB1FqCBOPKQjI/vBGWG3fL7FGfWm4Z62eTbCH4Xyv3FZuNywlT8UjPMQyKA==
|
||||
dependencies:
|
||||
"@react-types/shared" "^3.22.1"
|
||||
|
||||
"@react-types/grid@^3.2.4":
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@react-types/grid/-/grid-3.2.4.tgz#47b28424409b66b3bfcfcde03c92f03d6d41d1ba"
|
||||
@@ -7203,6 +7229,11 @@ cli-table3@^0.6.1:
|
||||
optionalDependencies:
|
||||
"@colors/colors" "1.5.0"
|
||||
|
||||
client-only@^0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1"
|
||||
integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==
|
||||
|
||||
cliui@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1"
|
||||
@@ -13067,7 +13098,32 @@ raw-body@2.5.1:
|
||||
iconv-lite "0.4.24"
|
||||
unpipe "1.0.0"
|
||||
|
||||
react-aria@3.32.1:
|
||||
react-aria-components@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-aria-components/-/react-aria-components-1.1.1.tgz#85e47d9321af878f9e7a183c943d7c222ab0c370"
|
||||
integrity sha512-XdgqSbrlh9V1vJEvTwrnr+YGndQWYcVEAbN+Rx104o9g88cAAabclgetU2OUJ9Gbht6+gwnvnA0ksgXzVZog2Q==
|
||||
dependencies:
|
||||
"@internationalized/date" "^3.5.2"
|
||||
"@internationalized/string" "^3.2.1"
|
||||
"@react-aria/focus" "^3.16.2"
|
||||
"@react-aria/interactions" "^3.21.1"
|
||||
"@react-aria/menu" "^3.13.1"
|
||||
"@react-aria/toolbar" "3.0.0-beta.3"
|
||||
"@react-aria/utils" "^3.23.2"
|
||||
"@react-stately/menu" "^3.6.1"
|
||||
"@react-stately/table" "^3.11.6"
|
||||
"@react-stately/utils" "^3.9.1"
|
||||
"@react-types/form" "^3.7.2"
|
||||
"@react-types/grid" "^3.2.4"
|
||||
"@react-types/shared" "^3.22.1"
|
||||
"@react-types/table" "^3.9.3"
|
||||
"@swc/helpers" "^0.5.0"
|
||||
client-only "^0.0.1"
|
||||
react-aria "^3.32.1"
|
||||
react-stately "^3.30.1"
|
||||
use-sync-external-store "^1.2.0"
|
||||
|
||||
react-aria@3.32.1, react-aria@^3.32.1:
|
||||
version "3.32.1"
|
||||
resolved "https://registry.yarnpkg.com/react-aria/-/react-aria-3.32.1.tgz#e490259969b8cfbcc0fdb9cd3e041b1769b285d4"
|
||||
integrity sha512-7KCJg4K5vlRqiXdGjgCT05Du8RhGBYC+2ok4GOh/Znmg8aMwOk7t0YwxaT5i1z30+fmDcJS/pk/ipUPUg28CXg==
|
||||
@@ -13202,6 +13258,35 @@ react-remove-scroll@2.5.5:
|
||||
use-callback-ref "^1.3.0"
|
||||
use-sidecar "^1.1.2"
|
||||
|
||||
react-stately@3.30.1, react-stately@^3.30.1:
|
||||
version "3.30.1"
|
||||
resolved "https://registry.yarnpkg.com/react-stately/-/react-stately-3.30.1.tgz#7d87649c69f1bcf42c68a732f121ff23393f5abb"
|
||||
integrity sha512-IEhKHMT7wijtczA5vtw/kdq9CZuOIF+ReoSimydTFiABRQxWO9ESAl/fToXOUM9qmCdhdqjGJgMAhqTnmheh8g==
|
||||
dependencies:
|
||||
"@react-stately/calendar" "^3.4.4"
|
||||
"@react-stately/checkbox" "^3.6.3"
|
||||
"@react-stately/collections" "^3.10.5"
|
||||
"@react-stately/combobox" "^3.8.2"
|
||||
"@react-stately/data" "^3.11.2"
|
||||
"@react-stately/datepicker" "^3.9.2"
|
||||
"@react-stately/dnd" "^3.2.8"
|
||||
"@react-stately/form" "^3.0.1"
|
||||
"@react-stately/list" "^3.10.3"
|
||||
"@react-stately/menu" "^3.6.1"
|
||||
"@react-stately/numberfield" "^3.9.1"
|
||||
"@react-stately/overlays" "^3.6.5"
|
||||
"@react-stately/radio" "^3.10.2"
|
||||
"@react-stately/searchfield" "^3.5.1"
|
||||
"@react-stately/select" "^3.6.2"
|
||||
"@react-stately/selection" "^3.14.3"
|
||||
"@react-stately/slider" "^3.5.2"
|
||||
"@react-stately/table" "^3.11.6"
|
||||
"@react-stately/tabs" "^3.6.4"
|
||||
"@react-stately/toggle" "^3.7.2"
|
||||
"@react-stately/tooltip" "^3.4.7"
|
||||
"@react-stately/tree" "^3.7.6"
|
||||
"@react-types/shared" "^3.22.1"
|
||||
|
||||
react-style-singleton@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.1.tgz#f99e420492b2d8f34d38308ff660b60d0b1205b4"
|
||||
@@ -15136,6 +15221,11 @@ use-sidecar@^1.1.2:
|
||||
detect-node-es "^1.1.0"
|
||||
tslib "^2.0.0"
|
||||
|
||||
use-sync-external-store@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
|
||||
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
|
||||
|
||||
util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
|
||||
Reference in New Issue
Block a user