Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Id component for ui #2697

Merged
merged 21 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion apps/engineering/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { GeistSans } from "geist/font/sans";

import type { ReactNode } from "react";

import { TooltipProvider } from "@unkey/ui/src/components/tooltip";
import "./global.css";

export default function Layout({ children }: { children: ReactNode }) {
Expand All @@ -14,7 +15,9 @@ export default function Layout({ children }: { children: ReactNode }) {
suppressHydrationWarning
>
<body>
<RootProvider>{children}</RootProvider>
<RootProvider>
<TooltipProvider>{children}</TooltipProvider>
</RootProvider>
</body>
</html>
);
Expand Down
61 changes: 61 additions & 0 deletions apps/engineering/content/design/components/id.mdx
MichaelUnkey marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
MichaelUnkey marked this conversation as resolved.
Show resolved Hide resolved
title: Id
---

import { ValueTruncateExample } from "./id.valueTruncate"
import { WidthExample } from "./id.width"
import { TypeTable } from 'fumadocs-ui/components/type-table';

<TypeTable
type={{
value: {
description:
'The identifier to display.',
type: 'string',
},
truncate: {
description:
'Number of characters to show before truncating.',
type: 'number | undefined',
default: undefined
},
className: {
description:
'A className applied to the component to override the styling.',
type: 'string | undefined',
default: undefined
},
}}
/>



## Overview

For the `<Id />` component to be used, the `<TooltipProvider>` must be used at the root of the application or somewhere higher in the scope. This is to ensure that the tooltip is rendered correctly.

## Truncate & Value

`Id` should be used to display a unique identifier. The `Id` value is passed into the `value` prop. If the value needs to be truncated, a number should be passed to the `truncate` prop.
MichaelUnkey marked this conversation as resolved.
Show resolved Hide resolved
<ValueTruncateExample />

## Container Width Full

<WidthExample />

















13 changes: 13 additions & 0 deletions apps/engineering/content/design/components/id.valueTruncate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { RenderComponentWithSnippet } from "@/app/components/render";
import { Row } from "@/app/components/row";
import { Id } from "@unkey/ui";

export const ValueTruncateExample: React.FC = () => (
<RenderComponentWithSnippet>
<Row>
<Id value={"api_zTLSnw1YTqUHRwJTgKWrg"} />
<Id value={"api_zTLSnw1YTqUHRwJTgKWrg"} truncate={6} />
<Id value={"api_zTLSnw1YTqUHRwJTgKWrg"} truncate={12} />
</Row>
</RenderComponentWithSnippet>
);
chronark marked this conversation as resolved.
Show resolved Hide resolved
10 changes: 10 additions & 0 deletions apps/engineering/content/design/components/id.width.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { RenderComponentWithSnippet } from "@/app/components/render";
import { Id } from "@unkey/ui";

export const WidthExample: React.FC = () => (
<RenderComponentWithSnippet>
<div className="w-full">
<Id value={"api_zTLSnw1YTqUHRwJTgKWrg"} truncate={20} />
</div>
</RenderComponentWithSnippet>
);
8 changes: 8 additions & 0 deletions apps/engineering/content/design/components/tooltip.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: Tooltip
---
import { OnHoverExample } from "./tooltip.onHover"

## Tooltip

<OnHoverExample />
63 changes: 63 additions & 0 deletions apps/engineering/content/design/components/tooltip.onHover.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { RenderComponentWithSnippet } from "@/app/components/render";
import { Row } from "@/app/components/row";

import { Tooltip, TooltipContent, TooltipTrigger } from "@unkey/ui";
import { InfoIcon } from "lucide-react";
export const OnHoverExample: React.FC = () => (
<RenderComponentWithSnippet>
<Row>
<Tooltip>
<TooltipTrigger>
<p className="inline-flex gap-4 border border-gray-2 px-3 py-1 rounded-lg ">
Bottom{" "}
<span>
<InfoIcon size={14} className="text-gray-10 self-auto h-full" />
</span>
</p>
</TooltipTrigger>
<TooltipContent className="h-8" side="bottom">
Content
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger>
<p className="inline-flex gap-4 border border-gray-2 px-3 py-1 rounded-lg ">
Top{" "}
<span>
<InfoIcon size={14} className="text-gray-10 self-auto h-full" />
</span>
</p>
</TooltipTrigger>
<TooltipContent className="h-8" side="top">
Content
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger>
<p className="inline-flex gap-4 border border-gray-2 px-3 py-1 rounded-lg ">
Right{" "}
<span>
<InfoIcon size={14} className="text-gray-10 self-auto h-full" />
</span>
</p>
</TooltipTrigger>
<TooltipContent className="h-8" side="right">
Content
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger>
<p className="inline-flex gap-4 border border-gray-2 px-3 py-1 rounded-lg ">
Left{" "}
<span>
<InfoIcon size={14} className="text-gray-10 self-auto h-full" />
</span>
</p>
</TooltipTrigger>
<TooltipContent className="h-8" side="left">
Content
</TooltipContent>
</Tooltip>
chronark marked this conversation as resolved.
Show resolved Hide resolved
</Row>
</RenderComponentWithSnippet>
);
4 changes: 3 additions & 1 deletion internal/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@
"typescript": "^5.5.3"
},
"dependencies": {
"@radix-ui/react-tooltip": "^1.0.7",
"@radix-ui/colors": "^3.0.0",
"@radix-ui/react-slot": "^1.1.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"lucide-react": "^0.378.0",
"react": "^18.2.0",
"tailwind-merge": "^2.5.4",
"tailwindcss-animate": "^1.0.7"
"tailwindcss-animate": "^1.0.7",
"@unkey/icons": "workspace:^"
}
}
75 changes: 75 additions & 0 deletions internal/ui/src/components/id.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"use client";
import { TaskChecked, TaskUnchecked } from "@unkey/icons";
import * as React from "react";
import { cn } from "../lib/utils";
import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip";

type IdProps = {
/**
* Value displayed on the component.
*/
value: string;
MichaelUnkey marked this conversation as resolved.
Show resolved Hide resolved
/**
* Number to truncate the value to. If the value is longer than the truncate number, it will be truncated and an ellipse will be added to the end.
*/
truncate?: number;
/**
* Any additional classes to apply to the component.
*/
className?: string;
};

export const Id: React.FC<IdProps> = ({ className, value, truncate, ...props }) => {
const [isCopied, setIsCopied] = React.useState(false);
const copyTextToClipboard = async (value: string) => {
try {
await navigator.clipboard.writeText(value);
setIsCopied(true);
} catch (error) {
console.error("Failed to copy: ", error);
}
};

React.useEffect(() => {
if (!isCopied) {
return;
}
const timer = setTimeout(() => {
setIsCopied(false);
}, 2000);
return () => clearTimeout(timer);
}, [isCopied]);

const ellipse = "••••";
const truncateValue = truncate ? value?.slice(0, truncate) + ellipse : value;

return (
<button
type="button"
className={cn(
"relative inline-flex ring-2 ring-transparent no-underline focus:ring-gray-6 group items-center transition duration-150 justify-center gap-3 whitespace-nowrap tracking-normal rounded-lg font-medium bg-gray-1 w-fit max-w-96 border border-accent-6 hover:border-accent-8 text-gray-12 font-mono h-8 px-3 py-1 text-xs overflow-hidden",
className,
)}
onClick={() => copyTextToClipboard(value)}
aria-label={`Copy ID: ${value}`}
{...props}
>
{truncateValue}
<Tooltip>
<div className="absolute flex h-8 w-8 top-0 right-0 opacity-0 group-hover:opacity-100 group-focus:opacity-100 transition-opacity">
<TooltipTrigger asChild>
<div className=" flex justify-end border w-full border-none h-full bg-accent-1">
{!isCopied ? (
<TaskUnchecked className="item-end my-auto mr-2 bg-gray-1" />
) : (
<TaskChecked className="item-end my-auto mr-2 bg-gray-1" />
)}
</div>
</TooltipTrigger>
<TooltipContent side="bottom">Copy ID</TooltipContent>
</div>
</Tooltip>
</button>
);
};
Id.displayName = "Id";
30 changes: 30 additions & 0 deletions internal/ui/src/components/tooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"use client";

import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import * as React from "react";

import { cn } from "../lib/utils";

const TooltipProvider = TooltipPrimitive.Provider;

const Tooltip = TooltipPrimitive.Root;

const TooltipTrigger = TooltipPrimitive.Trigger;

const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden font-sans font-medium shadow-md rounded rounded-lg leading-6 bg-gray-12 text-gray-1 px-2 py-1 gap-2 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,
)}
{...props}
/>
));
TooltipContent.displayName = TooltipPrimitive.Content.displayName;

export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
2 changes: 2 additions & 0 deletions internal/ui/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from "./components/button";
export * from "./components/id";
export * from "./components/tooltip";
12 changes: 9 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading