Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
34 changes: 34 additions & 0 deletions docs/app/docs/components/link/docs/codeUsage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Import API documentation
import link_api_SourceCode from './component_api/link.tsx';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid importing a .tsx file with an explicit extension from JS.

This can trip bundlers/linters; resolve by omitting the extension (or convert this file to TS).

-import link_api_SourceCode from './component_api/link.tsx';
+import linkApi from './component_api/link';

Also update the reference below:

-export const api_documentation = {
-    link: link_api_SourceCode,
-};
+export const api_documentation = { link: linkApi };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import link_api_SourceCode from './component_api/link.tsx';
// docs/app/docs/components/link/docs/codeUsage.js
import linkApi from './component_api/link';
-export const api_documentation = {
- link: link_api_SourceCode,
export const api_documentation = {
link: linkApi,
};
🤖 Prompt for AI Agents
In docs/app/docs/components/link/docs/codeUsage.js around line 2, the file
currently imports a .tsx file with an explicit extension which can break
bundlers/linters; change the import to omit the extension (import from
'./component_api/link' instead of './component_api/link.tsx') and update the
downstream reference(s) in this file that expect the original import name/path
so they point to the new import (ensure variable names remain correct and update
any string/path usages that included the .tsx extension).


const code = {
javascript: {
code: `import Link from "@radui/ui/Link"
const LinkExample = () => (
<Link href="https://rad-ui.com" target="_blank">Rad UI</Link>
)`
},
Comment on lines +6 to +11
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Align code and SCSS; add rel for target="_blank".

Sample uses .rad-ui-link styles but the element lacked that class. Also add rel for security.

-        code: `import Link from "@radui/ui/Link"
-
-const LinkExample = () => (
-    <Link href="https://rad-ui.com" target="_blank">Rad UI</Link>
-)
+        code: `import Link from "@radui/ui/Link"
+
+const LinkExample = () => (
+    <Link className="rad-ui-link" href="https://rad-ui.com" target="_blank" rel="noopener noreferrer">
+      Rad UI
+    </Link>
+) 
 `
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
code: `import Link from "@radui/ui/Link"
const LinkExample = () => (
<Link href="https://rad-ui.com" target="_blank">Rad UI</Link>
)`
},
code: `import Link from "@radui/ui/Link"
const LinkExample = () => (
<Link className="rad-ui-link" href="https://rad-ui.com" target="_blank" rel="noopener noreferrer">
Rad UI
</Link>
)`
🤖 Prompt for AI Agents
In docs/app/docs/components/link/docs/codeUsage.js around lines 6 to 11, the
sample JSX uses the .rad-ui-link SCSS but the rendered Link lacks that class and
also misses the security rel when using target="_blank"; update the example so
the Link includes className="rad-ui-link" and add rel="noopener noreferrer"
alongside target="_blank" so styles and security are aligned.

scss: {
code: `.rad-ui-link{
color: var(--rad-ui-color-indigo-900);
}
.rad-ui-link:hover{
text-decoration: underline;
}`
},
};

// API documentation
export const api_documentation = {
link: link_api_SourceCode,
};

// Component features
export const features = [
"Supports external and internal navigation",
"Adjustable sizes",
"Accessible keyboard navigation",
];

export default code;
62 changes: 62 additions & 0 deletions docs/app/docs/components/link/docs/component_api/link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const data = {
name: "Link",
description: "Hyperlink component for navigation between pages or external resources.",
columns: [
{
name: "Prop",
id: "prop",
},
{
name: "Type",
id: "type",
},
{
name: "Default",
id: "default",
}
],
data: [
{
prop: {
name: "href",
info_tooltips: "Destination URL for the link.",
},
type: "string",
default: "--",
},
{
prop: {
name: "children",
info_tooltips: "Link text or element.",
},
type: "ReactNode",
default: "--",
},
{
prop: {
name: "target",
info_tooltips: "Where to open the linked document.",
},
type: "string",
default: "'_self'",
},
{
prop: {
name: "size",
info_tooltips: "Visual size of the link.",
},
type: "string",
default: "'medium'",
},
{
prop: {
name: "className",
info_tooltips: "Additional CSS class names.",
},
type: "string",
default: "''",
}
]
};

export default data;
13 changes: 13 additions & 0 deletions docs/app/docs/components/link/examples/LinkExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Link from "@radui/ui/Link";

const LinkExample = () => {
return (
<div className="text-gray-1000">
<Link href="https://rad-ui.com" target="_blank">
Visit Rad UI
</Link>
</div>
);
};

export default LinkExample;
44 changes: 44 additions & 0 deletions docs/app/docs/components/link/page.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Documentation from '@/components/layout/Documentation/Documentation';
import Link from '@radui/ui/Link';
import codeUsage, { api_documentation, features } from './docs/codeUsage';
import LinkExample from './examples/LinkExample';
import linkMetadata from './seo';

export const metadata = linkMetadata;

<Documentation
title="Link"
description="Link navigates users to different pages or external resources."
>
{/* Component Hero */}
<Documentation.ComponentHero codeUsage={codeUsage}>
<LinkExample />
</Documentation.ComponentHero>

{/* Component Features */}
<Documentation.ComponentFeatures
features={features}
/>

{/* Embedded Storybook */}
<Documentation.Section title="Storybook" as="h2">
<iframe
src="/storybook/iframe.html?id=components-link--all"
className="w-full h-96 border rounded"
/>
</Documentation.Section>

{/* Accessibility */}
<Documentation.Section title="Accessibility" as="h2">
<p>Links are focusable and support keyboard navigation. Ensure link text clearly describes the destination.</p>
</Documentation.Section>

{/* API Documentation */}
<Documentation.Section title="API Documentation" as="h2" />
<Documentation.Table
title="Link"
description={api_documentation.link.description}
columns={api_documentation.link.columns}
data={api_documentation.link.data}
/>
</Documentation>
Comment on lines +37 to +44
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Wrap the API table inside the Section (layout/spacing & anchor semantics).

-  {/* API Documentation */}
-  <Documentation.Section title="API Documentation" as="h2" />
-  <Documentation.Table
-    title="Link"
-    description={api_documentation.link.description}
-    columns={api_documentation.link.columns}
-    data={api_documentation.link.data}
-  />
+  {/* API Documentation */}
+  <Documentation.Section title="API Documentation" as="h2">
+    <Documentation.Table
+      title="Link"
+      description={api_documentation.link.description}
+      columns={api_documentation.link.columns}
+      data={api_documentation.link.data}
+    />
+  </Documentation.Section>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Documentation.Section title="API Documentation" as="h2" />
<Documentation.Table
title="Link"
description={api_documentation.link.description}
columns={api_documentation.link.columns}
data={api_documentation.link.data}
/>
</Documentation>
{/* API Documentation */}
<Documentation.Section title="API Documentation" as="h2">
<Documentation.Table
title="Link"
description={api_documentation.link.description}
columns={api_documentation.link.columns}
data={api_documentation.link.data}
/>
</Documentation.Section>
🤖 Prompt for AI Agents
In docs/app/docs/components/link/page.mdx around lines 37 to 44, the
Documentation.Table is currently rendered outside the Documentation.Section
causing layout, spacing and anchor issues; move the Documentation.Table so it is
a child of the Documentation.Section (place the Table between the Section's
opening and closing tags) and adjust the surrounding tags so the Section
encapsulates the title and the table content.

8 changes: 8 additions & 0 deletions docs/app/docs/components/link/seo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import generateSeoMetadata from "@/utils/seo/generateSeoMetadata";

const linkMetadata = generateSeoMetadata({
title: "Link - Rad UI",
description: "Accessible hyperlink component for navigation and external resources.",
});

export default linkMetadata;
10 changes: 10 additions & 0 deletions docs/app/docs/docsNavigationSections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ export const docsNavigationSections = [
{
title:"Accessibility",
path:"/docs/guides/accessibility"
},
{
title:"Migration Guide",
path:"/docs/guides/migration",
is_new:true
}
]
},
Expand Down Expand Up @@ -89,6 +94,11 @@ export const docsNavigationSections = [
title:"Heading",
path:"/docs/components/heading"
},
{
title:"Link",
path:"/docs/components/link",
is_new:true
},
{
title:"Text",
path:"/docs/components/text"
Expand Down
26 changes: 26 additions & 0 deletions docs/app/docs/guides/migration/page.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Documentation from '@/components/layout/Documentation/Documentation';
import migrationMetadata from './seo';

export const metadata = migrationMetadata;

<Documentation
title="Migration Guide"
description="Compare Rad UI with other libraries and learn best practices for adopting it."
>
<Documentation.Section title="Migrating from Other Libraries" as="h2">
<h3>Radix UI</h3>
<p>Rad UI ships with pre-styled components while Radix UI offers unstyled primitives. When migrating, replace Radix primitives with their Rad UI counterparts and remove custom styling where possible.</p>
<h3>Base UI</h3>
<p>Base UI centers around Material Design. Rad UI is design‑system agnostic, so migrate by mapping Base UI components to Rad UI and adjusting theme tokens.</p>
<h3>Ark UI</h3>
<p>Ark UI emphasizes composability. Rad UI provides similar accessibility guarantees with a more opinionated API, making migrations largely drop‑in.</p>
</Documentation.Section>

<Documentation.Section title="Best Practices" as="h2">
<ul>
<li>Leverage Rad UI's accessible defaults before customizing.</li>
<li>Prefer composable components for flexibility.</li>
<li>Keep markup semantic and keyboard friendly.</li>
</ul>
</Documentation.Section>
</Documentation>
8 changes: 8 additions & 0 deletions docs/app/docs/guides/migration/seo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import generateSeoMetadata from "@/utils/seo/generateSeoMetadata";

const migrationMetadata = generateSeoMetadata({
title: "Migration Guide - Rad UI",
description: "Guidance for migrating to Rad UI and best practices compared with Radix, Base UI, and Ark UI.",
});

export default migrationMetadata;
12 changes: 7 additions & 5 deletions docs/components/docsHelpers/EditPageOnGithub.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ const EditPageOnGithub = () => {

const currentDocsPath = "docs/app/docs/" + page;

return (
<div className="w-full max-w-screen-lg mx-auto mt-2 py-[20px]">
<Link href={`https://github.com/rad-ui/rad-ui/edit/main/${currentDocsPath}/page.mdx`}>Edit this page on GitHub</Link>
</div>
);
return (
<div className="w-full max-w-screen-lg mx-auto mt-2 py-[20px]">
<Link href={`https://github.com/rad-ui/rad-ui/edit/main/${currentDocsPath}/page.mdx`}>
Edit on GitHub
</Link>
</div>
);
};

export default EditPageOnGithub;
90 changes: 60 additions & 30 deletions docs/components/navigation/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { usePathname } from 'next/navigation';
import { useContext, useEffect, useState } from 'react';

import { NavBarContext } from '@/components/Main/NavBar/NavBarContext';
import docsSections from "@/app/docs/docsNavigationSections"
import ScrollArea from "@radui/ui/ScrollArea"
import Category from './Category'
import docsSections from "@/app/docs/docsNavigationSections";
import ScrollArea from "@radui/ui/ScrollArea";
import Category from './Category';



Expand All @@ -26,42 +26,72 @@ const Navigation = ({ customSections }: { customSections?: any }) => {
const pathname = usePathname();
const { setIsDocsNavOpen } = useContext(NavBarContext) as { isDocsNavOpen: boolean, setIsDocsNavOpen: (isDocsNavOpen: boolean) => void };

const [sections, setSections] = useState(docsSections)
const [sections, setSections] = useState(docsSections);
const [query, setQuery] = useState("");
const versions = ["0.0.47", "0.0.46"];
const [version, setVersion] = useState(versions[0]);
// customSections || sections;
Comment on lines +29 to 33
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Initialize sections based on pathname to avoid UI flash; respect customSections

On non-docs routes, sections initially show docsSections until useEffect runs. Also, customSections is ignored. Initialize from pathname and prefer customSections when provided.

-    const [sections, setSections] = useState(docsSections);
+    const [sections, setSections] = useState(
+      (customSections ?? (pathname.includes("/docs/") ? docsSections : defaultSections))
+    );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const [sections, setSections] = useState(docsSections);
const [query, setQuery] = useState("");
const versions = ["0.0.47", "0.0.46"];
const [version, setVersion] = useState(versions[0]);
// customSections || sections;
const [sections, setSections] = useState(
(customSections ?? (pathname.includes("/docs/") ? docsSections : defaultSections))
);
const [query, setQuery] = useState("");
const versions = ["0.0.47", "0.0.46"];
const [version, setVersion] = useState(versions[0]);
// customSections || sections;
🤖 Prompt for AI Agents
In docs/components/navigation/Navigation.tsx around lines 29-33, the sections
state is always initialized to docsSections and ignores customSections which
causes a UI flash on non-docs routes; update the initial state logic to pick the
correct source based on the current pathname and prefer customSections when
provided (e.g., if pathname indicates docs use docsSections, otherwise use an
empty or non-docs default), and set useState to compute the initial sections
from pathname and customSections so the component renders the correct menu
immediately without waiting for useEffect.


useEffect(() => {
if (pathname.includes("/docs/")) {
setSections(docsSections)
}
else {
setSections(defaultSections)
}
}, [pathname])
setSections(defaultSections)
}
}, [pathname])
const filteredSections = sections
Comment on lines +40 to +43
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Effect should handle customSections and unify selection logic

Prefer customSections when present; otherwise pick based on pathname. Add customSections to deps.

-      }, [pathname])
+      }, [pathname, customSections])

And replace the effect body with:

useEffect(() => {
  if (customSections) {
    setSections(customSections);
    return;
  }
  setSections(pathname.includes("/docs/") ? docsSections : defaultSections);
}, [pathname, customSections]);
🤖 Prompt for AI Agents
In docs/components/navigation/Navigation.tsx around lines 40 to 43, the effect
currently only reacts to pathname and always falls back to defaultSections,
ignoring customSections and failing to include customSections in the dependency
array; change the effect to prefer customSections when present and to set
sections accordingly (use customSections if truthy, otherwise set docsSections
when pathname includes "/docs/" or defaultSections otherwise), and add
customSections to the dependency array so the effect runs when customSections
changes.

.map(section => ({
...section,
items: section.items.filter((item: any) =>
item.title.toLowerCase().includes(query.toLowerCase())
),
}))
.filter(section => section.items.length > 0);

return <ScrollArea.Root>
<ScrollArea.Viewport style={{ height: "100%" }}>
<div className="min-w-[240px]">
<div className="p-4 flex flex-col gap-2">
<input
aria-label="Search documentation"
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search..."
className="px-2 py-1 text-sm rounded border"
/>
<select
aria-label="Select docs version"
value={version}
onChange={(e) => setVersion(e.target.value)}
className="px-2 py-1 text-sm rounded border"
>
{versions.map(v => (
<option key={v} value={v}>{v}</option>
))}
</select>
</div>
<div className='flex-none pb-20 w-full lg:w-[240px] lg:bg-transparent'>
{filteredSections.map((section, i) => {
const isCategory = section.type === "CATEGORY";
if (isCategory) {
return <Category key={i} categoryItem={section} pathname={pathname} setIsDocsNavOpen={setIsDocsNavOpen} />
}
else{
return <div key={i} className='h-10 w-full bg-gray-100'>
Hello
</div>
}
})}
</div>
</div>

return <ScrollArea.Root>
<ScrollArea.Viewport style={{ height: "100%" }}>
<div className="min-w-[240px]">
<div className='flex-none pb-20 w-full lg:w-[240px] lg:bg-transparent'>
{sections.map((section, i) => {
const isCategory = section.type === "CATEGORY";
if (isCategory) {
return <Category key={i} categoryItem={section} pathname={pathname} setIsDocsNavOpen={setIsDocsNavOpen} />
}
else{
return <div key={i} className='h-10 w-full bg-gray-100'>
Hello
</div>
}
})}
</div>
</div>

</ScrollArea.Viewport>
<ScrollArea.Scrollbar orientation='vertical' >
<ScrollArea.Thumb />
</ScrollArea.Scrollbar>
</ScrollArea.Root>
</ScrollArea.Viewport>
<ScrollArea.Scrollbar orientation='vertical' >
<ScrollArea.Thumb />
</ScrollArea.Scrollbar>
</ScrollArea.Root>


}
Expand Down
Loading