mirror of
https://github.com/outline/outline.git
synced 2026-08-03 13:27:25 +03:00
feat: Adds user profile cards on hover (#13230)
* wip * Add option to suppress hover card
This commit is contained in:
@@ -28,9 +28,9 @@ export interface IAvatar {
|
||||
id?: string;
|
||||
}
|
||||
|
||||
type Props = {
|
||||
export type AvatarProps = {
|
||||
/** The size of the avatar */
|
||||
size: AvatarSize;
|
||||
size?: AvatarSize;
|
||||
/** The variant of the avatar */
|
||||
variant?: AvatarVariant;
|
||||
/** The source of the avatar image, if not passing a model. */
|
||||
@@ -40,58 +40,78 @@ type Props = {
|
||||
/** The alt text for the image */
|
||||
alt?: string;
|
||||
/** Optional click handler */
|
||||
onClick?: React.MouseEventHandler<HTMLImageElement>;
|
||||
onClick?: React.MouseEventHandler<HTMLElement>;
|
||||
/** Optional class name */
|
||||
className?: string;
|
||||
/** Optional style */
|
||||
style?: React.CSSProperties;
|
||||
/** Whether to show a tooltip */
|
||||
showTooltip?: boolean;
|
||||
};
|
||||
/** Whether to show a profile card on hover for users, defaults to true */
|
||||
showHoverCard?: boolean;
|
||||
} & Omit<
|
||||
React.ComponentPropsWithoutRef<"div">,
|
||||
"onClick" | "className" | "style"
|
||||
>;
|
||||
|
||||
function Avatar(props: Props) {
|
||||
const Avatar = React.forwardRef(function Avatar_(
|
||||
props: AvatarProps,
|
||||
ref: React.Ref<HTMLDivElement>
|
||||
) {
|
||||
const {
|
||||
model,
|
||||
style,
|
||||
variant = AvatarVariant.Round,
|
||||
size = AvatarSize.Medium,
|
||||
className,
|
||||
showTooltip,
|
||||
showHoverCard: _showHoverCard,
|
||||
src: srcProp,
|
||||
alt,
|
||||
onClick,
|
||||
...rest
|
||||
} = props;
|
||||
const src = props.src || model?.avatarUrl;
|
||||
const src = srcProp || model?.avatarUrl;
|
||||
const [error, handleError] = useBoolean(false);
|
||||
const initial =
|
||||
model?.initial || (model?.name ? model.name[0] : "").toUpperCase();
|
||||
|
||||
const content = (
|
||||
<Relative
|
||||
ref={ref}
|
||||
style={style}
|
||||
$variant={variant}
|
||||
$size={props.size}
|
||||
$size={size}
|
||||
className={className}
|
||||
{...rest}
|
||||
>
|
||||
{src && !error ? (
|
||||
<Image onError={handleError} src={src} {...rest} />
|
||||
) : model ? (
|
||||
<Initials color={model.color} {...rest}>
|
||||
{initial}
|
||||
</Initials>
|
||||
<Image
|
||||
onError={handleError}
|
||||
onClick={onClick}
|
||||
src={src}
|
||||
alt={alt}
|
||||
size={size}
|
||||
/>
|
||||
) : (
|
||||
<Initials {...rest} />
|
||||
<Initials
|
||||
color={model?.color}
|
||||
onClick={onClick}
|
||||
aria-label={alt}
|
||||
size={size}
|
||||
>
|
||||
{model ? initial : null}
|
||||
</Initials>
|
||||
)}
|
||||
</Relative>
|
||||
);
|
||||
|
||||
return showTooltip ? (
|
||||
<Tooltip content={props.alt || model?.name || ""}>{content}</Tooltip>
|
||||
<Tooltip content={alt || model?.name || ""}>{content}</Tooltip>
|
||||
) : (
|
||||
content
|
||||
);
|
||||
}
|
||||
|
||||
Avatar.defaultProps = {
|
||||
size: AvatarSize.Medium,
|
||||
};
|
||||
});
|
||||
|
||||
const Relative = styled.div<{ $variant: AvatarVariant; $size: AvatarSize }>`
|
||||
position: relative;
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { observer } from "mobx-react";
|
||||
import * as React from "react";
|
||||
import { UserHoverCard } from "~/components/UserHoverCard";
|
||||
import User from "~/models/User";
|
||||
import type { AvatarProps } from "./Avatar";
|
||||
import Avatar from "./Avatar";
|
||||
|
||||
/**
|
||||
* An avatar that additionally displays a profile card on hover when the model
|
||||
* it represents is a user.
|
||||
*/
|
||||
const AvatarWithHoverCard = React.forwardRef(function AvatarWithHoverCard_(
|
||||
{ showTooltip, showHoverCard = true, ...props }: AvatarProps,
|
||||
ref: React.Ref<HTMLDivElement>
|
||||
) {
|
||||
const { model } = props;
|
||||
|
||||
if (!showHoverCard || !(model instanceof User)) {
|
||||
return <Avatar ref={ref} showTooltip={showTooltip} {...props} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<UserHoverCard user={model}>
|
||||
<Avatar ref={ref} {...props} />
|
||||
</UserHoverCard>
|
||||
);
|
||||
});
|
||||
|
||||
export default observer(AvatarWithHoverCard);
|
||||
@@ -1,10 +1,12 @@
|
||||
import { observer } from "mobx-react";
|
||||
import { EditIcon, EyeIcon } from "outline-icons";
|
||||
import * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import styled, { css } from "styled-components";
|
||||
import { s } from "@shared/styles";
|
||||
import type User from "~/models/User";
|
||||
import User from "~/models/User";
|
||||
import Tooltip from "~/components/Tooltip";
|
||||
import { UserHoverCard } from "~/components/UserHoverCard";
|
||||
import Avatar, { AvatarSize } from "./Avatar";
|
||||
|
||||
/**
|
||||
@@ -41,7 +43,7 @@ type Props = {
|
||||
* - Observing users have a colored border matching their user color
|
||||
* - Hovering shows a colored border
|
||||
*
|
||||
* A tooltip displays the user's name and current status.
|
||||
* A profile card on hover displays the user's name and current status.
|
||||
*
|
||||
* @param props - Component properties
|
||||
* @returns React component
|
||||
@@ -58,28 +60,14 @@ function AvatarWithPresence({
|
||||
alt,
|
||||
}: Props) {
|
||||
const { t } = useTranslation();
|
||||
const { name } = user;
|
||||
const status = isPresent
|
||||
? isEditing
|
||||
? t("currently editing")
|
||||
: t("currently viewing")
|
||||
: t("previously edited");
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tooltip
|
||||
content={
|
||||
<Centered>
|
||||
<strong>{user.name}</strong> {isCurrentUser && `(${t("You")})`}
|
||||
{status && (
|
||||
<>
|
||||
<br />
|
||||
{status}
|
||||
</>
|
||||
)}
|
||||
</Centered>
|
||||
}
|
||||
placement="bottom"
|
||||
>
|
||||
const avatar = (
|
||||
<AvatarPresence
|
||||
$isPresent={isPresent}
|
||||
$isObserving={isObserving}
|
||||
@@ -88,14 +76,41 @@ function AvatarWithPresence({
|
||||
>
|
||||
<Avatar model={user} onClick={onClick} size={size} alt={alt} />
|
||||
</AvatarPresence>
|
||||
);
|
||||
|
||||
// The facepile overflow badge is rendered with a placeholder in place of a
|
||||
// real user, there's no profile to show for it.
|
||||
if (!(user instanceof User)) {
|
||||
return (
|
||||
<Tooltip content={<Centered>{name}</Centered>} placement="bottom">
|
||||
{avatar}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<UserHoverCard
|
||||
user={user}
|
||||
side="bottom"
|
||||
info={
|
||||
<>
|
||||
{isPresent && !isEditing ? (
|
||||
<EyeIcon size={18} />
|
||||
) : (
|
||||
<EditIcon size={18} />
|
||||
)}
|
||||
<span>
|
||||
{status}
|
||||
{isCurrentUser && ` (${t("You")})`}
|
||||
</span>
|
||||
</>
|
||||
}
|
||||
>
|
||||
{avatar}
|
||||
</UserHoverCard>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Centered container for tooltip content
|
||||
*/
|
||||
const Centered = styled.div`
|
||||
text-align: center;
|
||||
`;
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
import type { IAvatar } from "./Avatar";
|
||||
import Avatar, { AvatarSize, AvatarVariant } from "./Avatar";
|
||||
import type { AvatarProps, IAvatar } from "./Avatar";
|
||||
import { AvatarSize, AvatarVariant } from "./Avatar";
|
||||
import AvatarWithHoverCard from "./AvatarWithHoverCard";
|
||||
import AvatarWithPresence from "./AvatarWithPresence";
|
||||
import { GroupAvatar } from "./GroupAvatar";
|
||||
|
||||
/**
|
||||
* The default avatar, which shows a profile card on hover for users.
|
||||
*/
|
||||
const Avatar = AvatarWithHoverCard;
|
||||
|
||||
export { Avatar, GroupAvatar, AvatarSize, AvatarVariant, AvatarWithPresence };
|
||||
|
||||
export type { IAvatar };
|
||||
export type { AvatarProps, IAvatar };
|
||||
|
||||
+15
-9
@@ -1,22 +1,28 @@
|
||||
import { transparentize } from "polished";
|
||||
import { darken, transparentize } from "polished";
|
||||
import styled from "styled-components";
|
||||
|
||||
const Badge = styled.span<{ yellow?: boolean; primary?: boolean }>`
|
||||
padding: 1.5px 5.5px;
|
||||
margin: 0 2px;
|
||||
background-color: ${({ yellow, primary, theme }) =>
|
||||
yellow ? theme.yellow : primary ? theme.accent : "transparent"};
|
||||
background: ${({ yellow, primary, theme }) =>
|
||||
yellow
|
||||
? transparentize(0.85, theme.yellow)
|
||||
: primary
|
||||
? transparentize(0.85, theme.accent)
|
||||
: "transparent"};
|
||||
color: ${({ primary, yellow, theme }) =>
|
||||
primary
|
||||
? theme.accentText
|
||||
? theme.accent
|
||||
: yellow
|
||||
? theme.almostBlack
|
||||
? darken(0.1, theme.yellow)
|
||||
: theme.textTertiary};
|
||||
border: 1px solid
|
||||
${({ primary, yellow, theme }) =>
|
||||
primary || yellow
|
||||
? "transparent"
|
||||
: transparentize(0.4, theme.textTertiary)};
|
||||
${({ yellow, primary, theme }) =>
|
||||
yellow
|
||||
? transparentize(0.25, theme.yellow)
|
||||
: primary
|
||||
? transparentize(0.25, theme.accent)
|
||||
: theme.textTertiary};
|
||||
border-radius: 8px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
|
||||
@@ -3,6 +3,7 @@ import * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import styled from "styled-components";
|
||||
import type User from "~/models/User";
|
||||
import type { AvatarProps } from "~/components/Avatar";
|
||||
import { Avatar, AvatarSize } from "~/components/Avatar";
|
||||
import Flex from "~/components/Flex";
|
||||
import { s } from "@shared/styles";
|
||||
@@ -18,11 +19,7 @@ type Props = {
|
||||
/** The maximum number of users to display, defaults to 8 */
|
||||
limit?: number;
|
||||
/** A component to render the avatar, defaults to Avatar. */
|
||||
renderAvatar?: React.ComponentType<
|
||||
React.ComponentProps<typeof Avatar> & {
|
||||
model: User;
|
||||
}
|
||||
>;
|
||||
renderAvatar?: React.ComponentType<AvatarProps>;
|
||||
/** Whether to show tooltips on hover, defaults to true */
|
||||
showTooltip?: boolean;
|
||||
};
|
||||
|
||||
@@ -290,6 +290,7 @@ const Sidebar = React.forwardRef<HTMLDivElement, Props>(function Sidebar_(
|
||||
alt={t("Avatar of {{ name }}", { name: user.name })}
|
||||
model={user}
|
||||
size={24}
|
||||
showHoverCard={false}
|
||||
/>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
import * as HoverCardPrimitive from "@radix-ui/react-hover-card";
|
||||
import { observer } from "mobx-react";
|
||||
import { ClockIcon } from "outline-icons";
|
||||
import * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import styled from "styled-components";
|
||||
import { depths, s } from "@shared/styles";
|
||||
import Avatar, { AvatarSize } from "~/components/Avatar/Avatar";
|
||||
import Badge from "~/components/Badge";
|
||||
import Flex from "~/components/Flex";
|
||||
import Text from "~/components/Text";
|
||||
import Time from "~/components/Time";
|
||||
import { usePortalContext } from "~/components/Portal";
|
||||
import useMobile from "~/hooks/useMobile";
|
||||
import type User from "~/models/User";
|
||||
import { fadeAndScaleIn } from "~/styles/animations";
|
||||
|
||||
type Props = {
|
||||
/** The user to display a profile card for. */
|
||||
user: User;
|
||||
/** Additional information to display alongside the user's activity. */
|
||||
info?: React.ReactNode;
|
||||
/** The preferred side of the trigger to render against when open. */
|
||||
side?: "top" | "right" | "bottom" | "left";
|
||||
/** The element that triggers the card on hover. */
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Displays a card with a summary of the given user's profile when the wrapped
|
||||
* element is hovered.
|
||||
*/
|
||||
export const UserHoverCard = ({ user, info, side, children }: Props) => {
|
||||
const container = usePortalContext();
|
||||
const isMobile = useMobile();
|
||||
|
||||
if (isMobile) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
return (
|
||||
<HoverCardPrimitive.Root openDelay={500} closeDelay={150}>
|
||||
<HoverCardPrimitive.Trigger asChild>
|
||||
{children}
|
||||
</HoverCardPrimitive.Trigger>
|
||||
<HoverCardPrimitive.Portal container={container}>
|
||||
<Content side={side} sideOffset={8} collisionPadding={8}>
|
||||
<Profile user={user} info={info} />
|
||||
</Content>
|
||||
</HoverCardPrimitive.Portal>
|
||||
</HoverCardPrimitive.Root>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* The contents of the hover card, rendered only while the card is open so that
|
||||
* the per-minute clock updates do not affect avatars on the page.
|
||||
*/
|
||||
const Profile = observer(function Profile_({
|
||||
user,
|
||||
info,
|
||||
}: Pick<Props, "user" | "info">) {
|
||||
const { t } = useTranslation();
|
||||
const localTime = user.localTime;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex gap={12} align="center">
|
||||
<Avatar model={user} size={AvatarSize.XLarge} />
|
||||
<Flex column justify="center">
|
||||
<NameRow>
|
||||
<Name>{user.name}</Name>
|
||||
{user.isAdmin ? (
|
||||
<RoleBadge primary>{t("Admin")}</RoleBadge>
|
||||
) : user.isGuest ? (
|
||||
<RoleBadge>{t("Guest")}</RoleBadge>
|
||||
) : null}
|
||||
{user.isSuspended && <RoleBadge>{t("Suspended")}</RoleBadge>}
|
||||
</NameRow>
|
||||
<Info>
|
||||
{user.isInvited ? (
|
||||
t("Invited")
|
||||
) : user.isRecentlyActive ? (
|
||||
t("Online")
|
||||
) : (
|
||||
<>
|
||||
{t("Last seen")} <Time dateTime={user.lastActiveAt} addSuffix />
|
||||
</>
|
||||
)}
|
||||
</Info>
|
||||
</Flex>
|
||||
</Flex>
|
||||
{(localTime || info) && (
|
||||
<>
|
||||
<Divider />
|
||||
<Flex column gap={8}>
|
||||
{localTime && (
|
||||
<Row>
|
||||
<ClockIcon size={18} />
|
||||
{t("{{ time }} local time", { time: localTime })}
|
||||
</Row>
|
||||
)}
|
||||
{info && <Row>{info}</Row>}
|
||||
</Flex>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
const NameRow = styled(Flex).attrs({ align: "center", gap: 4 })`
|
||||
min-width: 0;
|
||||
`;
|
||||
|
||||
const Name = styled(Text).attrs({
|
||||
as: "h3",
|
||||
weight: "bold",
|
||||
ellipsis: true,
|
||||
})`
|
||||
margin: 0;
|
||||
min-width: 0;
|
||||
font-size: 15px;
|
||||
`;
|
||||
|
||||
// Scaled down from the default badge to sit comfortably beside the name.
|
||||
const RoleBadge = styled(Badge)`
|
||||
flex-shrink: 0;
|
||||
margin: 0;
|
||||
padding: 1px 4.5px;
|
||||
border-radius: 6px;
|
||||
font-size: 10px;
|
||||
`;
|
||||
|
||||
const Info = styled(Text).attrs({
|
||||
as: "p",
|
||||
type: "tertiary",
|
||||
size: "xsmall",
|
||||
})`
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
`;
|
||||
|
||||
const Divider = styled.div`
|
||||
height: 1px;
|
||||
margin: 12px 0;
|
||||
background: ${s("divider")};
|
||||
`;
|
||||
|
||||
const Row = styled(Flex).attrs({ align: "center", gap: 8 })`
|
||||
color: ${s("textSecondary")};
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
|
||||
svg {
|
||||
color: ${s("textTertiary")};
|
||||
flex-shrink: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const Content = styled(HoverCardPrimitive.Content)`
|
||||
z-index: ${depths.tooltip};
|
||||
transform-origin: var(--radix-hover-card-content-transform-origin);
|
||||
background: ${s("menuBackground")};
|
||||
box-shadow: ${s("menuShadow")};
|
||||
border-radius: 6px;
|
||||
padding: 12px;
|
||||
min-width: 180px;
|
||||
max-width: 320px;
|
||||
outline: none;
|
||||
user-select: none;
|
||||
|
||||
&[data-state="open"] {
|
||||
animation: ${fadeAndScaleIn} 150ms cubic-bezier(0.08, 0.82, 0.17, 1);
|
||||
}
|
||||
|
||||
@media print {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
} from "@shared/types";
|
||||
import type { NotificationSettings } from "@shared/types";
|
||||
import type { locales } from "@shared/utils/date";
|
||||
import { unicodeCLDRtoBCP47 } from "@shared/utils/date";
|
||||
import { client } from "~/utils/ApiClient";
|
||||
import type Document from "./Document";
|
||||
import type Group from "./Group";
|
||||
@@ -152,6 +153,30 @@ class User extends ParanoidModel implements Searchable {
|
||||
return new Date(this.lastActiveAt) > subMinutes(now(10000), 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* The current time where the user is located, formatted for the locale of the
|
||||
* signed-in user.
|
||||
*
|
||||
* @returns the formatted time, or undefined if the user's timezone is unknown
|
||||
*/
|
||||
@computed
|
||||
get localTime(): string | undefined {
|
||||
if (!this.timezone) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const language = this.store.rootStore.auth?.user?.language;
|
||||
|
||||
try {
|
||||
return new Date(now(60000)).toLocaleTimeString(
|
||||
language ? unicodeCLDRtoBCP47(language) : undefined,
|
||||
{ hour: "numeric", minute: "numeric", timeZone: this.timezone }
|
||||
);
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this user is using a separate editing mode behind an "Edit"
|
||||
* button rather than seamless always-editing.
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
"@radix-ui/react-dialog": "^1.1.19",
|
||||
"@radix-ui/react-direction": "^1.1.2",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.20",
|
||||
"@radix-ui/react-hover-card": "^1.1.23",
|
||||
"@radix-ui/react-one-time-password-field": "^0.1.12",
|
||||
"@radix-ui/react-popover": "^1.1.19",
|
||||
"@radix-ui/react-select": "^2.3.3",
|
||||
|
||||
@@ -596,6 +596,11 @@
|
||||
"A confirmation email will be sent to the new address before it is changed.": "A confirmation email will be sent to the new address before it is changed.",
|
||||
"New email": "New email",
|
||||
"Email can't be empty": "Email can't be empty",
|
||||
"Admin": "Admin",
|
||||
"Guest": "Guest",
|
||||
"Online": "Online",
|
||||
"Last seen": "Last seen",
|
||||
"{{ time }} local time": "{{ time }} local time",
|
||||
"Your import completed": "Your import completed",
|
||||
"View comment thread": "View comment thread",
|
||||
"Previous match": "Previous match",
|
||||
@@ -938,7 +943,6 @@
|
||||
"Sorry, you can only send {{MAX_INVITES}} invites at a time": "Sorry, you can only send {{MAX_INVITES}} invites at a time",
|
||||
"Invited {{roleName}} will receive access to": "Invited {{roleName}} will receive access to",
|
||||
"{{collectionCount}} collections": "{{collectionCount}} collections",
|
||||
"Admin": "Admin",
|
||||
"Can manage all workspace settings": "Can manage all workspace settings",
|
||||
"Can create, edit, and delete documents": "Can create, edit, and delete documents",
|
||||
"Can view and comment": "Can view and comment",
|
||||
@@ -1251,7 +1255,6 @@
|
||||
"You can import a zip file that was previously exported from an Outline installation – collections, documents, and images will be imported. In Outline, open <em>Export</em> in the Settings sidebar and click on <em>Export Data</em>.": "You can import a zip file that was previously exported from an Outline installation – collections, documents, and images will be imported. In Outline, open <em>Export</em> in the Settings sidebar and click on <em>Export Data</em>.",
|
||||
"Drag and drop the zip file from the Markdown export option in {{appName}}, or click to upload": "Drag and drop the zip file from the Markdown export option in {{appName}}, or click to upload",
|
||||
"Configure": "Configure",
|
||||
"Guest": "Guest",
|
||||
"Never used": "Never used",
|
||||
"Are you sure you want to revoke access?": "Are you sure you want to revoke access?",
|
||||
"Are you sure you want to delete the {{ appName }} application? This cannot be undone.": "Are you sure you want to delete the {{ appName }} application? This cannot be undone.",
|
||||
|
||||
@@ -4355,6 +4355,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/primitive@npm:1.1.7":
|
||||
version: 1.1.7
|
||||
resolution: "@radix-ui/primitive@npm:1.1.7"
|
||||
checksum: 10c0/6b1f8b964a57ece3490582d60df79a1c80fdba4c4331b806c4e04b11f42ac46d40a927bfc692dbd881136ec38c3f060c525dbacd6182ba6f3f0bd4284db1028e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-arrow@npm:1.1.11":
|
||||
version: 1.1.11
|
||||
resolution: "@radix-ui/react-arrow@npm:1.1.11"
|
||||
@@ -4374,6 +4381,25 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-arrow@npm:1.1.15":
|
||||
version: 1.1.15
|
||||
resolution: "@radix-ui/react-arrow@npm:1.1.15"
|
||||
dependencies:
|
||||
"@radix-ui/react-primitive": "npm:2.1.10"
|
||||
peerDependencies:
|
||||
"@types/react": "*"
|
||||
"@types/react-dom": "*"
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
"@types/react-dom":
|
||||
optional: true
|
||||
checksum: 10c0/06fa0a29ae332617d7912e4f25e952d110905264362e7266d2aa423e81aff492d0f1eaa7dd834b3271e6f5d45f56c8c54585d10d771356fb789e50c959f555ca
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-collapsible@npm:^1.1.16":
|
||||
version: 1.1.16
|
||||
resolution: "@radix-ui/react-collapsible@npm:1.1.16"
|
||||
@@ -4435,6 +4461,19 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-compose-refs@npm:1.1.5":
|
||||
version: 1.1.5
|
||||
resolution: "@radix-ui/react-compose-refs@npm:1.1.5"
|
||||
peerDependencies:
|
||||
"@types/react": "*"
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
checksum: 10c0/ab5cc8cc2f5be285981cffb64aa956d3a28427c649a953d125e900e1befb8b9a55f2d7a31bc01059d29df43ff4ae14ebc6cca7e4c2084d638cef5e5aef7cc263
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-context-menu@npm:^2.3.3":
|
||||
version: 2.3.3
|
||||
resolution: "@radix-ui/react-context-menu@npm:2.3.3"
|
||||
@@ -4471,6 +4510,19 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-context@npm:1.2.2":
|
||||
version: 1.2.2
|
||||
resolution: "@radix-ui/react-context@npm:1.2.2"
|
||||
peerDependencies:
|
||||
"@types/react": "*"
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
checksum: 10c0/f5c15339558d64901c99f243a2538be9b28eb20e0dae1e44c8872ed12580ec27f5f309fd491f85f1b0dcb214c90fdae7eede7fe2b0d26569c4dbeffbeff451c0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-dialog@npm:^1.1.1, @radix-ui/react-dialog@npm:^1.1.19":
|
||||
version: 1.1.19
|
||||
resolution: "@radix-ui/react-dialog@npm:1.1.19"
|
||||
@@ -4539,6 +4591,29 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-dismissable-layer@npm:1.1.19":
|
||||
version: 1.1.19
|
||||
resolution: "@radix-ui/react-dismissable-layer@npm:1.1.19"
|
||||
dependencies:
|
||||
"@radix-ui/primitive": "npm:1.1.7"
|
||||
"@radix-ui/react-compose-refs": "npm:1.1.5"
|
||||
"@radix-ui/react-primitive": "npm:2.1.10"
|
||||
"@radix-ui/react-use-callback-ref": "npm:1.1.4"
|
||||
"@radix-ui/react-use-effect-event": "npm:0.0.5"
|
||||
peerDependencies:
|
||||
"@types/react": "*"
|
||||
"@types/react-dom": "*"
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
"@types/react-dom":
|
||||
optional: true
|
||||
checksum: 10c0/205f2fded4a9e303fcc0d67b78274db84d37d0d35177bb99602c72202a6dcadc39f4cbf936a09e1303b4b42a2b494a279ead9e626cb1a41015152a91ad069fc5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-dropdown-menu@npm:^2.1.20":
|
||||
version: 2.1.20
|
||||
resolution: "@radix-ui/react-dropdown-menu@npm:2.1.20"
|
||||
@@ -4598,6 +4673,33 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-hover-card@npm:^1.1.23":
|
||||
version: 1.1.23
|
||||
resolution: "@radix-ui/react-hover-card@npm:1.1.23"
|
||||
dependencies:
|
||||
"@radix-ui/primitive": "npm:1.1.7"
|
||||
"@radix-ui/react-compose-refs": "npm:1.1.5"
|
||||
"@radix-ui/react-context": "npm:1.2.2"
|
||||
"@radix-ui/react-dismissable-layer": "npm:1.1.19"
|
||||
"@radix-ui/react-popper": "npm:1.3.7"
|
||||
"@radix-ui/react-portal": "npm:1.1.17"
|
||||
"@radix-ui/react-presence": "npm:1.1.10"
|
||||
"@radix-ui/react-primitive": "npm:2.1.10"
|
||||
"@radix-ui/react-use-controllable-state": "npm:1.2.6"
|
||||
peerDependencies:
|
||||
"@types/react": "*"
|
||||
"@types/react-dom": "*"
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
"@types/react-dom":
|
||||
optional: true
|
||||
checksum: 10c0/08b62baccf478f9cb5e2fa6da27a85d9b9499735c7a29c4e5986404ec9ee2c393464baec7739fa34a18681f1eb65d784271e991c7eeb6b91573046eaba232621
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-id@npm:1.1.2":
|
||||
version: 1.1.2
|
||||
resolution: "@radix-ui/react-id@npm:1.1.2"
|
||||
@@ -4740,7 +4842,35 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-portal@npm:1.1.13, @radix-ui/react-portal@npm:^1.0.1":
|
||||
"@radix-ui/react-popper@npm:1.3.7":
|
||||
version: 1.3.7
|
||||
resolution: "@radix-ui/react-popper@npm:1.3.7"
|
||||
dependencies:
|
||||
"@floating-ui/react-dom": "npm:^2.0.0"
|
||||
"@radix-ui/react-arrow": "npm:1.1.15"
|
||||
"@radix-ui/react-compose-refs": "npm:1.1.5"
|
||||
"@radix-ui/react-context": "npm:1.2.2"
|
||||
"@radix-ui/react-primitive": "npm:2.1.10"
|
||||
"@radix-ui/react-use-callback-ref": "npm:1.1.4"
|
||||
"@radix-ui/react-use-layout-effect": "npm:1.1.4"
|
||||
"@radix-ui/react-use-rect": "npm:1.1.4"
|
||||
"@radix-ui/react-use-size": "npm:1.1.4"
|
||||
"@radix-ui/rect": "npm:1.1.3"
|
||||
peerDependencies:
|
||||
"@types/react": "*"
|
||||
"@types/react-dom": "*"
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
"@types/react-dom":
|
||||
optional: true
|
||||
checksum: 10c0/f32e85f70d2161d724df4adae4103d5c1f61ff344d25ad51c4f3d0a02b6251890b864dde3313093d748efe824dc9cceb40a068ac68b10bd1163d4b678e01d6e3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-portal@npm:1.1.13":
|
||||
version: 1.1.13
|
||||
resolution: "@radix-ui/react-portal@npm:1.1.13"
|
||||
dependencies:
|
||||
@@ -4760,6 +4890,45 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-portal@npm:1.1.17, @radix-ui/react-portal@npm:^1.0.1":
|
||||
version: 1.1.17
|
||||
resolution: "@radix-ui/react-portal@npm:1.1.17"
|
||||
dependencies:
|
||||
"@radix-ui/react-primitive": "npm:2.1.10"
|
||||
"@radix-ui/react-use-layout-effect": "npm:1.1.4"
|
||||
peerDependencies:
|
||||
"@types/react": "*"
|
||||
"@types/react-dom": "*"
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
"@types/react-dom":
|
||||
optional: true
|
||||
checksum: 10c0/f3358ef906582ee8dd8ae62db1f1c1e9810e0554ff8e1a887c731fb35d3b673791e9d338cab884f3eddd74e24afd8e21679b1cc24fd035c68ad71dd09ed71bae
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-presence@npm:1.1.10":
|
||||
version: 1.1.10
|
||||
resolution: "@radix-ui/react-presence@npm:1.1.10"
|
||||
dependencies:
|
||||
"@radix-ui/react-use-layout-effect": "npm:1.1.4"
|
||||
peerDependencies:
|
||||
"@types/react": "*"
|
||||
"@types/react-dom": "*"
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
"@types/react-dom":
|
||||
optional: true
|
||||
checksum: 10c0/5ef8048ea02ecfd11284e229efa33f75074189788b68edb9fe38140cbc56cc40ee77f017f34e3c3d3a5dbc1fb12b5a18d5a9ef2a84ef966a1d90502be5a84617
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-presence@npm:1.1.7":
|
||||
version: 1.1.7
|
||||
resolution: "@radix-ui/react-presence@npm:1.1.7"
|
||||
@@ -4779,6 +4948,25 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-primitive@npm:2.1.10":
|
||||
version: 2.1.10
|
||||
resolution: "@radix-ui/react-primitive@npm:2.1.10"
|
||||
dependencies:
|
||||
"@radix-ui/react-slot": "npm:1.3.3"
|
||||
peerDependencies:
|
||||
"@types/react": "*"
|
||||
"@types/react-dom": "*"
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
"@types/react-dom":
|
||||
optional: true
|
||||
checksum: 10c0/3be05e842d20a5eb08cebbc1d4d08f24a4c09af8cb864e1d1dddf27f362b739ce0edc1c9fc188a7c734cecd8f5df21e379c15774230f4ab11ce2a8229d3598da
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-primitive@npm:2.1.7":
|
||||
version: 2.1.7
|
||||
resolution: "@radix-ui/react-primitive@npm:2.1.7"
|
||||
@@ -4886,7 +5074,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-slot@npm:1.3.0, @radix-ui/react-slot@npm:^1.3.0":
|
||||
"@radix-ui/react-slot@npm:1.3.0":
|
||||
version: 1.3.0
|
||||
resolution: "@radix-ui/react-slot@npm:1.3.0"
|
||||
dependencies:
|
||||
@@ -4901,6 +5089,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-slot@npm:1.3.3, @radix-ui/react-slot@npm:^1.3.0":
|
||||
version: 1.3.3
|
||||
resolution: "@radix-ui/react-slot@npm:1.3.3"
|
||||
dependencies:
|
||||
"@radix-ui/react-compose-refs": "npm:1.1.5"
|
||||
peerDependencies:
|
||||
"@types/react": "*"
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
checksum: 10c0/7ed356819bbb40415ccd16bc8a8da3162966e827ea8fa404c2ae547518777aa193b0aad07f139f3c9d3280f51433e1cc4fa4cfd8dc7e8e6215e7b0d7a25e4b39
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-switch@npm:^1.3.3":
|
||||
version: 1.3.3
|
||||
resolution: "@radix-ui/react-switch@npm:1.3.3"
|
||||
@@ -5066,6 +5269,19 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-use-callback-ref@npm:1.1.4":
|
||||
version: 1.1.4
|
||||
resolution: "@radix-ui/react-use-callback-ref@npm:1.1.4"
|
||||
peerDependencies:
|
||||
"@types/react": "*"
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
checksum: 10c0/d5cc1248ab6a58b12eefd3115c98fb438b74b2e6dec463d2e097d27df8e9f40b9d8693ee10a422da4f7a688fbe52c62cc2fe3aa5972020b9425b86a2a28f5f01
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-use-controllable-state@npm:1.2.3":
|
||||
version: 1.2.3
|
||||
resolution: "@radix-ui/react-use-controllable-state@npm:1.2.3"
|
||||
@@ -5082,6 +5298,23 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-use-controllable-state@npm:1.2.6":
|
||||
version: 1.2.6
|
||||
resolution: "@radix-ui/react-use-controllable-state@npm:1.2.6"
|
||||
dependencies:
|
||||
"@radix-ui/primitive": "npm:1.1.7"
|
||||
"@radix-ui/react-use-effect-event": "npm:0.0.5"
|
||||
"@radix-ui/react-use-layout-effect": "npm:1.1.4"
|
||||
peerDependencies:
|
||||
"@types/react": "*"
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
checksum: 10c0/1672c3fa5c1f2dbc354db4d403523eef15bcbe24448b911e67e3e95f351b72ffc1dc1021a225d98116cd78d1c96e6280f1645ac6d6b9930df46b180b8a6f11a5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-use-effect-event@npm:0.0.3":
|
||||
version: 0.0.3
|
||||
resolution: "@radix-ui/react-use-effect-event@npm:0.0.3"
|
||||
@@ -5097,6 +5330,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-use-effect-event@npm:0.0.5":
|
||||
version: 0.0.5
|
||||
resolution: "@radix-ui/react-use-effect-event@npm:0.0.5"
|
||||
dependencies:
|
||||
"@radix-ui/react-use-layout-effect": "npm:1.1.4"
|
||||
peerDependencies:
|
||||
"@types/react": "*"
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
checksum: 10c0/36eb3523d3c30e88615e0492aed5c644e61eb4fec98097de0fb2ee1cf33d7684b76e8a34bedb0aa7c25b412e0ef56c83b16772e9716d03d61901bc1b98cb1993
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-use-is-hydrated@npm:0.1.1":
|
||||
version: 0.1.1
|
||||
resolution: "@radix-ui/react-use-is-hydrated@npm:0.1.1"
|
||||
@@ -5123,6 +5371,19 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-use-layout-effect@npm:1.1.4":
|
||||
version: 1.1.4
|
||||
resolution: "@radix-ui/react-use-layout-effect@npm:1.1.4"
|
||||
peerDependencies:
|
||||
"@types/react": "*"
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
checksum: 10c0/427df10bb3c55de36afd6b9a749fb4b72b0f78840ae4abb5dda24aa09d653ede2d264c96a8030f58db353498f42b2bce929510c777004e250f7845b06c782bcf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-use-previous@npm:1.1.2":
|
||||
version: 1.1.2
|
||||
resolution: "@radix-ui/react-use-previous@npm:1.1.2"
|
||||
@@ -5151,6 +5412,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-use-rect@npm:1.1.4":
|
||||
version: 1.1.4
|
||||
resolution: "@radix-ui/react-use-rect@npm:1.1.4"
|
||||
dependencies:
|
||||
"@radix-ui/rect": "npm:1.1.3"
|
||||
peerDependencies:
|
||||
"@types/react": "*"
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
checksum: 10c0/3acfe9265f9fbdcdead05ec4540a95d8932fb53e9eabd73c080650122424d3d5247260d349ea2d91b2712af9670a27ac2110400671b98d061b2347390fe29490
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-use-size@npm:1.1.2":
|
||||
version: 1.1.2
|
||||
resolution: "@radix-ui/react-use-size@npm:1.1.2"
|
||||
@@ -5166,6 +5442,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-use-size@npm:1.1.4":
|
||||
version: 1.1.4
|
||||
resolution: "@radix-ui/react-use-size@npm:1.1.4"
|
||||
dependencies:
|
||||
"@radix-ui/react-use-layout-effect": "npm:1.1.4"
|
||||
peerDependencies:
|
||||
"@types/react": "*"
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
checksum: 10c0/ebb4a0c6e71768ae231635cc721d7f01de0a31637e73cccea095ad63921bfece9635eb9500cbe32504585380910f578216fb3eebdfc21b511f6dd6df81659f75
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/react-visually-hidden@npm:1.2.7, @radix-ui/react-visually-hidden@npm:^1.2.7":
|
||||
version: 1.2.7
|
||||
resolution: "@radix-ui/react-visually-hidden@npm:1.2.7"
|
||||
@@ -5192,6 +5483,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/rect@npm:1.1.3":
|
||||
version: 1.1.3
|
||||
resolution: "@radix-ui/rect@npm:1.1.3"
|
||||
checksum: 10c0/9396d6c4dbd8da51c0bef7481e1e46e7f371e27cc6a55c1079e854f3aa9f7dd89e02d98cc36e861e8d43fbb775eb76b06bdf5879fa12f25116bea676af2926da
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@reach/observe-rect@npm:^1.1.0":
|
||||
version: 1.2.0
|
||||
resolution: "@reach/observe-rect@npm:1.2.0"
|
||||
@@ -15456,6 +15754,7 @@ __metadata:
|
||||
"@radix-ui/react-dialog": "npm:^1.1.19"
|
||||
"@radix-ui/react-direction": "npm:^1.1.2"
|
||||
"@radix-ui/react-dropdown-menu": "npm:^2.1.20"
|
||||
"@radix-ui/react-hover-card": "npm:^1.1.23"
|
||||
"@radix-ui/react-one-time-password-field": "npm:^0.1.12"
|
||||
"@radix-ui/react-popover": "npm:^1.1.19"
|
||||
"@radix-ui/react-select": "npm:^2.3.3"
|
||||
|
||||
Reference in New Issue
Block a user