Skip to content

Redo#1

Merged
DimitriGilbert merged 17 commits into
mainfrom
redo
May 17, 2026
Merged

Redo#1
DimitriGilbert merged 17 commits into
mainfrom
redo

Conversation

@DimitriGilbert

@DimitriGilbert DimitriGilbert commented May 16, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Title bar variants (macOS, Windows, Linux, minimal, none) for the terminal
    • CSS custom properties for theming with light/dark palettes
    • Richer command/output shapes and copy callbacks (success/error)
  • Refactor

    • Modernized framework/tooling upgrades and updated UI primitives
    • Replaced toast-based notifications with callback-driven flows
    • Improved scrolling, typing, and cancelable command execution behavior
  • Documentation

    • Added modernization and agent guidance docs and CSS custom properties reference
    • Updated examples and props docs to match new APIs

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 16, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@DimitriGilbert has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 15 minutes and 56 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d6f22fd5-15bf-430e-90b2-c0af034e2f19

📥 Commits

Reviewing files that changed from the base of the PR and between f0222fe and 5510899.

📒 Files selected for processing (7)
  • public/r/terminable.json
  • registry/components/ui/Terminable.tsx
  • src/app/docs/page.tsx
  • src/app/page.tsx
  • src/components/TerminableExample.tsx
  • src/components/ui/glow-link.tsx
  • src/components/ui/tabs.tsx
📝 Walkthrough

Walkthrough

This PR modernizes tooling, swaps Radix primitives for Base UI, rewrites the Terminable component for abortable command processing and title-bar variants, updates registry metadata and public registry files, refreshes demo pages and examples to the new API, and adds developer guidance and a modernization plan.

Changes

TerMinable Modernization to Next.js 16 & Base UI

Layer / File(s) Summary
ESLint flat config, PostCSS, and Tailwind v4 build setup
.eslintrc.cjs (deleted), eslint.config.mjs, postcss.config.js (deleted), postcss.config.mjs, tailwind.config.ts (deleted), src/styles/globals.css, tsconfig.json, package.json, components.json
Migrate from .eslintrc.cjs to a flat eslint.config.mjs, add postcss.config.mjs, remove legacy PostCSS/Tailwind config files, update globals.css to Tailwind v4 directives and CSS variables, change tsconfig.json JSX handling, and refresh package.json scripts and dependencies.
Base UI primitive components (Button, HoverCard, NavigationMenu, Tabs, ScrollArea)
src/components/ui/button.tsx, src/components/ui/hover-card.tsx, src/components/ui/navigation-menu.tsx, src/components/ui/tabs.tsx, src/components/ui/scroll-area.tsx, src/components/theme-provider.tsx, src/components/ui/menubar.tsx (deleted), src/components/ui/sonner.tsx (deleted)
Replace Radix wrappers with Base UI primitives, add a ScrollArea wrapper, remove the sonner Toaster and menubar module, and simplify ThemeProvider (swap icons to lucide-react and remove extra wrappers).
Terminable component core rewrite with AbortController, title bar variants, and callbacks
registry/components/ui/Terminable.tsx, public/r/terminable.json
Rewrite Terminable using AbortController-driven, cancelable command/output processing; expand prompt/output shapes to support OutputContent placeholders and delayed swaps; respect prefers-reduced-motion; switch to ScrollArea viewport autoscroll with user-scroll pause; replace menubar/toast with configurable titleBarVariant and clipboard helpers plus onCopySuccess/onCopyError/onError callbacks; update registry entry.
Public registry entries and component metadata
public/r/registry.json, registry.json
Add public/r/registry.json registry entry for terminable, update registry.json to use scroll-area dependency (replacing menubar), remove Terminable.css style reference, and add cssVars light/dark theme definitions.
Home page, layout, and example component updates for new Terminable API
src/app/page.tsx, src/app/layout.tsx, src/components/TerminableExample.tsx, src/components/PkgMngCmdCopy.tsx, src/components/copy-button.tsx
Refactor layout/nav to use NavigationMenu and ThemeProvider, update HomePage to use buttonVariants and CSS variable–based palette defaults, pass titleBarVariant="macos" to Terminable, update examples to deterministic instance keys, and change copy/clipboard behaviors to silent failures or callback-driven handling.
Docs page with updated examples and new sections
src/app/docs/page.tsx
Remove toast dependency, update installation command to shadcn@latest, rebuild Props and CommandEntry tables to match new types and callbacks, add CSS Custom Properties and Title Bar Variants sections, and update all example code strings.
Developer guides: AGENTS.md and MODERNIZATION_PLAN.md
AGENTS.md, MODERNIZATION_PLAN.md
Add AGENTS.md documenting local workflows, bun scripts, registry-vs-demo responsibilities, and code conventions; add MODERNIZATION_PLAN.md outlining phased upgrades, component rewrite goals, and accessibility follow-ups.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🐰 A modernization hop through the warren,
From Radix to Base, the refactor's borne.
AbortController chains, and title bars bright,
Next.js 16 shines with React's new light.
Tailwind's directives dance, CSS vars set free,
A component reborn, as lovely as can be! 🎉

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.06% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Redo' is vague and does not convey any meaningful information about the extensive modernization changes included in this pull request. Use a more descriptive title that captures the main objective, such as 'Modernize TerMinable component and upgrade to Next.js 16 with Tailwind v4' or similar.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch redo

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
components.json (1)

7-7: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove stale Tailwind config reference from components.json.

Line 7 references tailwind.config.ts, but this file does not exist. The config field in components.json must be updated or removed to prevent shadcn tooling failures during builds or registry operations.

🤖 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 `@components.json` at line 7, components.json currently contains a stale config
entry ("config": "tailwind.config.ts") that points to a non-existent file;
remove this config field or replace its value with the correct Tailwind config
path used in the repo so shadcn tooling won't fail. Locate the "config" key in
components.json (the entry shown as "config": "tailwind.config.ts") and either
delete that property entirely or update it to the actual Tailwind config
filename (e.g., tailwind.config.cjs or tailwind.config.js) used by the project,
then save and run the build to confirm the registry/tooling no longer errors.
src/components/theme-provider.tsx (1)

14-34: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Remove the dead className prop from ThemeProvider.

The provider no longer renders a wrapper that can consume className, so the public prop now silently does nothing. Either restore a styled wrapper or drop the prop from the signature.

Suggested fix
-export function ThemeProvider({ children }: { children: React.ReactNode; className?: string }) {
+export function ThemeProvider({ children }: { children: React.ReactNode }) {
🤖 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 `@src/components/theme-provider.tsx` around lines 14 - 34, The ThemeProvider is
accepting a dead className prop that is never used; remove className from the
component's props and type signature so ThemeProvider({ children }: { children:
React.ReactNode }) only — then update any callers/tests that pass className to
stop passing it (or restore a wrapper if you intend to accept className); ensure
ThemeContext.Provider usage and the exported ThemeProvider signature are updated
accordingly to avoid lingering type/usage errors.
🤖 Prompt for all review comments with 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.

Inline comments:
In `@MODERNIZATION_PLAN.md`:
- Line 44: Clarify that the API expects the literal prop values for
titleBarVariant (e.g., "macos", "windows", "linux", "minimal", "none") while
using proper OS names in prose (e.g., macOS, Windows, GNOME) to prevent readers
from copying incorrect casing; update the MODERNIZATION_PLAN.md entry for
titleBarVariant to explicitly state the allowed literal values and show a
note/example that the human-facing label may use the OS trademark/capitalization
(e.g., titleBarVariant: "macos" — rendered as macOS-style dots).

In `@registry/components/ui/Terminable.tsx`:
- Around line 523-543: handleCommandClick is invoking cmd?.onCopy?.() using
commands[processingStateRef.current.currentIndex], which targets the currently
processing command rather than the clicked one; remove the erroneous onCopy
invocation and rely on copyToClipboard(...).then(() =>
onCopySuccess?.(entry.content as string)) / .catch(() => onCopyError?.(err))
instead, or alternatively, if you prefer preserving per-command handlers, add an
index to DisplayEntry and call the correct commands[index].onCopy() using that
entry index; update handleCommandClick to reference entry (or its stored index)
rather than processingStateRef.current.currentIndex.

In `@src/app/docs/page.tsx`:
- Around line 492-499: The doc text claims "five options" but only shows four
examples; add the missing "minimal" example by inserting another
LazyTerminableExample component with title="Minimal" and
titleBarVariant="minimal" into the example grid (the same place where
LazyTerminableExample with titleBarVariant="macos" is used) so all five variants
are demonstrated; also add the corresponding Minimal entry in the second grid
instance referenced around the later block to keep both sections consistent.
- Around line 735-737: The TSX examples use hardcoded hex colors in inline style
objects (e.g., the span elements rendering "Custom prompt" and "Custom output"
with style={{ color: "`#e0af68`" }} and style={{ color: "`#7dcfff`" }}); replace
these inline hex values with CSS custom properties (e.g., color:
"var(--terminable-<name>)") to match project theming rules—update the span
elements in the shown diff and the other occurrences around the file (lines
referenced 742-746 and 929) to use appropriate vars like
var(--terminable-accent) and var(--terminable-output) (or existing theme
variable names) instead of literal hex codes.
- Around line 773-788: The live "Callbacks" demo's commands array is missing the
onDone, onCopy and onBeforeOutput handlers declared in the code sample; locate
the commands array used to render the Callbacks section (the object literals
with prompt/output entries) and add the missing properties back into the
appropriate command objects (e.g., add onDone: handleDone, onCopy: handleCopy,
onBeforeOutput: handleBeforeOutput or inline functions). Implement small handler
functions referenced by those properties (handleDone to update state/log or mark
completion, handleCopy to perform copy and optionally show toast, and
handleBeforeOutput to return or set the delayed output/placeholder per the
sample) and ensure the component that renders commands receives/uses these
callbacks so the live demo behavior matches the shown code sample.

In `@src/app/page.tsx`:
- Around line 13-15: The three hardcoded hex color state initializations
(TermBackground, TermPromptColor, TermOutputColor) should be replaced with CSS
custom property references (e.g. use "var(--terminable-bg)",
"var(--terminable-prompt)", "var(--terminable-output)") so theming follows the
project contract; update the useState initializers for TermBackground,
setTermBackground usage, TermPromptColor and TermOutputColor to use var(...)
strings instead of hex literals, and also replace any other hardcoded terminal
color occurrences in this file (the other instances you noted) with the
corresponding CSS custom properties.
- Around line 70-78: Remove the nested interactive Button inside the Link
components (the Link and Button in the CTA blocks) and instead render a single
interactive element: either make the Button render as an anchor (use your
Button's "asChild"/component="a" prop or render the anchor <a> styled as a
button) and wrap it with Link or use Link to render the anchor directly, so
there is no button-inside-link nesting; also add rel="noopener noreferrer" to
every external Link that uses target="_blank" (update both CTA occurrences
referencing Link and Button around the Butt3r.dev and the other CTA at the other
occurrence).

In `@src/components/copy-button.tsx`:
- Around line 17-21: The icon-only button in the CopyButton component is missing
accessibility semantics; update the <button> element (used with
onClick={copyToClipboard} and rendering {copied ? <Check .../> : <Copy .../>})
to include type="button" and aria-label="Copy" so it doesn't behave like a
submit in forms and is accessible to screen readers; keep the existing
className, onClick handler, and conditional icon rendering intact.
- Line 19: The className template in the CopyButton component can emit the
literal "undefined" when the prop is omitted; update the CopyButton props so the
className prop has a safe default (e.g., className = "") in the
function/component parameter destructuring (or use your project's class-merge
util like cn or clsx when composing `rounded-md p-2 transition-colors
hover:bg-muted ${className}`) to ensure no "undefined" token gets appended.

In `@src/components/PkgMngCmdCopy.tsx`:
- Around line 62-67: The copy button currently can act as a form submitter and
lacks an accessible name; update the button element rendered alongside the Copy
icon to include type="button" and an accessible label (e.g. aria-label="Copy
command") so keyboard/screen-reader users can identify its purpose and it won’t
submit forms; locate the button that calls handleCopy and renders the <Copy />
icon and add those attributes.
- Around line 21-24: The current approach stores a selectedManager object that
embeds the prop-derived command (from cmd) which can become stale when cmd
changes; change state to store only the selected manager's name (e.g.,
selectedManagerName via setSelectedManagerName) and stop storing command strings
in state, keep the list of manager objects (name + command) derived each render
from the current cmd prop (or compute managers = [{name:"npx", command: "npx " +
cmd}, ...]) and when you need the active command use managers.find(m => m.name
=== selectedManagerName).command; update any usages of selectedManager to use
the derived object or command instead.

In `@src/components/ui/button.tsx`:
- Line 11: The default variant's class string uses an incorrect child-anchor
hover selector "[a]:hover:bg-primary/80" so the button never receives hover
styling; in the button variant definition (the "default" key in the variant
map/const inside src/components/ui/button.tsx) replace the
"[a]:hover:bg-primary/80" fragment with "hover:bg-primary/80" so the button
itself gets the hover style (keep the rest of the class string intact).

In `@src/components/ui/navigation-menu.tsx`:
- Around line 84-87: The Tailwind class string on
NavigationMenuPrimitive.Content (and the similar class on NavigationMenuPopup)
uses invalid data-variant/utility syntax so utilities are being dropped; update
all data-* modifiers to bracketed form (e.g. replace
data-activation-direction=left: with data-[activation-direction=left]: and
data-ending-style: / data-starting-style: with data-[ending-style=...]: and
data-[starting-style=...]:), and change any easing-[ease] style to the proper
ease-[ease] form; apply these exact replacements in the className for
NavigationMenuPrimitive.Content and the corresponding className in the
NavigationMenuPopup component so the popup animation utilities are valid.

In `@src/components/ui/tabs.tsx`:
- Around line 8-22: The Tabs wrapper currently sets data-orientation for styling
but does not pass the orientation prop into TabsPrimitive.Root, which breaks
vertical keyboard navigation; update the Tabs function to forward the
orientation value to TabsPrimitive.Root (i.e., include orientation={orientation}
on the TabsPrimitive.Root element) while keeping existing className,
data-orientation, and {...props} so the primitive receives the correct
orientation and internal behavior matches the visual state.

---

Outside diff comments:
In `@components.json`:
- Line 7: components.json currently contains a stale config entry ("config":
"tailwind.config.ts") that points to a non-existent file; remove this config
field or replace its value with the correct Tailwind config path used in the
repo so shadcn tooling won't fail. Locate the "config" key in components.json
(the entry shown as "config": "tailwind.config.ts") and either delete that
property entirely or update it to the actual Tailwind config filename (e.g.,
tailwind.config.cjs or tailwind.config.js) used by the project, then save and
run the build to confirm the registry/tooling no longer errors.

In `@src/components/theme-provider.tsx`:
- Around line 14-34: The ThemeProvider is accepting a dead className prop that
is never used; remove className from the component's props and type signature so
ThemeProvider({ children }: { children: React.ReactNode }) only — then update
any callers/tests that pass className to stop passing it (or restore a wrapper
if you intend to accept className); ensure ThemeContext.Provider usage and the
exported ThemeProvider signature are updated accordingly to avoid lingering
type/usage errors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 543559ef-aaf7-4d74-99ea-111e72f9308f

📥 Commits

Reviewing files that changed from the base of the PR and between 4b9dc64 and 1a38c96.

⛔ Files ignored due to path filters (4)
  • bun.lock is excluded by !**/*.lock
  • comm/docs_1.jpeg is excluded by !**/*.jpeg
  • comm/docs_2.jpeg is excluded by !**/*.jpeg
  • comm/home.jpeg is excluded by !**/*.jpeg
📒 Files selected for processing (29)
  • .eslintrc.cjs
  • AGENTS.md
  • MODERNIZATION_PLAN.md
  • components.json
  • eslint.config.mjs
  • package.json
  • postcss.config.js
  • postcss.config.mjs
  • public/r/registry.json
  • public/r/terminable.json
  • registry.json
  • registry/components/ui/Terminable.tsx
  • src/app/docs/page.tsx
  • src/app/layout.tsx
  • src/app/page.tsx
  • src/components/PkgMngCmdCopy.tsx
  • src/components/TerminableExample.tsx
  • src/components/copy-button.tsx
  • src/components/theme-provider.tsx
  • src/components/ui/button.tsx
  • src/components/ui/hover-card.tsx
  • src/components/ui/menubar.tsx
  • src/components/ui/navigation-menu.tsx
  • src/components/ui/scroll-area.tsx
  • src/components/ui/sonner.tsx
  • src/components/ui/tabs.tsx
  • src/styles/globals.css
  • tailwind.config.ts
  • tsconfig.json
💤 Files with no reviewable changes (5)
  • postcss.config.js
  • .eslintrc.cjs
  • src/components/ui/menubar.tsx
  • tailwind.config.ts
  • src/components/ui/sonner.tsx

Comment thread MODERNIZATION_PLAN.md
| Task | Details |
|---|---|
| **Replace Radix Menubar with native elements** | The 3 traffic-light dots become plain `<div>`/`<button>` elements. No more `menubar` registry dependency. |
| **Add title bar variants** | New `titleBarVariant` prop: `"macos"` (dots), `"windows"` (min/max/close), `"linux"` (GNOME-style), `"minimal"` (just title), `"none"` (no title bar). Each rendered with pure HTML/CSS. |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clarify API literal vs OS label to avoid invalid prop values.

Keep the prop value as "macos" but use the proper OS name (macOS) in prose so readers don’t accidentally copy "macOS" as the literal.

Suggested doc tweak
-| **Add title bar variants** | New `titleBarVariant` prop: `"macos"` (dots), `"windows"` (min/max/close), `"linux"` (GNOME-style), `"minimal"` (just title), `"none"` (no title bar). Each rendered with pure HTML/CSS. |
+| **Add title bar variants** | New `titleBarVariant` prop: `"macos"` (macOS traffic-light dots), `"windows"` (min/max/close), `"linux"` (GNOME-style), `"minimal"` (just title), `"none"` (no title bar). Each rendered with pure HTML/CSS. |
📝 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
| **Add title bar variants** | New `titleBarVariant` prop: `"macos"` (dots), `"windows"` (min/max/close), `"linux"` (GNOME-style), `"minimal"` (just title), `"none"` (no title bar). Each rendered with pure HTML/CSS. |
| **Add title bar variants** | New `titleBarVariant` prop: `"macos"` (macOS traffic-light dots), `"windows"` (min/max/close), `"linux"` (GNOME-style), `"minimal"` (just title), `"none"` (no title bar). Each rendered with pure HTML/CSS. |
🧰 Tools
🪛 LanguageTool

[uncategorized] ~44-~44: The operating system from Apple is written “macOS”.
Context: ...ariants** | New titleBarVariant prop: "macos" (dots), "windows" (min/max/close), ...

(MAC_OS)

🤖 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 `@MODERNIZATION_PLAN.md` at line 44, Clarify that the API expects the literal
prop values for titleBarVariant (e.g., "macos", "windows", "linux", "minimal",
"none") while using proper OS names in prose (e.g., macOS, Windows, GNOME) to
prevent readers from copying incorrect casing; update the MODERNIZATION_PLAN.md
entry for titleBarVariant to explicitly state the allowed literal values and
show a note/example that the human-facing label may use the OS
trademark/capitalization (e.g., titleBarVariant: "macos" — rendered as
macOS-style dots).

Comment thread registry/components/ui/Terminable.tsx
Comment thread src/app/docs/page.tsx
Comment on lines +492 to +499
prop controls the visual style of the title bar. Choose from five
options:
</p>

<div className="grid gap-8 md:grid-cols-2">
<LazyTerminableExample
title="macOS"
titleBarVariant="macos"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

The section says “five options” but only four variants are demonstrated.

minimal is missing from the example grid. Add a titleBarVariant="minimal" example or adjust the wording.

Also applies to: 548-563

🤖 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 `@src/app/docs/page.tsx` around lines 492 - 499, The doc text claims "five
options" but only shows four examples; add the missing "minimal" example by
inserting another LazyTerminableExample component with title="Minimal" and
titleBarVariant="minimal" into the example grid (the same place where
LazyTerminableExample with titleBarVariant="macos" is used) so all five variants
are demonstrated; also add the corresponding Minimal entry in the second grid
instance referenced around the later block to keep both sections consistent.

Comment thread src/app/docs/page.tsx Outdated
Comment thread src/app/docs/page.tsx
Comment thread src/components/PkgMngCmdCopy.tsx
Comment thread src/components/PkgMngCmdCopy.tsx
Comment thread src/components/ui/button.tsx Outdated
Comment on lines +84 to +87
<NavigationMenuPrimitive.Content
data-slot="navigation-menu-content"
className={cn(
"data-ending-style:data-activation-direction=left:translate-x-[50%] data-ending-style:data-activation-direction=right:translate-x-[-50%] data-starting-style:data-activation-direction=left:translate-x-[-50%] data-starting-style:data-activation-direction=right:translate-x-[50%] h-full w-auto p-1 transition-[opacity,transform,translate] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] group-data-[viewport=false]/navigation-menu:rounded-lg group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:ring-1 group-data-[viewport=false]/navigation-menu:ring-foreground/10 group-data-[viewport=false]/navigation-menu:duration-300 data-ending-style:opacity-0 data-starting-style:opacity-0 data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 data-[motion^=from-]:animate-in data-[motion^=from-]:fade-in data-[motion^=to-]:animate-out data-[motion^=to-]:fade-out **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none group-data-[viewport=false]/navigation-menu:data-open:animate-in group-data-[viewport=false]/navigation-menu:data-open:fade-in-0 group-data-[viewport=false]/navigation-menu:data-open:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-closed:animate-out group-data-[viewport=false]/navigation-menu:data-closed:fade-out-0 group-data-[viewport=false]/navigation-menu:data-closed:zoom-out-95",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

In Tailwind CSS v4, are data-activation-direction=left:andeasing-[ease]valid class prefixes/utilities, or should they be written asdata-[activation-direction=left]:andease-[ease]?

💡 Result:

In Tailwind CSS v4, you should use the bracketed syntax for both cases: data-[activation-direction=left]: and ease-[ease]. For data attributes, while Tailwind v4 allows you to use bare variants for simple boolean flags (e.g., data-active:) [1][2], complex data attributes that include values (like data-activation-direction="left") require the arbitrary variant syntax using square brackets: data-[activation-direction=left]: [3][4]. For easing utilities, the correct syntax for an arbitrary value is ease-[...] [5]. Using ease-[ease] would apply the literal CSS value "ease" to the transition-timing-function property [5]. If you intended to use a custom easing function, you would place that specific value inside the brackets, such as ease-[cubic-bezier(...)] [5][6].

Citations:


🏁 Script executed:

cat -n src/components/ui/navigation-menu.tsx | sed -n '80,120p'

Repository: DimitriGilbert/TerMinable

Length of output: 3778


Fix invalid Tailwind data-variant and utility syntax.

data-activation-direction=left: requires bracket syntax (data-[activation-direction=left]:), and easing-[ease] should be ease-[ease]. Additionally, data-variant modifiers like data-ending-style: and data-starting-style: should use bracket syntax for consistency in Tailwind v4. These invalid utilities are silently dropped, breaking the popup animation.

Suggested fixes

Lines 84–87 (NavigationMenuContent):

-        "data-ending-style:data-activation-direction=left:translate-x-[50%] data-ending-style:data-activation-direction=right:translate-x-[-50%] data-starting-style:data-activation-direction=left:translate-x-[-50%] data-starting-style:data-activation-direction=right:translate-x-[50%] h-full w-auto p-1 transition-[opacity,transform,translate] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] group-data-[viewport=false]/navigation-menu:rounded-lg group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:ring-1 group-data-[viewport=false]/navigation-menu:ring-foreground/10 group-data-[viewport=false]/navigation-menu:duration-300 data-ending-style:opacity-0 data-starting-style:opacity-0 data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 data-[motion^=from-]:animate-in data-[motion^=from-]:fade-in data-[motion^=to-]:animate-out data-[motion^=to-]:fade-out **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none group-data-[viewport=false]/navigation-menu:data-open:animate-in group-data-[viewport=false]/navigation-menu:data-open:fade-in-0 group-data-[viewport=false]/navigation-menu:data-open:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-closed:animate-out group-data-[viewport=false]/navigation-menu:data-closed:fade-out-0 group-data-[viewport=false]/navigation-menu:data-closed:zoom-out-95",
+        "data-[ending-style]:data-[activation-direction=left]:translate-x-[50%] data-[ending-style]:data-[activation-direction=right]:translate-x-[-50%] data-[starting-style]:data-[activation-direction=left]:translate-x-[-50%] data-[starting-style]:data-[activation-direction=right]:translate-x-[50%] h-full w-auto p-1 transition-[opacity,transform,translate] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] group-data-[viewport=false]/navigation-menu:rounded-lg group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:ring-1 group-data-[viewport=false]/navigation-menu:ring-foreground/10 group-data-[viewport=false]/navigation-menu:duration-300 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0 data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 data-[motion^=from-]:animate-in data-[motion^=from-]:fade-in data-[motion^=to-]:animate-out data-[motion^=to-]:fade-out **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none group-data-[viewport=false]/navigation-menu:data-open:animate-in group-data-[viewport=false]/navigation-menu:data-open:fade-in-0 group-data-[viewport=false]/navigation-menu:data-open:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-closed:animate-out group-data-[viewport=false]/navigation-menu:data-closed:fade-out-0 group-data-[viewport=false]/navigation-menu:data-closed:zoom-out-95",

Line 116 (NavigationMenuPopup):

-        <NavigationMenuPrimitive.Popup className="data-[ending-style]:easing-[ease] xs:w-(--popup-width) relative h-(--popup-height) w-(--popup-width) origin-(--transform-origin) rounded-lg bg-popover text-popover-foreground shadow ring-1 ring-foreground/10 transition-[opacity,transform,width,height,scale,translate] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] outline-none data-ending-style:scale-90 data-ending-style:opacity-0 data-ending-style:duration-150 data-starting-style:scale-90 data-starting-style:opacity-0">
+        <NavigationMenuPrimitive.Popup className="data-[ending-style]:ease-[ease] xs:w-(--popup-width) relative h-(--popup-height) w-(--popup-width) origin-(--transform-origin) rounded-lg bg-popover text-popover-foreground shadow ring-1 ring-foreground/10 transition-[opacity,transform,width,height,scale,translate] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] outline-none data-[ending-style]:scale-90 data-[ending-style]:opacity-0 data-[ending-style]:duration-150 data-[starting-style]:scale-90 data-[starting-style]:opacity-0">
🤖 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 `@src/components/ui/navigation-menu.tsx` around lines 84 - 87, The Tailwind
class string on NavigationMenuPrimitive.Content (and the similar class on
NavigationMenuPopup) uses invalid data-variant/utility syntax so utilities are
being dropped; update all data-* modifiers to bracketed form (e.g. replace
data-activation-direction=left: with data-[activation-direction=left]: and
data-ending-style: / data-starting-style: with data-[ending-style=...]: and
data-[starting-style=...]:), and change any easing-[ease] style to the proper
ease-[ease] form; apply these exact replacements in the className for
NavigationMenuPrimitive.Content and the corresponding className in the
NavigationMenuPopup component so the popup animation utilities are valid.

Comment thread src/components/ui/tabs.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/app/docs/page.tsx (1)

50-69: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add rel to the new external links.

Both links open a new tab with target="_blank", but neither sets rel="noreferrer noopener". That leaves the opener relationship intact unnecessarily.

🤖 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 `@src/app/docs/page.tsx` around lines 50 - 69, The external links created by
the GlowLink and Link components open in a new tab but lack rel attributes;
update the GlowLink invocation (symbol: GlowLink) and the Link invocation
(symbol: Link) to include rel="noreferrer noopener" whenever target="_blank" is
used so the opener relationship is removed and security/privacy is improved;
ensure both instances in the shown diff are updated (the GlowLink with href
"https://ui.shadcn.com/" and the Link with href
"https://ui.shadcn.com/docs/installation/nextjs") to include the rel attribute.
♻️ Duplicate comments (1)
src/app/docs/page.tsx (1)

768-784: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep the code samples on CSS variables too.

The live examples here were updated to var(--terminable-...), but the embedded snippets still teach hardcoded hex colors. That leaves the docs internally inconsistent and keeps the theming guidance stale. As per coding guidelines: **/*.{ts,tsx,css}: Use CSS custom properties for theming (e.g. var(--terminable-bg)) instead of hardcoded hex values or inline color classes.

Also applies to: 955-983

🤖 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 `@src/app/docs/page.tsx` around lines 768 - 784, The embedded code sample
passed to the Terminable component (the codeString prop) uses hardcoded hex
colors; update those inline style color values to use the project CSS custom
properties (e.g. var(--terminable-prompt), var(--terminable-output),
var(--terminable-node-1), var(--terminable-node-2) or whatever naming you use)
so the snippet matches the live examples and theming guidance. Locate the
codeString for the Terminable usage in this file (and the similar block later
around the second example) and replace "`#e0af68`", "`#7dcfff`", "`#f7768e`",
"`#7aa2f7`" with the appropriate var(...) tokens, keeping the same JSX structure
and keys. Ensure both occurrences mentioned in the comment are updated so docs
remain consistent.
🤖 Prompt for all review comments with 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.

Inline comments:
In `@registry/components/ui/Terminable.tsx`:
- Around line 296-300: The loop in Terminable.tsx incorrectly treats
falsy-but-valid outputs (like "" or 0) as missing by using if (!line); change
that check to an explicit null/undefined test (e.g., if (line == null) continue)
wherever you filter outputs (the for...of loop handling outputs and the similar
block around lines 438-447 that checks cmd.output) so empty strings and
zero-valued ReactNodes are preserved.
- Around line 625-653: The span used for copyable commands is made focusable and
keyboard-interactive but lacks an accessible role; update the element in
Terminable.tsx (the span that uses allowCopy, entry.done and entry.content and
handlers handleCommandClick/handleCommandKeyDown) to include role="button" when
it is focusable/clickable (i.e., the same conditional used for
tabIndex/onKeyDown/aria-label), so assistive tech recognizes it as a button;
keep the existing keyboard handler logic (handleCommandKeyDown) and aria-label
as-is.
- Around line 531-537: The code calls cmd?.onCopy?.() before attempting the
async copy, so callers receive a success callback even if copyToClipboard fails;
move the call to cmd?.onCopy?.() into the success branch of the copyToClipboard
promise alongside onCopySuccess, i.e., after
copyToClipboard(entry.content).then(...) invoke both
onCopySuccess(entry.content) and cmd?.onCopy?.(), and do not call
cmd?.onCopy?.() on rejection so failures don't trigger success handlers; locate
the commands/entry usage around the copyToClipboard call to make this change.

In `@src/app/docs/page.tsx`:
- Around line 198-220: The docs currently list literal hex values as prop
defaults for backgroundColor, promptColor, and outputColor which is incorrect
because these are optional overrides in TerminableProps that fall back to
internal CSS variables; update the table rows in page.tsx so the "Default"
column does NOT show the hex strings for the props backgroundColor, promptColor,
and outputColor (replace with an explicit indication like "uses CSS var" or "—"
/ "no default") and adjust the description text to state these props override
the internal CSS variable rather than implying a JS-level default value.
- Around line 837-855: The live demo isn't receiving the color props—only the
codeString was updated—so the preview still uses defaults; update the
LazyTerminableExample invocation to pass backgroundColor, promptColor, and
outputColor props (same values shown in codeString) so the rendered example uses
the custom palette, ensuring the prop names match the
LazyTerminableExample/Terminable API (backgroundColor, promptColor,
outputColor).

---

Outside diff comments:
In `@src/app/docs/page.tsx`:
- Around line 50-69: The external links created by the GlowLink and Link
components open in a new tab but lack rel attributes; update the GlowLink
invocation (symbol: GlowLink) and the Link invocation (symbol: Link) to include
rel="noreferrer noopener" whenever target="_blank" is used so the opener
relationship is removed and security/privacy is improved; ensure both instances
in the shown diff are updated (the GlowLink with href "https://ui.shadcn.com/"
and the Link with href "https://ui.shadcn.com/docs/installation/nextjs") to
include the rel attribute.

---

Duplicate comments:
In `@src/app/docs/page.tsx`:
- Around line 768-784: The embedded code sample passed to the Terminable
component (the codeString prop) uses hardcoded hex colors; update those inline
style color values to use the project CSS custom properties (e.g.
var(--terminable-prompt), var(--terminable-output), var(--terminable-node-1),
var(--terminable-node-2) or whatever naming you use) so the snippet matches the
live examples and theming guidance. Locate the codeString for the Terminable
usage in this file (and the similar block later around the second example) and
replace "`#e0af68`", "`#7dcfff`", "`#f7768e`", "`#7aa2f7`" with the appropriate var(...)
tokens, keeping the same JSX structure and keys. Ensure both occurrences
mentioned in the comment are updated so docs remain consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: abade382-424a-458a-8c06-23d1897a2758

📥 Commits

Reviewing files that changed from the base of the PR and between 1a38c96 and f0222fe.

📒 Files selected for processing (10)
  • components.json
  • public/r/terminable.json
  • registry/components/ui/Terminable.tsx
  • src/app/docs/page.tsx
  • src/app/page.tsx
  • src/components/PkgMngCmdCopy.tsx
  • src/components/copy-button.tsx
  • src/components/theme-provider.tsx
  • src/components/ui/button.tsx
  • src/components/ui/tabs.tsx
✅ Files skipped from review due to trivial changes (1)
  • components.json
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/components/copy-button.tsx
  • src/components/PkgMngCmdCopy.tsx
  • src/app/page.tsx
  • src/components/ui/button.tsx
  • public/r/terminable.json

Comment thread registry/components/ui/Terminable.tsx
Comment thread registry/components/ui/Terminable.tsx
Comment thread registry/components/ui/Terminable.tsx
Comment thread src/app/docs/page.tsx Outdated
Comment thread src/app/docs/page.tsx
@DimitriGilbert DimitriGilbert merged commit 5510899 into main May 17, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant