Skip to content
Merged
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
9 changes: 7 additions & 2 deletions docs/app/docs/first-steps/installation/content.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ Getting started with Rad UI is simple and quick! Whether you're integrating it i

## Install via npm


If you use npm, run the following command to install Rad UI:

```bash
npm install @radui/ui --save
<MultipleTabs items={[
{ manager: 'pnpm', command: 'pnpm install @radui/ui' },
{ manager: 'npm', command: 'npm install @radui/ui --save' },
{ manager: 'yarn', command: 'yarn add @radui/ui' },
{ manager: 'bun', command: 'bun add @radui/ui' },
]} />
121 changes: 121 additions & 0 deletions docs/components/mdx/MultipleTabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
"use client";
import React, { useRef, useState } from 'react';
import CodeBlock from '@/components/layout/Documentation/helpers/CodeBlock';
import Copy from '@/components/Copy';
import TooltipWrapper from '@/components/ui/Tooltip';
import clsx from 'clsx';
import { refractor } from 'refractor';
import ScrollArea from '@radui/ui/ScrollArea';
import Button from '@radui/ui/Button';

const renderElement = (element, index) => {
if (element.type === 'element') {
const { tagName, properties, children } = element;
const className = properties.className.join(' ');
Comment on lines +13 to +14

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Prevent potential crashes from missing className arrays.

The AST returned by refractor may not always contain a className array for every element. If it's undefined, calling .join(' ') will throw an error and crash the component. Use optional chaining to safely access and join the classes.

🛡️ Proposed fix
         const { tagName, properties, children } = element;
-        const className = properties.className.join(' ');
+        const className = properties?.className?.join(' ') || '';
📝 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 { tagName, properties, children } = element;
const className = properties.className.join(' ');
const { tagName, properties, children } = element;
const className = properties?.className?.join(' ') || '';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/components/mdx/MultipleTabs.tsx` around lines 13 - 14, Update the
className handling in the element-processing logic to safely access and join an
absent properties.className array using optional chaining, preventing the
component from throwing when the AST element has no classes.


return React.createElement(
tagName,
{ className, key: index },
children.map((child, childIndex) => renderElement(child, childIndex))
);
} else if (element.type === 'text') {
return element.value;
} else {
return null;
}
};

export const MultipleTabs = ({ items = [] }) => {
const [expanded, setExpanded] = useState(false);
const [hasOverflow, setHasOverflow] = useState(false);
const viewportRef = useRef(null);
Comment on lines +29 to +31

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Calculate hasOverflow to enable expandable display behavior.

The setHasOverflow function is never called, meaning hasOverflow is always false. As a result, the expandable code block functionality ("Show more" button, blur effect, and scrollbars) will never render.

Implement a useEffect hook to measure the viewport's scrollHeight against collapsedHeight and update the state.

🐛 Proposed fix to add the missing logic
     const [expanded, setExpanded] = useState(false);
     const [hasOverflow, setHasOverflow] = useState(false);
     const viewportRef = useRef(null);
+
+    useEffect(() => {
+        if (viewportRef.current) {
+            setHasOverflow(viewportRef.current.scrollHeight > 220);
+        }
+    }, [activeTab]);
📝 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 [expanded, setExpanded] = useState(false);
const [hasOverflow, setHasOverflow] = useState(false);
const viewportRef = useRef(null);
const [expanded, setExpanded] = useState(false);
const [hasOverflow, setHasOverflow] = useState(false);
const viewportRef = useRef(null);
useEffect(() => {
if (viewportRef.current) {
setHasOverflow(viewportRef.current.scrollHeight > 220);
}
}, [activeTab]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/components/mdx/MultipleTabs.tsx` around lines 29 - 31, In the
MultipleTabs component, add a useEffect tied to viewportRef and collapsedHeight
that measures the referenced viewport’s scrollHeight against collapsedHeight and
updates hasOverflow via setHasOverflow. Ensure the measurement runs after
rendering and preserves the existing expandable display behavior.

const [activeTab, setActiveTab] = useState(items[0]?.manager || 'pnpm');
const activeItem = items.find(item => item.manager === activeTab);
const collapsedHeight = 220;
const maxHeight = expanded ? 640 : collapsedHeight;

if (!activeItem) return null;

let code;
try {
code = refractor.highlight(activeItem.command, 'bash');
code = code.children.map((child, index) => renderElement(child, index));
} catch (error) {
code = [activeItem.command];
}

const copyContent = activeItem.command.trim();


return (
<pre className="docs-syntax-pre relative my-5 overflow-hidden rounded-[18px] border">
<div className="docs-syntax-toolbar flex items-center justify-between px-3.5 py-2 border-b border-gray-800/50">
<div className="flex items-center space-x-4">
<div className="flex items-center justify-center w-6 h-6 rounded bg-gray-800 text-gray-400 text-xs font-mono font-bold">
&gt;_
</div>
<div className="flex items-center space-x-1">
{items.map((item) => (
<button
key={item.manager}
onClick={() => setActiveTab(item.manager)}
className={clsx(
"px-3 py-1 text-sm rounded-md transition-colors",
activeTab === item.manager
? "bg-gray-800 text-gray-200"
: "text-gray-500 hover:text-gray-300"
)}
>
{item.manager}
</button>
))}
</div>
</div>
<TooltipWrapper label="Copy" placement="bottom">
<Copy
content={copyContent}
className="docs-syntax-copy h-8 w-8 rounded-[11px] border border-transparent hover:border-gray-700 hover:bg-gray-800/50"
iconSize={15}
/>
</TooltipWrapper>
</div>
<div className="relative px-5 py-4">


<ScrollArea.Root
className={clsx(
expanded ? "max-h-[640px]" : "max-h-[220px]",
"docs-syntax-scroll-area overflow-visible",
)}
>
<ScrollArea.Viewport
ref={viewportRef}
style={{
maxHeight,
overflowY: hasOverflow ? 'auto' : 'hidden',
}}
>

<code className="language-bash docs-code-block block whitespace-pre-wrap">
{code}
</code>
</ScrollArea.Viewport>

{hasOverflow && (
<ScrollArea.Scrollbar>
<ScrollArea.Thumb />
</ScrollArea.Scrollbar>
)}
</ScrollArea.Root>
{hasOverflow && <>
{!expanded && <div className="code-block-blur"></div>}
<div className="docs-syntax-footer flex w-full justify-center px-4 py-1.5">
<Button size="small" variant="ghost" className="docs-syntax-expand min-h-0 rounded-full border px-3 py-1 text-[0.78rem]" onClick={() => setExpanded(!expanded)}>
Show {expanded ? 'less' : 'more'}
</Button>
</div>
</>}
</div>
</pre>
);
};
2 changes: 2 additions & 0 deletions docs/mdx-components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Strong from "@radui/ui/Strong"
import { TableRoot, TableHead, TableBody, TableRow, TableHeader, TableCell } from '@/components/mdx/TableComponents'

import Documentation from '@/components/layout/Documentation/Documentation';
import { MultipleTabs } from '@/components/mdx/MultipleTabs';


const headingColorClasses = "text-gray-1000"
Expand Down Expand Up @@ -102,6 +103,7 @@ export function useMDXComponents(components: MDXComponents): MDXComponents {
// {...(props as ImageProps)}
// />
// ),
MultipleTabs,
...components,
}
}
Loading