From 5c08c7c17d2b74e0affce1d4117bceb7ab0752c6 Mon Sep 17 00:00:00 2001
From: MananTank
Date: Wed, 27 Aug 2025 23:18:35 +0000
Subject: [PATCH] packages/ui: Add code components (#7927)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
## PR-Codex overview
This PR focuses on refactoring code related to the `CodeClient` component, improving its structure and imports, while also updating several components to use a new centralized location for code utilities. It removes deprecated files and enhances code organization across the project.
### Detailed summary
- Deleted unused files related to clipboard and code rendering.
- Refactored `CodeClient` to use a centralized import from `@workspace/ui/components/code/code.client`.
- Updated various components to import `CodeClient` and other utilities from the new centralized location.
- Added new `CodeServer` component for server-side rendering of code.
- Improved loading states and error handling in code components.
- Updated component imports across the project to maintain consistency.
- Enhanced `PlainTextCodeBlock` functionality with new props for better customization.
- Removed redundant code and improved overall project structure.
> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`
---
apps/dashboard/knip.json | 3 +-
.../src/@/components/ui/code/code.client.tsx | 70 +-----------------
.../src/@/components/ui/code/code.server.tsx | 26 ++-----
.../@/components/ui/code/plaintext-code.tsx | 30 +-------
apps/playground-web/knip.json | 3 +-
.../blueprint-playground.client.tsx | 3 +-
.../src/app/payments/components/CodeGen.tsx | 23 +++---
.../_components/airdrop-code.tsx | 6 +-
.../mint-tokens/_components/mint-code.tsx | 6 +-
.../webhooks/_components/webhooks-preview.tsx | 8 +--
.../wallets/sign-in/components/CodeGen.tsx | 18 +++--
.../5792-get-capabilities.tsx | 3 +-
.../src/components/code/RenderCode.tsx | 39 ----------
.../src/components/code/code-example.tsx | 4 +-
.../src/components/code/code.client.tsx | 58 +--------------
.../src/components/code/code.tsx | 28 +-------
.../src/components/code/getCodeHtml.tsx | 38 ----------
.../src/components/in-app-wallet/profiles.tsx | 3 +-
.../src/components/ui/markdown-renderer.tsx | 2 +-
.../APIEndpointMeta/DynamicRequestExample.tsx | 5 +-
.../components/Document/AuthMethodsTabs.tsx | 3 +-
.../components/code/CodeBlockContainer.tsx | 59 ---------------
.../portal/src/components/code/RenderCode.tsx | 39 ----------
.../src/components/code/code.client.tsx | 61 ++--------------
.../src/components/code/getCodeHtml.tsx | 47 ------------
.../src/components/code/plaintext-code.tsx | 30 +-------
.../components/markdown/MarkdownRenderer.tsx | 13 ++--
apps/portal/src/components/ui/CopyButton.tsx | 36 ----------
packages/ui/package.json | 11 ++-
packages/ui/src/components/badge.tsx | 3 +-
packages/ui/src/components/breadcrumb.tsx | 3 +-
packages/ui/src/components/button.stories.tsx | 4 +-
packages/ui/src/components/button.tsx | 2 +-
.../components}/code/CodeBlockContainer.tsx | 8 +--
.../ui/src/components}/code/RenderCode.tsx | 0
.../ui/src/components/code/code.client.tsx | 71 +++++++++++++++++++
.../ui/src/components/code/code.server.tsx | 22 ++++++
.../ui/src/components}/code/code.stories.tsx | 4 +-
.../ui/src/components}/code/getCodeHtml.tsx | 0
.../code/plaintext-code.stories.tsx | 4 +-
.../ui/src/components/code/plaintext-code.tsx | 29 ++++++++
packages/ui/src/components/img.stories.tsx | 4 +-
packages/ui/src/components/img.tsx | 2 +-
packages/ui/src/components/input.tsx | 2 +-
packages/ui/src/components/scroll-shadow.tsx | 2 +-
packages/ui/src/components/spinner.tsx | 2 +-
packages/ui/src/components/table.stories.tsx | 4 +-
packages/ui/src/components/table.tsx | 2 +-
packages/ui/src/components/tooltip.tsx | 3 +-
.../ui}/src/hooks/useClipboard.ts | 0
packages/ui/src/storybook/utils.tsx | 2 +-
packages/ui/tsconfig.json | 5 +-
pnpm-lock.yaml | 6 ++
53 files changed, 228 insertions(+), 631 deletions(-)
delete mode 100644 apps/playground-web/src/components/code/RenderCode.tsx
delete mode 100644 apps/playground-web/src/components/code/getCodeHtml.tsx
delete mode 100644 apps/portal/src/components/code/CodeBlockContainer.tsx
delete mode 100644 apps/portal/src/components/code/RenderCode.tsx
delete mode 100644 apps/portal/src/components/code/getCodeHtml.tsx
delete mode 100644 apps/portal/src/components/ui/CopyButton.tsx
rename {apps/dashboard/src/@/components/ui => packages/ui/src/components}/code/CodeBlockContainer.tsx (87%)
rename {apps/dashboard/src/@/components/ui => packages/ui/src/components}/code/RenderCode.tsx (100%)
create mode 100644 packages/ui/src/components/code/code.client.tsx
create mode 100644 packages/ui/src/components/code/code.server.tsx
rename {apps/dashboard/src/@/components/ui => packages/ui/src/components}/code/code.stories.tsx (96%)
rename {apps/dashboard/src/@/components/ui => packages/ui/src/components}/code/getCodeHtml.tsx (100%)
rename {apps/dashboard/src/@/components/ui => packages/ui/src/components}/code/plaintext-code.stories.tsx (92%)
create mode 100644 packages/ui/src/components/code/plaintext-code.tsx
rename {apps/portal => packages/ui}/src/hooks/useClipboard.ts (100%)
diff --git a/apps/dashboard/knip.json b/apps/dashboard/knip.json
index 9d3a56b9ed3..3260bd4557c 100644
--- a/apps/dashboard/knip.json
+++ b/apps/dashboard/knip.json
@@ -15,7 +15,8 @@
"fast-xml-parser",
"@workspace/ui",
"tailwindcss-animate",
- "@radix-ui/react-tooltip"
+ "@radix-ui/react-tooltip",
+ "shiki"
],
"next": true,
"project": ["src/**"]
diff --git a/apps/dashboard/src/@/components/ui/code/code.client.tsx b/apps/dashboard/src/@/components/ui/code/code.client.tsx
index a56b4ba6543..5b837a9e19b 100644
--- a/apps/dashboard/src/@/components/ui/code/code.client.tsx
+++ b/apps/dashboard/src/@/components/ui/code/code.client.tsx
@@ -1,71 +1,3 @@
"use client";
-import { keepPreviousData, useQuery } from "@tanstack/react-query";
-import type { BundledLanguage } from "shiki";
-import { getCodeHtml } from "./getCodeHtml";
-import { PlainTextCodeBlock } from "./plaintext-code";
-import { RenderCode } from "./RenderCode";
-export type CodeProps = {
- code: string;
- lang: BundledLanguage;
- className?: string;
- scrollableClassName?: string;
- keepPreviousDataOnCodeChange?: boolean;
- copyButtonClassName?: string;
- scrollableContainerClassName?: string;
- shadowColor?: string;
- ignoreFormattingErrors?: boolean;
- onCopy?: (code: string) => void;
-};
-
-export const CodeClient: React.FC = ({
- code,
- lang,
- className,
- scrollableClassName,
- keepPreviousDataOnCodeChange = false,
- copyButtonClassName,
- ignoreFormattingErrors,
- scrollableContainerClassName,
- shadowColor,
- onCopy,
-}) => {
- const codeQuery = useQuery({
- placeholderData: keepPreviousDataOnCodeChange
- ? keepPreviousData
- : undefined,
- queryFn: () =>
- getCodeHtml(code, lang, {
- ignoreFormattingErrors: ignoreFormattingErrors,
- }),
- queryKey: ["html", code],
- retry: false,
- });
-
- if (!codeQuery.data) {
- return (
-
- );
- }
-
- return (
-
- );
-};
+export { CodeClient } from "@workspace/ui/components/code/code.client";
diff --git a/apps/dashboard/src/@/components/ui/code/code.server.tsx b/apps/dashboard/src/@/components/ui/code/code.server.tsx
index 82a87a4e8d0..4e4621a7f03 100644
--- a/apps/dashboard/src/@/components/ui/code/code.server.tsx
+++ b/apps/dashboard/src/@/components/ui/code/code.server.tsx
@@ -1,22 +1,4 @@
-import type { BundledLanguage } from "shiki";
-import { getCodeHtml } from "./getCodeHtml";
-import { RenderCode } from "./RenderCode";
-
-export type CodeProps = {
- code: string;
- lang: BundledLanguage;
- className?: string;
- ignoreFormattingErrors?: boolean;
-};
-
-export const CodeServer: React.FC = async ({
- code,
- lang,
- className,
- ignoreFormattingErrors,
-}) => {
- const { html, formattedCode } = await getCodeHtml(code, lang, {
- ignoreFormattingErrors,
- });
- return ;
-};
+export {
+ type CodeProps,
+ CodeServer,
+} from "@workspace/ui/components/code/code.server";
diff --git a/apps/dashboard/src/@/components/ui/code/plaintext-code.tsx b/apps/dashboard/src/@/components/ui/code/plaintext-code.tsx
index de79cc4d354..12a0e83743b 100644
--- a/apps/dashboard/src/@/components/ui/code/plaintext-code.tsx
+++ b/apps/dashboard/src/@/components/ui/code/plaintext-code.tsx
@@ -1,29 +1 @@
-import { cn } from "@/lib/utils";
-import { CodeBlockContainer } from "./CodeBlockContainer";
-
-export function PlainTextCodeBlock(props: {
- code: string;
- copyButtonClassName?: string;
- className?: string;
- scrollableClassName?: string;
- codeClassName?: string;
- scrollableContainerClassName?: string;
- shadowColor?: string;
- onCopy?: (code: string) => void;
-}) {
- return (
-
-
- {props.code}
-
-
- );
-}
+export { PlainTextCodeBlock } from "@workspace/ui/components/code/plaintext-code";
diff --git a/apps/playground-web/knip.json b/apps/playground-web/knip.json
index c4187581b15..335586f1233 100644
--- a/apps/playground-web/knip.json
+++ b/apps/playground-web/knip.json
@@ -5,7 +5,8 @@
"server-only",
"@workspace/ui",
"tailwindcss-animate",
- "@radix-ui/react-tooltip"
+ "@radix-ui/react-tooltip",
+ "prettier"
],
"next": true,
"project": ["src/**"]
diff --git a/apps/playground-web/src/app/insight/[blueprint_slug]/blueprint-playground.client.tsx b/apps/playground-web/src/app/insight/[blueprint_slug]/blueprint-playground.client.tsx
index ac91fa43506..b86c2d108d1 100644
--- a/apps/playground-web/src/app/insight/[blueprint_slug]/blueprint-playground.client.tsx
+++ b/apps/playground-web/src/app/insight/[blueprint_slug]/blueprint-playground.client.tsx
@@ -17,7 +17,7 @@ import {
useForm,
} from "react-hook-form";
import { z } from "zod";
-import { CodeClient, CodeLoading } from "@/components/code/code.client";
+import { CodeClient } from "@/components/code/code.client";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Form, FormField, FormItem, FormMessage } from "@/components/ui/form";
@@ -724,7 +724,6 @@ function ResponseSection(props: {
className="rounded-none border-none bg-transparent"
code={formattedData || ""}
lang="json"
- loader={}
scrollableClassName="h-full"
scrollableContainerClassName="h-full"
// shadowColor="hsl(var(--muted)/50%)"
diff --git a/apps/playground-web/src/app/payments/components/CodeGen.tsx b/apps/playground-web/src/app/payments/components/CodeGen.tsx
index 70f46c55afc..7e7da112df8 100644
--- a/apps/playground-web/src/app/payments/components/CodeGen.tsx
+++ b/apps/playground-web/src/app/payments/components/CodeGen.tsx
@@ -1,19 +1,26 @@
import { lazy, Suspense } from "react";
-import { CodeLoading } from "../../../components/code/code.client";
+import { LoadingDots } from "../../../components/ui/LoadingDots";
import type { BridgeComponentsPlaygroundOptions } from "./types";
-const CodeClient = lazy(() => import("../../../components/code/code.client"));
+const CodeClient = lazy(() =>
+ import("../../../components/code/code.client").then((m) => ({
+ default: m.CodeClient,
+ })),
+);
+
+function CodeLoading() {
+ return (
+
+
+
+ );
+}
export function CodeGen(props: { options: BridgeComponentsPlaygroundOptions }) {
return (
}>
- }
- />
+
);
diff --git a/apps/playground-web/src/app/transactions/airdrop-tokens/_components/airdrop-code.tsx b/apps/playground-web/src/app/transactions/airdrop-tokens/_components/airdrop-code.tsx
index 5bbb0611d9e..2e11ad3deb2 100644
--- a/apps/playground-web/src/app/transactions/airdrop-tokens/_components/airdrop-code.tsx
+++ b/apps/playground-web/src/app/transactions/airdrop-tokens/_components/airdrop-code.tsx
@@ -1,4 +1,4 @@
-import { Code } from "../../../../components/code/code";
+import { CodeServer } from "@/components/code/code";
import { airdropExample } from "../constants";
export function AirdropCode() {
@@ -15,7 +15,7 @@ export function AirdropCode() {
Send Airdrop Transaction Request
-
+
@@ -28,7 +28,7 @@ export function AirdropCode() {
of the transaction using the following code.
-
+
);
}
diff --git a/apps/playground-web/src/app/transactions/mint-tokens/_components/mint-code.tsx b/apps/playground-web/src/app/transactions/mint-tokens/_components/mint-code.tsx
index fc378086fcd..bbd004b5339 100644
--- a/apps/playground-web/src/app/transactions/mint-tokens/_components/mint-code.tsx
+++ b/apps/playground-web/src/app/transactions/mint-tokens/_components/mint-code.tsx
@@ -1,4 +1,4 @@
-import { Code } from "../../../../components/code/code";
+import { CodeServer } from "@/components/code/code";
import { mintExample } from "../constants";
export function MintCode() {
@@ -15,7 +15,7 @@ export function MintCode() {
Send Transaction Request to Mint Dynamic NFTs
-
+
@@ -28,7 +28,7 @@ export function MintCode() {
the transaction using the following code.
-
+
);
}
diff --git a/apps/playground-web/src/app/transactions/webhooks/_components/webhooks-preview.tsx b/apps/playground-web/src/app/transactions/webhooks/_components/webhooks-preview.tsx
index 4593a33c484..5f4bf2aed64 100644
--- a/apps/playground-web/src/app/transactions/webhooks/_components/webhooks-preview.tsx
+++ b/apps/playground-web/src/app/transactions/webhooks/_components/webhooks-preview.tsx
@@ -19,8 +19,7 @@ import {
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
-import CodeClient from "../../../../components/code/code.client";
-import { LoadingDots } from "../../../../components/ui/LoadingDots";
+import { CodeClient } from "../../../../components/code/code.client";
import { Label } from "../../../../components/ui/label";
import { Spinner } from "../../../../components/ui/Spinner";
import { THIRDWEB_CLIENT } from "../../../../lib/client";
@@ -147,11 +146,6 @@ export function EngineWebhooksPreview() {
className="grow rounded-none border-none"
code={JSON.stringify(engineTxStatusQuery.data, null, 2)}
lang="json"
- loader={
-
-
-
- }
scrollableContainerClassName="h-full"
/>
diff --git a/apps/playground-web/src/app/wallets/sign-in/components/CodeGen.tsx b/apps/playground-web/src/app/wallets/sign-in/components/CodeGen.tsx
index 886e46cb7a9..408b14d8ce0 100644
--- a/apps/playground-web/src/app/wallets/sign-in/components/CodeGen.tsx
+++ b/apps/playground-web/src/app/wallets/sign-in/components/CodeGen.tsx
@@ -1,11 +1,21 @@
import { lazy, Suspense } from "react";
-import { CodeLoading } from "../../../../components/code/code.client";
+import { LoadingDots } from "../../../../components/ui/LoadingDots";
import type { ConnectPlaygroundOptions } from "./types";
-const CodeClient = lazy(
- () => import("../../../../components/code/code.client"),
+const CodeClient = lazy(() =>
+ import("../../../../components/code/code.client").then((m) => ({
+ default: m.CodeClient,
+ })),
);
+function CodeLoading() {
+ return (
+
+
+
+ );
+}
+
export function CodeGen(props: { connectOptions: ConnectPlaygroundOptions }) {
return (
@@ -14,8 +24,6 @@ export function CodeGen(props: { connectOptions: ConnectPlaygroundOptions }) {
className="xl:h-[calc(100vh-100px)]"
code={getCode(props.connectOptions)}
lang="tsx"
- // Need to add max-h in both places - TODO figure out a better way
- loader={
}
scrollableClassName="xl:h-[calc(100vh-100px)]"
/>
diff --git a/apps/playground-web/src/components/account-abstraction/5792-get-capabilities.tsx b/apps/playground-web/src/components/account-abstraction/5792-get-capabilities.tsx
index b8c76bdcdf6..bd8fe60bcd7 100644
--- a/apps/playground-web/src/components/account-abstraction/5792-get-capabilities.tsx
+++ b/apps/playground-web/src/components/account-abstraction/5792-get-capabilities.tsx
@@ -8,7 +8,7 @@ import {
} from "thirdweb/react";
import { createWallet, inAppWallet } from "thirdweb/wallets";
import { THIRDWEB_CLIENT } from "../../lib/client";
-import CodeClient from "../code/code.client";
+import { CodeClient } from "../code/code.client";
export function Eip5792GetCapabilitiesPreview() {
const capabilities = useCapabilities();
@@ -48,7 +48,6 @@ export function Eip5792GetCapabilitiesPreview() {
className="max-h-[500px] w-[400px] overflow-y-auto"
code={JSON.stringify(capabilities.data, null, 2)}
lang="json"
- loader={
Loading...
}
scrollableClassName="h-full"
scrollableContainerClassName="h-full"
/>
diff --git a/apps/playground-web/src/components/code/RenderCode.tsx b/apps/playground-web/src/components/code/RenderCode.tsx
deleted file mode 100644
index eb25d85786e..00000000000
--- a/apps/playground-web/src/components/code/RenderCode.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import { cn } from "../../lib/utils";
-import { CopyButton } from "../ui/CopyButton";
-import { ScrollShadow } from "../ui/ScrollShadow";
-
-export function RenderCode(props: {
- code: string;
- html: string;
- className?: string;
- scrollableClassName?: string;
- scrollableContainerClassName?: string;
-}) {
- return (
-
- );
-}
diff --git a/apps/playground-web/src/components/code/code-example.tsx b/apps/playground-web/src/components/code/code-example.tsx
index c102de5635d..1a196550de5 100644
--- a/apps/playground-web/src/components/code/code-example.tsx
+++ b/apps/playground-web/src/components/code/code-example.tsx
@@ -2,7 +2,7 @@ import { Code2Icon, EyeIcon } from "lucide-react";
import type { JSX } from "react";
import type { BundledLanguage } from "shiki";
import { ClientOnly } from "../ClientOnly";
-import { Code } from "./code";
+import { CodeServer } from "./code";
type CodeExampleProps = {
preview: JSX.Element;
@@ -35,7 +35,7 @@ export const CodeExample: React.FC
= ({
-
-
-
- );
-}
-
-export const CodeClient: React.FC
= ({
- code,
- lang,
- loader,
- className,
- scrollableClassName,
- scrollableContainerClassName,
-}) => {
- const codeQuery = useQuery({
- placeholderData: keepPreviousData,
- queryFn: () => getCodeHtml(code, lang),
- queryKey: ["html", code],
- });
-
- if (!codeQuery.data) {
- return loader;
- }
-
- return (
-
- );
-};
-
-/** @alias */
-export default CodeClient;
+export { CodeClient } from "@workspace/ui/components/code/code.client";
diff --git a/apps/playground-web/src/components/code/code.tsx b/apps/playground-web/src/components/code/code.tsx
index 1c87c58ee32..84234ad2a77 100644
--- a/apps/playground-web/src/components/code/code.tsx
+++ b/apps/playground-web/src/components/code/code.tsx
@@ -1,27 +1 @@
-import type { BundledLanguage } from "shiki";
-import { getCodeHtml } from "./getCodeHtml";
-import { RenderCode } from "./RenderCode";
-
-type CodeProps = {
- code: string;
- lang: BundledLanguage;
- className?: string;
- scrollableClassName?: string;
-};
-
-export const Code: React.FC = async ({
- code,
- lang,
- className,
- scrollableClassName,
-}) => {
- const { html, formattedCode } = await getCodeHtml(code, lang);
- return (
-
- );
-};
+export { CodeServer } from "@workspace/ui/components/code/code.server";
diff --git a/apps/playground-web/src/components/code/getCodeHtml.tsx b/apps/playground-web/src/components/code/getCodeHtml.tsx
deleted file mode 100644
index aa4e06784a5..00000000000
--- a/apps/playground-web/src/components/code/getCodeHtml.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import * as parserBabel from "prettier/plugins/babel";
-import { format } from "prettier/standalone";
-import { type BundledLanguage, codeToHtml } from "shiki";
-
-function isPrettierSupportedLang(lang: BundledLanguage) {
- return (
- lang === "js" ||
- lang === "jsx" ||
- lang === "ts" ||
- lang === "tsx" ||
- lang === "javascript" ||
- lang === "typescript"
- );
-}
-
-export async function getCodeHtml(code: string, lang: BundledLanguage) {
- const estreePlugin = await import("prettier/plugins/estree");
-
- const formattedCode = isPrettierSupportedLang(lang)
- ? await format(code, {
- parser: "babel-ts",
- plugins: [parserBabel, estreePlugin.default],
- printWidth: 80,
- }).catch(() => {
- return code;
- })
- : code;
-
- const html = await codeToHtml(formattedCode, {
- lang: lang,
- themes: {
- dark: "github-dark-default",
- light: "github-light",
- },
- });
-
- return { formattedCode, html };
-}
diff --git a/apps/playground-web/src/components/in-app-wallet/profiles.tsx b/apps/playground-web/src/components/in-app-wallet/profiles.tsx
index 329331f8644..74b803a8f19 100644
--- a/apps/playground-web/src/components/in-app-wallet/profiles.tsx
+++ b/apps/playground-web/src/components/in-app-wallet/profiles.tsx
@@ -3,7 +3,7 @@ import { baseSepolia } from "thirdweb/chains";
import { useActiveAccount, useLinkProfile, useProfiles } from "thirdweb/react";
import { createWallet, type WalletId } from "thirdweb/wallets";
import { THIRDWEB_CLIENT } from "../../lib/client";
-import CodeClient, { CodeLoading } from "../code/code.client";
+import { CodeClient } from "../code/code.client";
import { StyledConnectButton } from "../styled-connect-button";
import { Button } from "../ui/button";
@@ -20,7 +20,6 @@ export function LinkedAccounts() {
}
/>
) : (
diff --git a/apps/playground-web/src/components/ui/markdown-renderer.tsx b/apps/playground-web/src/components/ui/markdown-renderer.tsx
index e8f79a0be3f..ad83bbaedfe 100644
--- a/apps/playground-web/src/components/ui/markdown-renderer.tsx
+++ b/apps/playground-web/src/components/ui/markdown-renderer.tsx
@@ -13,7 +13,7 @@ import {
TableRow,
} from "@/components/ui/table";
import { cn } from "@/lib/utils";
-import CodeClient from "../code/code.client";
+import { CodeClient } from "../code/code.client";
export const MarkdownRenderer: React.FC<{
markdownText: string;
diff --git a/apps/portal/src/components/Document/APIEndpointMeta/DynamicRequestExample.tsx b/apps/portal/src/components/Document/APIEndpointMeta/DynamicRequestExample.tsx
index 5ae508c515c..b3f10319bd9 100644
--- a/apps/portal/src/components/Document/APIEndpointMeta/DynamicRequestExample.tsx
+++ b/apps/portal/src/components/Document/APIEndpointMeta/DynamicRequestExample.tsx
@@ -2,7 +2,7 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { useEffect, useState } from "react";
-import CodeClient, { CodeLoading } from "../../code/code.client";
+import { CodeClient } from "../../code/code.client";
import { Details } from "../Details";
import type { APIParameter } from "./ApiEndpoint";
import { RequestExample } from "./RequestExample";
@@ -59,7 +59,6 @@ function InlineParameterItem({ param }: { param: APIParameter }) {
}
className="rounded-none border-none"
lang="json"
- loader={}
scrollableContainerClassName="m-0"
scrollableClassName="max-h-[200px]"
/>
@@ -146,7 +145,6 @@ export function DynamicRequestExample(props: DynamicRequestExampleProps) {
}
scrollableContainerClassName="m-0"
lang={example.lang}
/>
@@ -166,7 +164,6 @@ export function DynamicRequestExample(props: DynamicRequestExampleProps) {
}
scrollableContainerClassName="m-0"
lang={selectedExample.lang}
/>
diff --git a/apps/portal/src/components/Document/AuthMethodsTabs.tsx b/apps/portal/src/components/Document/AuthMethodsTabs.tsx
index c0fd3fec1ab..1aa37d7032e 100644
--- a/apps/portal/src/components/Document/AuthMethodsTabs.tsx
+++ b/apps/portal/src/components/Document/AuthMethodsTabs.tsx
@@ -15,7 +15,7 @@ import {
UnrealEngineIcon,
} from "@/icons";
import { cn } from "@/lib/utils";
-import { CodeClient, CodeLoading } from "../code/code.client";
+import { CodeClient } from "../code/code.client";
type AuthMethod =
| "email"
@@ -927,7 +927,6 @@ function AuthMethodsTabsContent() {
? "csharp"
: "typescript"
}
- loader={}
className="text-sm"
/>
),
diff --git a/apps/portal/src/components/code/CodeBlockContainer.tsx b/apps/portal/src/components/code/CodeBlockContainer.tsx
deleted file mode 100644
index 90fec3dae8b..00000000000
--- a/apps/portal/src/components/code/CodeBlockContainer.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-"use client";
-
-import { CheckIcon, CopyIcon } from "lucide-react";
-import { ScrollShadow } from "@/components/ui/ScrollShadow"; // Adjusted path for portal
-import { useClipboard } from "@/hooks/useClipboard"; // Adjusted path for portal
-import { cn } from "@/lib/utils";
-import { Button } from "../ui/button"; // Adjusted path for portal
-
-export function CodeBlockContainer(props: {
- codeToCopy: string;
- children: React.ReactNode;
- className?: string;
- scrollableClassName?: string;
- scrollableContainerClassName?: string;
- copyButtonClassName?: string;
- shadowColor?: string;
- onCopy?: (code: string) => void;
-}) {
- const { hasCopied, onCopy: onClipboardCopy } = useClipboard(props.codeToCopy); // Renamed onCopy to avoid conflict
-
- return (
-
-
- {props.children}
-
-
-
-
- );
-}
diff --git a/apps/portal/src/components/code/RenderCode.tsx b/apps/portal/src/components/code/RenderCode.tsx
deleted file mode 100644
index 5b423ad6288..00000000000
--- a/apps/portal/src/components/code/RenderCode.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import { ScrollShadow } from "@/components/ui/ScrollShadow";
-import { cn } from "../../lib/utils";
-import { CopyButton } from "../ui/CopyButton";
-
-export function RenderCode(props: {
- code: string;
- html: string;
- className?: string;
- scrollableClassName?: string;
- scrollableContainerClassName?: string;
-}) {
- return (
-
- );
-}
diff --git a/apps/portal/src/components/code/code.client.tsx b/apps/portal/src/components/code/code.client.tsx
index e0ed9789863..89767cbe17c 100644
--- a/apps/portal/src/components/code/code.client.tsx
+++ b/apps/portal/src/components/code/code.client.tsx
@@ -1,57 +1,6 @@
-import { keepPreviousData, useQuery } from "@tanstack/react-query";
-import type { BundledLanguage } from "shiki";
-import { LoadingDots } from "../ui/LoadingDots";
-import { getCodeHtml } from "./getCodeHtml";
-import { RenderCode } from "./RenderCode";
+"use client";
-// Use CodeClient where the code changes based user input
-// Using RSC in that scenario feels too slow and unnecessary keep hitting the server
-
-type CodeProps = {
- code: string;
- lang: BundledLanguage | string | undefined | null;
- loader: React.ReactNode;
- className?: string;
- scrollableClassName?: string;
- scrollableContainerClassName?: string;
-};
-
-export function CodeLoading() {
- return (
-
-
-
- );
-}
-
-export const CodeClient: React.FC = ({
- code,
- lang,
- loader,
- className,
- scrollableClassName,
- scrollableContainerClassName,
-}) => {
- const codeQuery = useQuery({
- placeholderData: keepPreviousData,
- queryFn: () => getCodeHtml(code, lang),
- queryKey: ["html", code],
- });
-
- if (!codeQuery.data) {
- return loader;
- }
-
- return (
-
- );
-};
-
-/** @alias */
-export default CodeClient;
+export {
+ CodeClient,
+ type CodeProps,
+} from "@workspace/ui/components/code/code.client";
diff --git a/apps/portal/src/components/code/getCodeHtml.tsx b/apps/portal/src/components/code/getCodeHtml.tsx
deleted file mode 100644
index f083aee0126..00000000000
--- a/apps/portal/src/components/code/getCodeHtml.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import * as parserBabel from "prettier/plugins/babel";
-import { format } from "prettier/standalone";
-import { type BundledLanguage, codeToHtml } from "shiki";
-
-function isPrettierSupportedLang(
- lang: BundledLanguage | string | undefined | null,
-) {
- if (!lang) {
- return false;
- }
-
- return (
- lang === "js" ||
- lang === "jsx" ||
- lang === "ts" ||
- lang === "tsx" ||
- lang === "javascript" ||
- lang === "typescript"
- );
-}
-
-export async function getCodeHtml(
- code: string,
- lang: BundledLanguage | string | undefined | null,
-) {
- const estreePlugin = await import("prettier/plugins/estree");
-
- const formattedCode = isPrettierSupportedLang(lang)
- ? await format(code, {
- parser: "babel-ts",
- plugins: [parserBabel, estreePlugin.default],
- printWidth: 80,
- }).catch(() => {
- return code;
- })
- : code;
-
- const html = await codeToHtml(formattedCode, {
- lang: (lang || "javascript") as BundledLanguage,
- themes: {
- dark: "github-dark-default",
- light: "github-light",
- },
- });
-
- return { formattedCode, html };
-}
diff --git a/apps/portal/src/components/code/plaintext-code.tsx b/apps/portal/src/components/code/plaintext-code.tsx
index f85a5099741..12a0e83743b 100644
--- a/apps/portal/src/components/code/plaintext-code.tsx
+++ b/apps/portal/src/components/code/plaintext-code.tsx
@@ -1,29 +1 @@
-import { cn } from "@/lib/utils"; // Adjusted path for portal
-import { CodeBlockContainer } from "./CodeBlockContainer"; // Path within portal/components/code
-
-export function PlainTextCodeBlock(props: {
- code: string;
- copyButtonClassName?: string;
- className?: string;
- scrollableClassName?: string;
- codeClassName?: string;
- scrollableContainerClassName?: string;
- shadowColor?: string;
- onCopy?: (code: string) => void;
-}) {
- return (
-
-
- {props.code}
-
-
- );
-}
+export { PlainTextCodeBlock } from "@workspace/ui/components/code/plaintext-code";
diff --git a/apps/portal/src/components/markdown/MarkdownRenderer.tsx b/apps/portal/src/components/markdown/MarkdownRenderer.tsx
index f97421bd289..a611fc9ef02 100644
--- a/apps/portal/src/components/markdown/MarkdownRenderer.tsx
+++ b/apps/portal/src/components/markdown/MarkdownRenderer.tsx
@@ -1,8 +1,7 @@
import { onlyText } from "react-children-utilities"; // Assuming this dependency is available
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm"; // Assuming this dependency is available
-import type { BundledLanguage } from "shiki"; // For CodeClient lang prop
-import { CodeClient, CodeLoading } from "@/components/code/code.client"; // Adjusted path for portal
+import { CodeClient, type CodeProps } from "@/components/code/code.client"; // Adjusted path for portal
import { PlainTextCodeBlock } from "@/components/code/plaintext-code"; // Adjusted path for portal
import { InlineCode } from "@/components/ui/inline-code"; // Adjusted path for portal
import {
@@ -85,18 +84,14 @@ export const MarkdownRenderer: React.FC<{
);
}
- const language = inheritedClassName.replace(
- "language-",
- "",
- ) as BundledLanguage;
+ const language = inheritedClassName.replace("language-", "");
+
return (
} // Basic loader
/>
);
diff --git a/apps/portal/src/components/ui/CopyButton.tsx b/apps/portal/src/components/ui/CopyButton.tsx
deleted file mode 100644
index 933ded9f6c9..00000000000
--- a/apps/portal/src/components/ui/CopyButton.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-"use client";
-
-import { CheckIcon, CopyIcon } from "lucide-react";
-import { cn } from "@/lib/utils";
-import { useClipboard } from "../../hooks/useClipboard";
-import { Button } from "./button";
-import { ToolTipLabel } from "./tooltip";
-
-export function CopyButton(props: {
- text: string;
- className?: string;
- iconClassName?: string;
- variant?: "ghost" | "primary" | "secondary";
-}) {
- const { hasCopied, onCopy } = useClipboard(props.text, 1000);
- return (
-
-
-
- );
-}
diff --git a/packages/ui/package.json b/packages/ui/package.json
index b07a58afcb9..051da1fea0a 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -11,7 +11,11 @@
"./src/hooks/*.ts",
"./src/hooks/*.tsx"
],
- "./components/*": "./src/components/*.tsx"
+ "./components/*": "./src/components/*.tsx",
+ "./storybook/*": [
+ "./src/storybook/*.tsx",
+ "./src/storybook/*.ts"
+ ]
},
"dependencies": {
"@radix-ui/react-label": "^2.1.7",
@@ -23,12 +27,15 @@
"lucide-react": "0.525.0",
"next": "15.3.5",
"next-themes": "^0.4.6",
+ "prettier": "3.6.2",
+ "shiki": "1.27.0",
"sonner": "2.0.6",
"tailwind-merge": "^2.6.0",
"tailwindcss-animate": "^1.0.7"
},
"scripts": {
- "storybook": "storybook dev -p 6006"
+ "storybook": "storybook dev -p 6006",
+ "typecheck": "tsc --noEmit"
},
"peerDependencies": {
"react": "^19.0.0",
diff --git a/packages/ui/src/components/badge.tsx b/packages/ui/src/components/badge.tsx
index c1f5874fe11..7825e467076 100644
--- a/packages/ui/src/components/badge.tsx
+++ b/packages/ui/src/components/badge.tsx
@@ -1,8 +1,7 @@
+import { cn } from "@workspace/ui/lib/utils";
import { cva, type VariantProps } from "class-variance-authority";
import type * as React from "react";
-import { cn } from "@/lib/utils";
-
const badgeVariants = cva(
"inline-flex items-center rounded-full border border-border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 leading-4",
{
diff --git a/packages/ui/src/components/breadcrumb.tsx b/packages/ui/src/components/breadcrumb.tsx
index 60e4b7848a3..49ea7cde5c1 100644
--- a/packages/ui/src/components/breadcrumb.tsx
+++ b/packages/ui/src/components/breadcrumb.tsx
@@ -1,9 +1,8 @@
import { Slot } from "@radix-ui/react-slot";
+import { cn } from "@workspace/ui/lib/utils";
import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react";
import * as React from "react";
-import { cn } from "@/lib/utils";
-
const Breadcrumb = React.forwardRef<
HTMLElement,
React.ComponentPropsWithoutRef<"nav"> & {
diff --git a/packages/ui/src/components/button.stories.tsx b/packages/ui/src/components/button.stories.tsx
index c5da13a84ec..7b8052ca9ea 100644
--- a/packages/ui/src/components/button.stories.tsx
+++ b/packages/ui/src/components/button.stories.tsx
@@ -1,7 +1,7 @@
import type { Meta, StoryObj } from "@storybook/nextjs";
+import { Button } from "@workspace/ui/components/button";
+import { BadgeContainer } from "@workspace/ui/storybook/utils";
import { StarIcon } from "lucide-react";
-import { Button } from "@/components/button";
-import { BadgeContainer } from "@/storybook/utils";
const meta = {
component: Component,
diff --git a/packages/ui/src/components/button.tsx b/packages/ui/src/components/button.tsx
index bc6b1f07433..0510f6b09d3 100644
--- a/packages/ui/src/components/button.tsx
+++ b/packages/ui/src/components/button.tsx
@@ -1,7 +1,7 @@
import { Slot } from "@radix-ui/react-slot";
+import { cn } from "@workspace/ui/lib/utils";
import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
-import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
diff --git a/apps/dashboard/src/@/components/ui/code/CodeBlockContainer.tsx b/packages/ui/src/components/code/CodeBlockContainer.tsx
similarity index 87%
rename from apps/dashboard/src/@/components/ui/code/CodeBlockContainer.tsx
rename to packages/ui/src/components/code/CodeBlockContainer.tsx
index 9aa752d9f4b..420766225c1 100644
--- a/apps/dashboard/src/@/components/ui/code/CodeBlockContainer.tsx
+++ b/packages/ui/src/components/code/CodeBlockContainer.tsx
@@ -1,10 +1,10 @@
"use client";
+import { useClipboard } from "@workspace/ui/hooks/useClipboard";
+import { cn } from "@workspace/ui/lib/utils";
import { CheckIcon, CopyIcon } from "lucide-react";
-import { Button } from "@/components/ui/button";
-import { ScrollShadow } from "@/components/ui/ScrollShadow";
-import { useClipboard } from "@/hooks/useClipboard";
-import { cn } from "@/lib/utils";
+import { Button } from "../button";
+import { ScrollShadow } from "../scroll-shadow";
export function CodeBlockContainer(props: {
codeToCopy: string;
diff --git a/apps/dashboard/src/@/components/ui/code/RenderCode.tsx b/packages/ui/src/components/code/RenderCode.tsx
similarity index 100%
rename from apps/dashboard/src/@/components/ui/code/RenderCode.tsx
rename to packages/ui/src/components/code/RenderCode.tsx
diff --git a/packages/ui/src/components/code/code.client.tsx b/packages/ui/src/components/code/code.client.tsx
new file mode 100644
index 00000000000..a56b4ba6543
--- /dev/null
+++ b/packages/ui/src/components/code/code.client.tsx
@@ -0,0 +1,71 @@
+"use client";
+import { keepPreviousData, useQuery } from "@tanstack/react-query";
+import type { BundledLanguage } from "shiki";
+import { getCodeHtml } from "./getCodeHtml";
+import { PlainTextCodeBlock } from "./plaintext-code";
+import { RenderCode } from "./RenderCode";
+
+export type CodeProps = {
+ code: string;
+ lang: BundledLanguage;
+ className?: string;
+ scrollableClassName?: string;
+ keepPreviousDataOnCodeChange?: boolean;
+ copyButtonClassName?: string;
+ scrollableContainerClassName?: string;
+ shadowColor?: string;
+ ignoreFormattingErrors?: boolean;
+ onCopy?: (code: string) => void;
+};
+
+export const CodeClient: React.FC = ({
+ code,
+ lang,
+ className,
+ scrollableClassName,
+ keepPreviousDataOnCodeChange = false,
+ copyButtonClassName,
+ ignoreFormattingErrors,
+ scrollableContainerClassName,
+ shadowColor,
+ onCopy,
+}) => {
+ const codeQuery = useQuery({
+ placeholderData: keepPreviousDataOnCodeChange
+ ? keepPreviousData
+ : undefined,
+ queryFn: () =>
+ getCodeHtml(code, lang, {
+ ignoreFormattingErrors: ignoreFormattingErrors,
+ }),
+ queryKey: ["html", code],
+ retry: false,
+ });
+
+ if (!codeQuery.data) {
+ return (
+
+ );
+ }
+
+ return (
+
+ );
+};
diff --git a/packages/ui/src/components/code/code.server.tsx b/packages/ui/src/components/code/code.server.tsx
new file mode 100644
index 00000000000..82a87a4e8d0
--- /dev/null
+++ b/packages/ui/src/components/code/code.server.tsx
@@ -0,0 +1,22 @@
+import type { BundledLanguage } from "shiki";
+import { getCodeHtml } from "./getCodeHtml";
+import { RenderCode } from "./RenderCode";
+
+export type CodeProps = {
+ code: string;
+ lang: BundledLanguage;
+ className?: string;
+ ignoreFormattingErrors?: boolean;
+};
+
+export const CodeServer: React.FC = async ({
+ code,
+ lang,
+ className,
+ ignoreFormattingErrors,
+}) => {
+ const { html, formattedCode } = await getCodeHtml(code, lang, {
+ ignoreFormattingErrors,
+ });
+ return ;
+};
diff --git a/apps/dashboard/src/@/components/ui/code/code.stories.tsx b/packages/ui/src/components/code/code.stories.tsx
similarity index 96%
rename from apps/dashboard/src/@/components/ui/code/code.stories.tsx
rename to packages/ui/src/components/code/code.stories.tsx
index 6c134227fc2..dbcf86e7d00 100644
--- a/apps/dashboard/src/@/components/ui/code/code.stories.tsx
+++ b/packages/ui/src/components/code/code.stories.tsx
@@ -1,11 +1,11 @@
import type { Meta, StoryObj } from "@storybook/nextjs";
-import { BadgeContainer } from "@/storybook/utils";
+import { BadgeContainer } from "@workspace/ui/storybook/utils";
import { CodeClient } from "./code.client";
const meta = {
component: Component,
parameters: {},
- title: "code/lang",
+ title: "ui/code/lang",
} satisfies Meta;
export default meta;
diff --git a/apps/dashboard/src/@/components/ui/code/getCodeHtml.tsx b/packages/ui/src/components/code/getCodeHtml.tsx
similarity index 100%
rename from apps/dashboard/src/@/components/ui/code/getCodeHtml.tsx
rename to packages/ui/src/components/code/getCodeHtml.tsx
diff --git a/apps/dashboard/src/@/components/ui/code/plaintext-code.stories.tsx b/packages/ui/src/components/code/plaintext-code.stories.tsx
similarity index 92%
rename from apps/dashboard/src/@/components/ui/code/plaintext-code.stories.tsx
rename to packages/ui/src/components/code/plaintext-code.stories.tsx
index 00064cba244..a57249d3345 100644
--- a/apps/dashboard/src/@/components/ui/code/plaintext-code.stories.tsx
+++ b/packages/ui/src/components/code/plaintext-code.stories.tsx
@@ -1,11 +1,11 @@
import type { Meta, StoryObj } from "@storybook/nextjs";
-import { BadgeContainer } from "@/storybook/utils";
+import { BadgeContainer } from "@workspace/ui/storybook/utils";
import { PlainTextCodeBlock } from "./plaintext-code";
const meta = {
component: Component,
parameters: {},
- title: "code/plaintext",
+ title: "ui/code/plaintext",
} satisfies Meta;
export default meta;
diff --git a/packages/ui/src/components/code/plaintext-code.tsx b/packages/ui/src/components/code/plaintext-code.tsx
new file mode 100644
index 00000000000..b48eb11820e
--- /dev/null
+++ b/packages/ui/src/components/code/plaintext-code.tsx
@@ -0,0 +1,29 @@
+import { cn } from "@workspace/ui/lib/utils";
+import { CodeBlockContainer } from "./CodeBlockContainer";
+
+export function PlainTextCodeBlock(props: {
+ code: string;
+ copyButtonClassName?: string;
+ className?: string;
+ scrollableClassName?: string;
+ codeClassName?: string;
+ scrollableContainerClassName?: string;
+ shadowColor?: string;
+ onCopy?: (code: string) => void;
+}) {
+ return (
+
+
+ {props.code}
+
+
+ );
+}
diff --git a/packages/ui/src/components/img.stories.tsx b/packages/ui/src/components/img.stories.tsx
index f22d14f17fe..243172d0306 100644
--- a/packages/ui/src/components/img.stories.tsx
+++ b/packages/ui/src/components/img.stories.tsx
@@ -1,8 +1,8 @@
import type { Meta, StoryObj } from "@storybook/nextjs";
+import { Button } from "@workspace/ui/components/button";
+import { BadgeContainer } from "@workspace/ui/storybook/utils";
import { ImageIcon, Loader2 } from "lucide-react";
import { useState } from "react";
-import { Button } from "@/components/button";
-import { BadgeContainer } from "@/storybook/utils";
import { Img } from "./img";
const meta = {
diff --git a/packages/ui/src/components/img.tsx b/packages/ui/src/components/img.tsx
index a7d5ec44fef..4a31e260994 100644
--- a/packages/ui/src/components/img.tsx
+++ b/packages/ui/src/components/img.tsx
@@ -1,6 +1,6 @@
"use client";
+import { cn } from "@workspace/ui/lib/utils";
import { useLayoutEffect, useRef, useState } from "react";
-import { cn } from "@/lib/utils";
type imgElementProps = React.DetailedHTMLProps<
React.ImgHTMLAttributes,
diff --git a/packages/ui/src/components/input.tsx b/packages/ui/src/components/input.tsx
index 465f5065cc7..73c16bed777 100644
--- a/packages/ui/src/components/input.tsx
+++ b/packages/ui/src/components/input.tsx
@@ -1,5 +1,5 @@
+import { cn } from "@workspace/ui/lib/utils";
import * as React from "react";
-import { cn } from "@/lib/utils";
export interface InputProps
extends React.InputHTMLAttributes {}
diff --git a/packages/ui/src/components/scroll-shadow.tsx b/packages/ui/src/components/scroll-shadow.tsx
index 4a1b6919637..6a6e2bfae72 100644
--- a/packages/ui/src/components/scroll-shadow.tsx
+++ b/packages/ui/src/components/scroll-shadow.tsx
@@ -1,7 +1,7 @@
"use client";
+import { cn } from "@workspace/ui/lib/utils";
import { useLayoutEffect, useRef } from "react";
-import { cn } from "@/lib/utils";
export function ScrollShadow(props: {
children: React.ReactNode;
diff --git a/packages/ui/src/components/spinner.tsx b/packages/ui/src/components/spinner.tsx
index 59d26e79e9e..eb51b6c52e1 100644
--- a/packages/ui/src/components/spinner.tsx
+++ b/packages/ui/src/components/spinner.tsx
@@ -1,4 +1,4 @@
-import { cn } from "@/lib/utils";
+import { cn } from "@workspace/ui/lib/utils";
export function Spinner(props: { className?: string }) {
return (
diff --git a/packages/ui/src/components/table.stories.tsx b/packages/ui/src/components/table.stories.tsx
index c6a8acfed29..54c4d43e700 100644
--- a/packages/ui/src/components/table.stories.tsx
+++ b/packages/ui/src/components/table.stories.tsx
@@ -1,7 +1,7 @@
import type { Meta, StoryObj } from "@storybook/nextjs";
+import { cn } from "@workspace/ui/lib/utils";
+import { BadgeContainer } from "@workspace/ui/storybook/utils";
import Link from "next/link";
-import { cn } from "@/lib/utils";
-import { BadgeContainer } from "@/storybook/utils";
import { Badge } from "./badge";
import {
Table,
diff --git a/packages/ui/src/components/table.tsx b/packages/ui/src/components/table.tsx
index cd575926071..61bea7750a6 100644
--- a/packages/ui/src/components/table.tsx
+++ b/packages/ui/src/components/table.tsx
@@ -1,5 +1,5 @@
+import { cn } from "@workspace/ui/lib/utils";
import * as React from "react";
-import { cn } from "@/lib/utils";
import { ScrollShadow } from "./scroll-shadow";
const Table = React.forwardRef<
diff --git a/packages/ui/src/components/tooltip.tsx b/packages/ui/src/components/tooltip.tsx
index 687bfe4fac7..b03614e0d75 100644
--- a/packages/ui/src/components/tooltip.tsx
+++ b/packages/ui/src/components/tooltip.tsx
@@ -1,10 +1,9 @@
"use client";
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
+import { cn } from "@workspace/ui/lib/utils";
import * as React from "react";
-import { cn } from "@/lib/utils";
-
const TooltipProvider = TooltipPrimitive.Provider;
const Tooltip = TooltipPrimitive.Root;
diff --git a/apps/portal/src/hooks/useClipboard.ts b/packages/ui/src/hooks/useClipboard.ts
similarity index 100%
rename from apps/portal/src/hooks/useClipboard.ts
rename to packages/ui/src/hooks/useClipboard.ts
diff --git a/packages/ui/src/storybook/utils.tsx b/packages/ui/src/storybook/utils.tsx
index 9915d675562..6b9939579ec 100644
--- a/packages/ui/src/storybook/utils.tsx
+++ b/packages/ui/src/storybook/utils.tsx
@@ -1,4 +1,4 @@
-import { Badge } from "@/components/badge";
+import { Badge } from "@workspace/ui/components/badge";
function StoryBadge(props: { label: string }) {
return (
diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json
index 59179be8a91..6f1963e3014 100644
--- a/packages/ui/tsconfig.json
+++ b/packages/ui/tsconfig.json
@@ -18,10 +18,7 @@
"noUncheckedIndexedAccess": true,
"resolveJsonModule": true,
"baseUrl": ".",
- "jsx": "preserve",
- "paths": {
- "@/*": ["./src/*"]
- }
+ "jsx": "preserve"
},
"include": ["src"],
"exclude": ["node_modules"]
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index eea6f78e480..7201bdc4fe2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1504,12 +1504,18 @@ importers:
next-themes:
specifier: ^0.4.6
version: 0.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ prettier:
+ specifier: 3.6.2
+ version: 3.6.2
react:
specifier: ^19.0.0
version: 19.1.0
react-dom:
specifier: ^19.0.0
version: 19.1.0(react@19.1.0)
+ shiki:
+ specifier: 1.27.0
+ version: 1.27.0
sonner:
specifier: 2.0.6
version: 2.0.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)