feat: improve site ui and integrate with shadcn - #59
Conversation
Feat/comp searching
* fix: improve sidebar layout * fix: update search bar component ui
* fix: improve sidebar layout * fix: update sidebar ui
* fix: improve sidebar layout * fix: update sidebar ui * fix: update side bar ui
…istry and add named installation configuration.
…t installation to use named components, and remove CLI documentation.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the 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. 📝 WalkthroughWalkthroughThis PR implements a comprehensive registry system for Sona UI components with shadcn-compatible architecture. It restructures configuration to support dynamic component registration, adds build scripts for registry generation, introduces ten UI components with manifest entries, implements an advanced code block system with syntax highlighting, updates styling infrastructure, and reorganizes documentation with component-driven examples. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Note
Due to the large number of review comments, Critical severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (6)
src/content/docs/magnetic-button.mdx (1)
11-56:⚠️ Potential issue | 🟡 MinorRemove "global" from the Features section.
The
interactionAreaprop only supports"self"and"parent". The Features section incorrectly lists "global" as an option—remove it to match the actual component API shown in the Props table.src/content/docs/accordion.mdx (1)
69-73:⚠️ Potential issue | 🟡 MinorProps table variant type is inconsistent with the features list.
Line 17 states the variants are
default,outlined, andsplitted, but the PropTable on line 70 still shows'default' | 'bordered' | 'splitted'. The AI summary confirms the variant was renamed from "bordered" to "outlined".📝 Proposed fix
{ name: "variant", - type: "'default' | 'bordered' | 'splitted'", + type: "'default' | 'outlined' | 'splitted'", default: "default", description: "The visual style of the accordion.", },src/content/docs/expandable-tabs.mdx (1)
52-57:⚠️ Potential issue | 🟡 MinorProps table shows outdated prop name
transitionConfig.The component interface uses
motionConfig(visible in relevant code snippets atsrc/registry/sonaui/expandableTabs/ExpandableTabs.tsx:15), but the documentation still referencestransitionConfig. The changelog also confirms this rename occurred in v2.5.1.📝 Proposed fix
{ - name: "transitionConfig", - type: "Transition", + name: "motionConfig", + type: "MotionConfigProps", default: '{ duration: 0.2, ease: "easeInOut" }', description: "Configuration for the transition animations.", },src/content/docs/bubble-up-button.mdx (1)
17-17:⚠️ Potential issue | 🟡 MinorUpdate library reference from "Framer Motion" to "Motion".
The PR migrated the dependency from
framer-motiontomotion(as noted in the commit messages and library context showingmotionversion 12.29.2). The documentation should reflect this change.📝 Proposed fix
-- Built with Framer Motion for smooth animations. +- Built with Motion for smooth animations.src/content/docs/spinning-text.mdx (1)
68-72:⚠️ Potential issue | 🟡 MinorRemove
fontSizefrom the props documentation or add it as a prop to the component.The
fontSizeprop documented in the props table (lines 68-72) does not exist in theSpinningTextPropsinterface (lines 8-20 ofsrc/registry/sonaui/spinning-text/spinning-text.tsx). The component accepts astyleprop for custom styling but does not expose a dedicatedfontSizeprop. Either addfontSizeas a dedicated prop to the component or update the documentation to direct users to thestyleprop instead.src/registry/sonaui/accordion/accordion.tsx (1)
163-182:⚠️ Potential issue | 🟠 MajorAccessibility: Missing keyboard support on accordion trigger.
The
AccordionItemTriggeruses adivwithonClickbut lacks keyboard accessibility. Users should be able to toggle with Enter/Space keys.🐛 Add keyboard support
const AccordionItemTrigger = ({ value, children, }: AccordionItemTriggerProps) => { const context = useContext(AccordionContext); if (!context) throw new Error("AccordionTrigger must be used within AccordionRoot"); const { openItems, toggleItem } = context; const isOpen = openItems.has(value); + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + toggleItem(value); + } + }; return ( <div + role="button" + tabIndex={0} aria-expanded={isOpen} onClick={() => toggleItem(value)} + onKeyDown={handleKeyDown} className="cursor-pointer" > {children} </div> ); };
🤖 Fix all issues with AI agents
In `@src/app/globals.css`:
- Around line 76-80: The CSS defines circular font variables (--font-sans,
--font-mono, --font-rubik) that reference themselves; update the assignments
inside the `@theme` block to reference the actual Next.js-injected variables
(--font-geist-sans, --font-geist-mono, --font-clash-display) used in
src/app/layout.tsx (or replace them with real font stacks), e.g. set
--font-sans: var(--font-geist-sans), --font-mono: var(--font-geist-mono), and
--font-rubik: var(--font-clash-display) so the variables resolve correctly.
In `@src/components/common/component-installation.tsx`:
- Line 78: The code uses the experimental ViewTransition component
(ViewTransition) which is not available in stable react@19.2 and is applied only
to the manual tab content (ManualInstallTab) while the CLI tab (CliInstallTab)
remains unwrapped, causing both compatibility and inconsistent animation
behavior; either remove the ViewTransition import and wrapper entirely from the
component (ComponentInstallation) to remain compatible with stable React, or
switch the project to react@canary/react@experimental and wrap both tab contents
(the ManualInstallTab and CliInstallTab render branches) with ViewTransition so
the behavior is consistent across tabs.
In `@src/registry/registry.json`:
- Around line 16-136: Registry entries use camelCase "name" values causing
lookup mismatches; update each component "name" to kebab-case to match how MDX
passes slugs and the generator's expectation. Edit src/registry/registry.json
and replace names like verticalTab, rippleButton, spinningText, staggerText,
linkPreview, bubbleUpButton, expandableTabs with vertical-tab, ripple-button,
spinning-text, stagger-text, link-preview, bubble-up-button, expandable-tabs
respectively (leave other fields unchanged). After change, run the registry
generator (the script that documents "kebab-case directory name") or validate
that MDX ComponentInstallation lookups succeed.
In `@src/styles/theme-data.css`:
- Around line 6-9: The CSS custom properties --font-sans, --font-mono, and
--font-rubik currently alias themselves (e.g., --font-sans: var(--font-sans))
causing circular, unresolved values; replace each of those declarations with
real font-family fallbacks (for example set --font-sans to a stack like "Inter,
system-ui, -apple-system, sans-serif") or remove the unused variables entirely,
and apply the same change to any duplicate declarations elsewhere in the
codebase to ensure fonts actually resolve.
🟠 Major comments (20)
src/components/common/tabs.tsx-24-44 (1)
24-44:⚠️ Potential issue | 🟠 MajorAdd tab semantics and keyboard navigation.
This is a tabs UI but lacks
role="tablist"/"tab"/"tabpanel",aria-selected,aria-controls, and keyboard navigation, which makes it inaccessible to screen readers and keyboard users.Minimal a11y wiring (example)
- <div className="bg-secondary max-w-[calc(100vw-16px) relative flex w-fit overflow-auto rounded-xl p-1 md:max-w-[auto] md:space-x-2"> + <div + role="tablist" + aria-orientation="horizontal" + className="bg-secondary max-w-[calc(100vw-16px)] relative flex w-fit overflow-auto rounded-xl p-1 md:max-w-[auto] md:space-x-2" + > {tabs.map((tab, index) => ( <Button key={index} className={cn("relative cursor-pointer rounded-lg")} onClick={() => setActiveTab(index)} data-active={activeTab === index} + role="tab" + id={`${tabId}-tab-${index}`} + aria-selected={activeTab === index} + aria-controls={`${tabId}-panel-${index}`} + tabIndex={activeTab === index ? 0 : -1} > {activeTab === index && ( <motion.div layoutId={`active-tab-${tabId}`} className="bg-background/90 absolute inset-0 h-full w-full rounded-lg border-2" transition={{ type: "spring", bounce: 0.2, duration: 0.6 }} /> )} <span className="relative z-10 block px-4 py-2">{tab.title}</span> </Button> ))} </div> - <div className="tabs-content">{tabs[activeTab]?.content}</div> + <div + role="tabpanel" + id={`${tabId}-panel-${activeTab}`} + aria-labelledby={`${tabId}-tab-${activeTab}`} + className="tabs-content" + > + {tabs[activeTab]?.content} + </div>You’ll also want ArrowLeft/ArrowRight/Home/End key handling to complete keyboard support.
registry.json-72-102 (1)
72-102:⚠️ Potential issue | 🟠 MajorAdd missing
motiondependency to Marquee and Ripple Button registry entries.Both components import from
motion/reactbut theirdependenciesarrays don't include it:
- Marquee declares only
["react-use-measure"], missing"motion"- Ripple Button declares
[], missing"motion"This will break downstream installs via the registry. Update both entries to include
"motion"in their dependencies arrays.public/r/spinning-text.json-8-15 (1)
8-15:⚠️ Potential issue | 🟠 MajorAdd missing
motiondependency to manifest.The embedded code imports
motion/react, but the registry entry lists no dependencies. This will break consumers pulling from the public registry.Suggested JSON update
- "dependencies": [], + "dependencies": [ + "motion" + ],public/r/vertical-tab.json-8-15 (1)
8-15:⚠️ Potential issue | 🟠 MajorAdd missing dependencies for imported packages to the registry manifest.
The component code imports
motion/reactandreact-use-measure, but both packages are missing from the dependencies array. This will cause installation failures for consumers. Add them to match the pattern used in other registry components likeaccordionandmarquee.Suggested JSON fix
- "dependencies": [], + "dependencies": [ + "motion", + "react-use-measure" + ],src/registry/registry.json-16-89 (1)
16-89:⚠️ Potential issue | 🟠 MajorAdd missing external dependency
motionto components that import it.
verticalTab,spinningText, andrippleButtonall importmotion/react, butdependenciesdon't includemotion. This will cause broken installs when users consume registry entries.
verticalTab: Add"motion"to dependenciesspinningText: Add"motion"to dependenciesrippleButton: Add"motion"to dependencies(Note:
accordionalready hasmotioncorrectly listed.)🛠️ Suggested JSON updates
"dependencies": [ - "react-use-measure" + "react-use-measure", + "motion" ]- "dependencies": [] + "dependencies": [ + "motion" + ]- "dependencies": [] + "dependencies": [ + "motion" + ]public/r/stagger-text.json-14-15 (1)
14-15:⚠️ Potential issue | 🟠 MajorRegistry entry is missing the
motiondependency.The embedded component imports
motion/react(line 9 of the file content), butdependenciesis empty. Registry consumers will miss-install the package and hit module resolution errors.Suggested fix
- "dependencies": [], + "dependencies": ["motion"],public/r/bubble-up-button.json-14-15 (1)
14-15:⚠️ Potential issue | 🟠 MajorAdd the missing
motiondependency.
The component importsmotion/react, but the dependency is not declared. Consumers using the CLI will not automatically install it.Suggested fix
- "dependencies": [], + "dependencies": ["motion"],src/components/code-block/code-block-source.tsx-9-18 (1)
9-18:⚠️ Potential issue | 🟠 MajorConstrain
filePathinreadFileContentto trusted locations.The
readFileContentfunction insrc/lib/file-utils.tsaccepts an arbitraryfilePathand joins it withprocess.cwd()without validating against path traversal attacks. A malicious or accidental path like../../../../etc/passwdcould read arbitrary server files. Add a normalization check to ensure paths stay within the intended directory.🛡️ Example fix
+import path from "node:path"; ... export async function readFileContent(filePath: string): Promise<string> { try { - const fullPath = path.join(process.cwd(), filePath); + const root = path.join(process.cwd(), "src"); + const resolved = path.resolve(root, filePath); + if (!resolved.startsWith(root + path.sep)) { + throw new Error("Invalid filePath"); + } + const fullPath = resolved; const content = await fs.readFile(fullPath, "utf-8"); return content;src/components/code-block/internal-code-block.tsx-15-23 (1)
15-23:⚠️ Potential issue | 🟠 Major
classNamefrom props is overwritten.
BecauseclassNameis set after{...props}, any caller‑providedclassNameis discarded. Merge instead.🔧 Suggested fix
-import * as React from "react"; +import * as React from "react"; +import { cn } from "@/lib/utils"; ... -export function InternalCodeBlock({ - code, - language, - filename, - ...props -}: InternalCodeBlockProps) { +export function InternalCodeBlock({ + code, + language, + filename, + className, + ...props +}: InternalCodeBlockProps) { return ( - <CodeBlock code={code} language={language} {...props} className=" my-4"> + <CodeBlock + code={code} + language={language} + {...props} + className={cn("my-4", className)} + >public/r/link-preview.json-9-9 (1)
9-9:⚠️ Potential issue | 🟠 MajorPositioning logic may cause incorrect popup placement.
The embedded LinkPreview component calculates popup position using
containerBounds.leftandcontainerBounds.top(viewport-relative coordinates fromgetBoundingClientRect), but applies them directly to an absolutely positioned element rendered as a sibling fragment. This will only work correctly if the popup's positioned ancestor is at(0,0)of the viewport. In most layouts with scrolling or nested positioned containers, the popup will appear misaligned.Consider either:
- Using
position: fixedfor the popup (with viewport coordinates)- Calculating the offset relative to the positioned ancestor
- Using a portal to render at the document body level
public/r/link-preview.json-14-15 (1)
14-15:⚠️ Potential issue | 🟠 MajorMissing runtime dependencies in the registry manifest.
The component imports
motion/react,react-icons/fa6, andreact-use-measure, but thedependenciesarray is empty. Consumers installing this component via the shadcn CLI won't have these packages installed automatically.Suggested fix
- "dependencies": [], + "dependencies": ["motion", "react-icons", "react-use-measure"],public/r/ripple-button.json-14-15 (1)
14-15:⚠️ Potential issue | 🟠 MajorMissing motion dependency.
The component imports from
motion/reactbut thedependenciesarray is empty.Suggested fix
- "dependencies": [], + "dependencies": ["motion"],public/r/expandable-tabs.json-14-15 (1)
14-15:⚠️ Potential issue | 🟠 MajorMissing runtime dependencies.
The component imports from
motion/reactandreact-icons, but these are not listed in thedependenciesarray. This will cause installation failures for consumers using the shadcn CLI.Suggested fix
- "dependencies": [], + "dependencies": ["motion", "react-icons"],public/r/magnetic-button.json-14-15 (1)
14-15:⚠️ Potential issue | 🟠 MajorMissing motion dependency.
The component imports from
motion/reactbut thedependenciesarray is empty. This will cause installation issues for consumers.Suggested fix
- "dependencies": [], + "dependencies": ["motion"],scripts/build-registry-json.ts-86-95 (1)
86-95:⚠️ Potential issue | 🟠 MajorSpread operator may unintentionally override computed fields.
The
...metadataspread at the end will override any previously set fields (name,type,title,description,files,dependencies,registryDependencies) if they exist in the metadata object. This is likely unintended since you're computing these values explicitly.Suggested fix - spread metadata first
const entry = { + ...metadata, // Apply metadata first so explicit values take precedence name: componentName, type: "registry:ui", title: metadata.title || toTitleCase(componentName), description: metadata.description || `Component for ${componentName}`, files: componentFiles, dependencies: metadata.dependencies || [], registryDependencies: metadata.registryDependencies || [], - ...metadata, // overwrite with specific metadata if exists };scripts/update-registry-json.ts-9-23 (1)
9-23:⚠️ Potential issue | 🟠 MajorComplete the migration from
framer-motiontomotionor remove unused package from KNOWN_DEPENDENCIES.The codebase still has 3 active imports from
framer-motion(in src/registry/index.ts, src/registry/sonaui/accordion/animated-plus-minus-button.tsx, and src/components/common/scroll-up-button.tsx), but themotionpackage is listed in KNOWN_DEPENDENCIES and installed as a dependency without being used. Either finish migrating all components to use themotionpackage and remove"framer-motion"from KNOWN_DEPENDENCIES, or remove"motion"if it's no longer needed.scripts/build-registry.ts-246-257 (1)
246-257:⚠️ Potential issue | 🟠 MajorNormalize componentMetadata keys to kebab-case to avoid lookup misses.
The generated registry uses kebab-case component IDs (from folder names), but componentMetadata keys are taken verbatim from
registry.json(camelCase in the current output).ComponentInstallationServerindexes by the kebab-case component string, so metadata will resolve toundefinedfor names likevertical-tabvsverticalTab. Normalize keys when ingestingregistry.json.✅ Suggested fix
- componentMetadata = registryData.reduce((acc: any, item: any) => { + componentMetadata = registryData.reduce((acc: any, item: any) => { // Normalize usage fields if they are arrays if (item.usage) { if (Array.isArray(item.usage.imports)) { item.usage.imports = item.usage.imports.join("\n"); } if (Array.isArray(item.usage.code)) { item.usage.code = item.usage.code.join("\n"); } } - acc[item.name] = item; + const key = toKebabCase(item.name); + acc[key] = { ...item, name: key }; return acc; }, {});public/r/registry.json-58-162 (1)
58-162:⚠️ Potential issue | 🟠 MajorFill in missing dependency lists for motion/react, react-use-measure, react-icons.
Several components use external packages but list incomplete or empty dependencies, which will cause shadcn CLI installs to fail:
bubble-up-button,ripple-button,stagger-textimportmotion/reactbut have no dependencies listedvertical-tabimports bothmotion/reactandreact-use-measurebut has no dependencies listedexpandable-tabsimportsmotion/reactandreact-iconsbut has no dependencies listedlink-previewimportsmotion/react,react-icons, andreact-use-measurebut has no dependencies listedmarqueeimportsmotion/reactbut only listsreact-use-measureaccordion'sanimated-plus-minus-button.tsximportsframer-motionwhile the manifest declares"motion"as a dependency; align this discrepancyExample dependency fixes (apply similarly)
{ "name": "bubble-up-button", "type": "registry:ui", "title": "Bubble Up Button", "description": "Component for bubble-up-button", "files": [ { "path": "registry/sonaui/bubble-up-button/bubble-up-button.tsx", "type": "registry:ui", "target": "components/sona-ui/bubble-up-button/bubble-up-button.tsx" } ], - "dependencies": [], + "dependencies": ["motion"], "registryDependencies": [] }, { "name": "vertical-tab", "type": "registry:ui", "title": "Vertical Tab", "description": "Component for vertical-tab", "files": [ { "path": "registry/sonaui/vertical-tab/vertical-tab.tsx", "type": "registry:ui", "target": "components/sona-ui/vertical-tab/vertical-tab.tsx" } ], - "dependencies": [], + "dependencies": ["motion", "react-use-measure"], "registryDependencies": [] }, { "name": "expandable-tabs", "type": "registry:ui", "title": "Expandable Tabs", "description": "Component for expandable-tabs", "files": [ { "path": "registry/sonaui/expandable-tabs/expandable-tabs.tsx", "type": "registry:ui", "target": "components/sona-ui/expandable-tabs/expandable-tabs.tsx" } ], - "dependencies": [], + "dependencies": ["motion", "react-icons"], "registryDependencies": [] }, { "name": "link-preview", "type": "registry:ui", "title": "Link Preview", "description": "Component for link-preview", "files": [ { "path": "registry/sonaui/link-preview/link-preview.tsx", "type": "registry:ui", "target": "components/sona-ui/link-preview/link-preview.tsx" } ], - "dependencies": [], + "dependencies": ["motion", "react-icons", "react-use-measure"], "registryDependencies": [] }src/components/common/mdx-components.tsx-5-25 (1)
5-25:⚠️ Potential issue | 🟠 MajorAdd "use client" directive and resolve client/server component mixing in the MDX components map.
This module uses the
useMDXComponentReact hook (line 146) but lacks a"use client"directive, which will cause Next.js to throw an error since hooks can only run in client components. Additionally, thecomponentsobject (lines 46–138) mixes client-only components (Tabs, CodeBlock variants, CodeSyntaxHighlighter, ComponentWrapper) with server-only components (ComponentInstallationServer, ComponentUsageServer, ComponentPreviewServer), creating a client/server boundary violation.Add
"use client"at the top of the file, then either split the component map into separate server/client modules or use dynamic imports to wrap server-only components so they're not directly imported into a client module.src/components/code-block/code-block.tsx-130-140 (1)
130-140:⚠️ Potential issue | 🟠 MajorPrevent stale async highlight results from overwriting newer code. When
code/languagechanges quickly, earlier promises can resolve after newer ones and callsetNodes()with stale results. Add a cancellation flag in the effect cleanup to guard against this race condition.✅ Suggested fix (cancel stale async results)
useLayoutEffect(() => { - // Only run async highlighting when no pre-rendered content - if (!initial) { - const normalizedLanguage = (language as BundledLanguage) || "javascript"; - void highlight(code, normalizedLanguage, { - highlightLines, - showDiff, - focusLines, - }).then(setNodes); - } + if (initial) return; + let cancelled = false; + const normalizedLanguage = (language as BundledLanguage) || "javascript"; + void highlight(code, normalizedLanguage, { + highlightLines, + showDiff, + focusLines, + }).then((result) => { + if (!cancelled) setNodes(result); + }); + return () => { + cancelled = true; + }; }, [code, language, initial, highlightLines, showDiff, focusLines]);
🟡 Minor comments (22)
src/content/docs/ripple-button.mdx-3-3 (1)
3-3:⚠️ Potential issue | 🟡 MinorUpdate sitemap.ts to use the new slug format.
The documentation slug was changed to
ripple-button, butsrc/app/sitemap.tsstill references the old camelCase formatrippleButton. Update the sitemap entry to match the new slug to ensure proper navigation and SEO consistency.src/components/common/start-count.tsx-21-26 (1)
21-26:⚠️ Potential issue | 🟡 MinorKeep a screen-reader label on small screens.
The label is now fully hidden on small screens, which can remove the accessible name. Consider keeping it
sr-onlyfor small viewports and visible on large.Suggested adjustment
- <span className="hidden leading-3.5 lg:block">Star on GitHub</span> + <span className="sr-only lg:not-sr-only">Star on GitHub</span>FEATURE_REQUEST_SHADCN_REGISTRY.md-28-28 (1)
28-28:⚠️ Potential issue | 🟡 MinorTypo: "strucute" should be "structure".
📝 Proposed fix
-# page strucute +# page structuresrc/content/docs/accordion.mdx-41-41 (1)
41-41:⚠️ Potential issue | 🟡 MinorTypo: "Splited" should be "Splitted".
The section header has a spelling error. Note that line 43 correctly uses "splitted".
📝 Proposed fix
-### Splited +### Splittedsrc/components/common/prop-table.tsx-21-23 (1)
21-23:⚠️ Potential issue | 🟡 Minor
rounded-lg!is invalid Tailwind syntax.If you need the important modifier, the
!must prefix the class.Proposed fix
- className="props-table overflow-clip rounded-lg! border border-border text-wrap shadow-sm" + className="props-table overflow-clip !rounded-lg border border-border text-wrap shadow-sm"src/components/common/tabs.tsx-24-26 (1)
24-26:⚠️ Potential issue | 🟡 MinorFix malformed Tailwind class token.
max-w-[calc(100vw-16px)is missing the closing], so the max-width rule won’t apply.Proposed fix
- <div className="bg-secondary max-w-[calc(100vw-16px) relative flex w-fit overflow-auto rounded-xl p-1 md:max-w-[auto] md:space-x-2"> + <div className="bg-secondary max-w-[calc(100vw-16px)] relative flex w-fit overflow-auto rounded-xl p-1 md:max-w-[auto] md:space-x-2">src/components/copy-button/lib/copy-to-clipboard.ts-1-22 (1)
1-22:⚠️ Potential issue | 🟡 MinorGuard for non-browser usage and ensure cleanup in
finally.If this helper is ever invoked outside the browser, it will throw. Also, if
execCommandfails mid-way, the textarea may not be removed.Proposed fix
export async function copyToClipboard(text: string): Promise<boolean> { + if (typeof navigator === "undefined" || typeof document === "undefined") { + return false; + } try { // Try modern Clipboard API first await navigator.clipboard.writeText(text); return true; } catch { // Fallback to legacy execCommand method try { const textarea = document.createElement("textarea"); textarea.value = text; textarea.style.position = "fixed"; textarea.style.opacity = "0"; document.body.appendChild(textarea); textarea.select(); - - const success = document.execCommand("copy"); - document.body.removeChild(textarea); - - return success; + try { + return document.execCommand("copy"); + } finally { + document.body.removeChild(textarea); + } } catch { return false; } } }src/registry/examples/ripple-button/ripple-button-demo.tsx-22-31 (1)
22-31:⚠️ Potential issue | 🟡 MinorForward
classNameand remaining props toRippleButton.
classNameand...propsare accepted but never applied, so styling/ARIA/disabled props are silently dropped. Consider forwarding and merging.Proposed fix
export default function RippleButtonExample({ textProps, buttonProps, className, ...props }: RippleButtonEx1Props) { + const mergedClassName = [className, buttonProps?.className] + .filter(Boolean) + .join(" "); return ( - <RippleButton {...buttonProps}> + <RippleButton {...props} {...buttonProps} className={mergedClassName}> <RippleButtonText {...textProps} text="Hover me!" /> </RippleButton> ); };src/app/globals.css-197-199 (1)
197-199:⚠️ Potential issue | 🟡 MinorUndefined CSS variable
--color-codeWrapper.The rule
pre > code spanreferencesvar(--color-codeWrapper), but this variable is not defined in:rootor the@theme inlineblocks. This will result in no background color being applied.🐛 Define the missing variable
Add to the
:rootblock:--scrollbar: light-dark(oklch(0.87 0 0), oklch(0.7 0 0)); + --codeWrapper: transparent; /* or your desired color */And expose it in
@theme inline:--color-scrollbar: var(--scrollbar); + --color-codeWrapper: var(--codeWrapper);scripts/sync-releases.ts-64-74 (1)
64-74:⚠️ Potential issue | 🟡 MinorRaw
release.bodyinjection may produce malformed MDX.The release body is inserted directly without sanitization. If any release body contains MDX frontmatter delimiters (
---) or invalid JSX, the generated file may fail to parse. Additionally, the<Divider/>component is used but never imported in the generated MDX.🛡️ Suggested improvements
const content = releases .map((release) => { + // Escape potential frontmatter delimiters in body + const safeBody = release.body?.replace(/^---$/gm, '\\---') ?? ''; return ` -${release.body} +${safeBody} [View on GitHub](${release.html_url}) -<Divider/> `; }) - .join("\n---\n\n"); + .join("\n\n---\n\n");Also consider adding an import statement for
<Divider/>in the frontmatter section if you keep using it, or replace it with a standard Markdown horizontal rule (---).src/app/globals.css-143-145 (1)
143-145:⚠️ Potential issue | 🟡 MinorMissing
floatkeyframes definition.Line 144 references
--animate-float: float 4s ease-in-out infinitebut thefloatkeyframes are not defined. Onlyfade-in-upkeyframes are present (lines 146-155).🐛 Add the missing keyframes
`@keyframes` fade-in-up { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } + + `@keyframes` float { + 0%, 100% { + transform: translateY(0); + } + 50% { + transform: translateY(-10px); + } + } }src/content/docs/installation.mdx-26-35 (1)
26-35:⚠️ Potential issue | 🟡 MinorCLI command format inconsistency.
The documentation shows
npx shadcn@latest add@sona-ui/magnetic-button``, butcomponent-installation.tsx(line 42) uses `npx sona-ui@latest add ${component}`. Please align these command formats across the documentation and code to avoid user confusion.src/content/docs/installation.mdx-43-46 (1)
43-46:⚠️ Potential issue | 🟡 MinorFilename casing inconsistency in manual instructions.
Step 3 suggests saving as
components/ui/Accordion.tsx(PascalCase), but the PR normalizes filenames to kebab-case (e.g.,accordion.tsx). Consider updating to match the actual file naming convention used in the registry.Proposed fix
-3. Copy the code into a file in your project (e.g., `components/ui/Accordion.tsx`). +3. Copy the code into a file in your project (e.g., `components/ui/accordion.tsx`).src/styles/theme-data.css-73-75 (1)
73-75:⚠️ Potential issue | 🟡 MinorMissing
floatkeyframes definition.
--animate-floatreferencesfloat 4s ease-in-out infinitebut only thefade-in-upkeyframes are defined (lines 76-85). Thefloatkeyframes need to be added for this animation to work.Proposed fix - add float keyframes
`@keyframes` fade-in-up { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } + + `@keyframes` float { + 0%, 100% { + transform: translateY(0); + } + 50% { + transform: translateY(-10px); + } + } }src/content/docs/theming.mdx-53-180 (1)
53-180:⚠️ Potential issue | 🟡 MinorUpdate CSS filename references to match the actual repo file.
The documentation references
global.css, but the actual file isglobals.css. Update both the text and the code block filename attribute:Changes required
-You can customize the color palette by overriding the Tailwind CSS configuration in your `global.css` file. +You can customize the color palette by overriding the Tailwind CSS configuration in your `globals.css` file.-`} language="" filename="global.css" /> +`} language="" filename="globals.css" />src/components/common/theme-toggle.tsx-10-55 (1)
10-55:⚠️ Potential issue | 🟡 MinorUse
resolvedThemeto show correct active state when theme is set to "system".Currently, when
themeis"system", neither button appears active because the checks only look for explicit"dark"or"light"values. UsingresolvedThemeensures the button matching the actual OS-resolved theme displays as active.Note: This changes the default behavior when the theme is undefined—it will no longer default to showing dark mode as active.
Suggested adjustment
- const { setTheme, theme } = useTheme(); + const { setTheme, resolvedTheme } = useTheme(); ... - data-active={theme === "dark" || theme === undefined} + data-active={resolvedTheme === "dark"} ... - theme: theme === "dark" ? "opacity-100" : "opacity-75", + theme: resolvedTheme === "dark" ? "opacity-100" : "opacity-75", ... - data-active={theme === "light" || theme === undefined} + data-active={resolvedTheme === "light"}src/components/common/component-preview-server.tsx-1-27 (1)
1-27:⚠️ Potential issue | 🟡 MinorFix RSC serialization pattern: pass component function instead of JSX element.
The props signature is correct (
component: React.ReactNode; code: string), but passing<example.component />(a JSX element) from the server component to the client component violates React Server Component best practices. Instead, pass the component function itself and instantiate it inside the client component. Change<ComponentPreview component={<example.component />} code={example.code} />to<ComponentPreview component={example.component} code={example.code} />and updateComponentPreviewto handleReact.ComponentTyperather thanReact.ReactNode.src/registry/examples/link-preview/link-preview-demo.tsx-6-6 (1)
6-6:⚠️ Potential issue | 🟡 MinorFix heading grammar.
“Projects that I works on!!!” → “Projects that I work on”.✍️ Suggested fix
- <h3>Projects that I works on!!!</h3> + <h3>Projects that I work on</h3>src/components/code-block/lib/transformers/utils.ts-11-16 (1)
11-16:⚠️ Potential issue | 🟡 MinorMake array input normalization consistent with string input in
parseLineRange.Array input is returned as-is while string input is deduplicated and sorted, creating behavioral inconsistency. The callers (highlight-lines.ts, focus.ts) both defensively apply
new Set()afterwards, suggesting this normalization should happen within the function.♻️ Suggested fix
- if (Array.isArray(input)) return input; + if (Array.isArray(input)) { + return Array.from(new Set(input)).sort((a, b) => a - b); + }public/r/expandable-tabs.json-9-9 (1)
9-9:⚠️ Potential issue | 🟡 MinorKeyboard activation missing for interactive tab elements.
The embedded component renders tabs with
role="button"andtabIndex={0}, making them focusable and announcing them as buttons to assistive technology. However, there's noonKeyDownhandler to activate them via Enter or Space keys, which is expected for elements withrole="button".Suggested keyboard handler addition
onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setIsActive(index); } }}public/r/ripple-button.json-9-9 (1)
9-9:⚠️ Potential issue | 🟡 MinorContradictory accessibility attributes on RippleButtonText.
In the embedded code,
RippleButtonTextrenders a<span>with bothrole="presentation"andaria-label="ripple-button-text". Therole="presentation"removes the element from the accessibility tree, making thearia-labelineffective. Choose one approach:
- Remove
role="presentation"if the label should be announced- Remove
aria-labelif the element is truly presentationalscripts/build-registry-json.ts-139-142 (1)
139-142:⚠️ Potential issue | 🟡 MinorLog message inconsistent with actual output path.
The log message states the public index is written to
public/r/index.json, but line 135 writes topublic/r/registry.json.Suggested fix
console.log(`Registry generated: - Root: registry.json - - Public Index: public/r/index.json + - Public Index: public/r/registry.json - Individual Items: public/r/*.json`);
🧹 Nitpick comments (22)
src/components/common/component-wrapper.tsx (1)
18-18: UI styling improvements look good.The addition of
min-h-[350px]ensures consistent height for component previews, androunded-xlprovides a more pronounced border radius.Minor nitpick: There's a double space between
bg-secondaryandmin-h-[350px]in the class string. Not a functional issue, but could be cleaned up for consistency.🧹 Optional: Remove extra space
- "xs:w-full bg-secondary min-h-[350px] flex w-[calc(100vw-16px)] items-center justify-center overflow-clip rounded-xl border p-4 shadow-lg sm:w-full md:p-6", + "xs:w-full bg-secondary min-h-[350px] flex w-[calc(100vw-16px)] items-center justify-center overflow-clip rounded-xl border p-4 shadow-lg sm:w-full md:p-6",src/components/common/Fade.tsx (1)
1-71: Consider renaming file to kebab-case for consistency.The PR is normalizing filenames to kebab-case (e.g.,
animated-link.tsx,component-wrapper.tsx), but this file remainsFade.tsx(PascalCase). Consider renaming tofade.tsxfor consistency across the codebase.src/components/button/index.tsx (1)
8-13: Unusedhrefprop in interface.The
hrefprop is defined inButtonPropsbut never used in the component implementation. If this is intended for link-like button behavior, consider implementing it (e.g., rendering an anchor whenhrefis provided) or remove it to avoid confusion.♻️ Option: Remove unused prop or implement link behavior
If not needed:
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> { children: ReactNode; className?: string; variant?: "default" | "outline" | "filled"; - href?: string; }Or implement as link button:
+import Link from "next/link"; + export default function Button({ children, className, variant = "default", + href, ...props }: ButtonProps) { // ... + if (href) { + return ( + <Link href={href} className={cn(baseClasses, variantClasses[variant], className)}> + {children} + </Link> + ); + } return ( <BaseButtonscripts/generate-usage-code.ts (1)
18-21: Normalize CRLF and trim trailing empty line to avoid noisy entries.Proposed tweak
- const content = fs.readFileSync(absolutePath, "utf-8"); - const lines = content.split("\n"); + const content = fs.readFileSync(absolutePath, "utf-8"); + const normalized = content.replace(/\r\n/g, "\n"); + const lines = normalized.split("\n"); + if (lines.length > 0 && lines[lines.length - 1] === "") { + lines.pop(); + }FEATURE_REQUEST_SHADCN_REGISTRY.md (1)
28-42: Consider expanding the page structure outline.The outline section (lines 28-42) appears to be rough notes. Consider either removing it from the feature request or expanding it with more detailed descriptions for each section to make it actionable.
src/lib/file-utils.ts (1)
14-16: Consider throwing instead of returning an error string.Returning
// Error reading file: ${filePath}silently masks failures—callers may unknowingly render this as valid code content. If this is intentional (graceful degradation in code blocks), consider logging at a higher severity or adding a distinct return type to differentiate success from failure.♻️ Alternative: use a Result-style return or re-throw
- } catch (error) { - console.error(`Error reading file at ${filePath}:`, error); - return `// Error reading file: ${filePath}`; - } + } catch (error) { + console.error(`Error reading file at ${filePath}:`, error); + throw new Error(`Failed to read file: ${filePath}`); + }Or, if graceful degradation is intended, return a structured result:
type ReadResult = { success: true; content: string } | { success: false; error: string };src/components/hero/index-old.tsx (1)
1-89: Consider removing or deprecating this old file.The filename
index-old.tsxsuggests this is a legacy version. If it's no longer used, consider removing it to avoid maintenance overhead. If kept for reference, add a comment explaining its purpose.package.json (1)
11-15: Confirm Bun is required and documented for dev/build.
predevandprebuildnow callbunscripts. Please ensure CI and contributors have Bun available (or add an engines/packageManager hint + docs).scripts/sync-releases.ts (1)
39-41: UnusedformatDatefunction.The
formatDatefunction is defined but never called anywhere in the script. Consider removing it or using it in thegenerateMarkdownfunction (e.g., to displaypublished_atfor each release).♻️ Either remove the function or use it
If you want to display dates:
return ` +## ${release.name || release.tag_name} - ${formatDate(release.published_at)} + ${release.body} [View on GitHub](${release.html_url})Or remove the unused function:
-function formatDate(dateString: string) { - return new Date(dateString).toISOString().split("T")[0]; -} -src/components/copy-button/copy-button.tsx (1)
21-26: Silent failure on copy operation.The
copyfunction silently ignores failures. Users won't know if the copy failed. Consider adding optional error feedback.♻️ Optional: Add failure state handling
+export function useCopyToClipboard(timeout: number = 2000) { + const [copied, setCopied] = useState(false); + const [error, setError] = useState(false); // Clean up timeout on unmount or when copied changes useEffect(() => { if (copied) { const timer = setTimeout(() => setCopied(false), timeout); return () => clearTimeout(timer); } }, [copied, timeout]); const copy = async (text: string) => { const success = await copyToClipboard(text); if (success) { setCopied(true); + setError(false); + } else { + setError(true); + setTimeout(() => setError(false), timeout); } }; - return { copied, copy }; + return { copied, copy, error }; }src/registry/sonaui/accordion/accordion.tsx (1)
27-41: Typo in variable name and redundant variant definitions.
accordionWrapperVarinatshas a typo - should beaccordionWrapperVariants- All three variants have identical classes (
"overflow-clip rounded-2xl"), making the variant system ineffective for the wrapper♻️ Fix typo and differentiate variants
-const accordionWrapperVarinats = cva( +const accordionWrapperVariants = cva( "flex flex-col overflow-clip rounded-2xl", { variants: { variant: { - default: "overflow-clip rounded-2xl", - outlined: "overflow-clip rounded-2xl", - splitted: "overflow-clip rounded-2xl", + default: "", + outlined: "border border-border", + splitted: "overflow-visible rounded-none", }, }, defaultVariants: { variant: "default", }, }, );Also update line 114:
- accordionWrapperVarinats({ variant }), + accordionWrapperVariants({ variant }),src/registry/examples/accordion/accordion-splitted.tsx (1)
1-65: LGTM!Clean example demonstrating the splitted accordion variant. Structure aligns with existing accordion examples.
Minor nit: Line 60 has an empty
className=""on the<p>element which can be removed.src/registry/examples/accordion/accordion-outlined.tsx (1)
10-45: Consider extracting shared accordion data.The
accordionDataarray is duplicated acrossaccordion-demo.tsx,accordion-outlined.tsx,accordion-multistep.tsx, andaccordion-splitted.tsx. Consider extracting this to a shared constant to reduce duplication and ease maintenance.src/registry/examples/accordion/accordion-multistep.tsx (1)
9-9: Consider renaming for clarity.The name
AccordionMultiStepExamplemight be misleading as "multi-step" typically refers to wizard/stepper patterns. Since this example demonstratesallowMultiple={true}behavior, a name likeAccordionMultiOpenExampleorAccordionMultipleExamplewould better convey the intent.src/components/common/component-installation.tsx (3)
4-4: Remove unused import.
startTransitionis imported but never used in this component.Proposed fix
-import { startTransition, useState, ViewTransition } from "react"; +import { useState, ViewTransition } from "react";
26-29:registryDependenciesis defined but unused.The
registryDependenciesfield in the metadata interface is never referenced in the component logic. Either remove it or implement the intended functionality (perhaps to show peer registry component dependencies).
125-151: Consider extracting IIFE to a named component.The immediately-invoked function expression (IIFE) for rendering multiple files could be cleaner as a separate component or by lifting the
activeFilecalculation outside the JSX.Proposed refactor
- ) : ( - // Multiple files: use tabs - (() => { - const activeFile = - componentFiles.find((f) => f.path === activeFileTab) || - componentFiles[0]; - - return ( - <CodeBlock - code={activeFile.content} - language="tsx" - > + ) : (() => { + const activeFile = + componentFiles.find((f) => f.path === activeFileTab) || + componentFiles[0]; + return ( + <CodeBlock code={activeFile.content} language="tsx">Or extract
activeFilebefore the return statement for cleaner JSX.public/r/stagger-text.json (1)
9-9: Use grapheme‑safe splitting for user text.
text.split("")breaks surrogate pairs and combining marks (e.g., emoji), producing visual glitches. ConsiderArray.from(text)(basic) orIntl.Segmenter(full grapheme support).♻️ Suggested change
- {text.split("").map((char, i) => { + {Array.from(text).map((char, i) => {scripts/build-registry-json.ts (1)
23-23: Consider using async fs operations for consistency.The function is declared
asyncbut uses synchronousfsoperations (existsSync,mkdirSync,readFileSync,readdirSync,statSync,writeFileSync). While functional for a build script, usingfs/promiseswould be more consistent with the async declaration and avoid blocking the event loop.scripts/update-registry-json.ts (2)
7-7: Unused constantEXAMPLE_DIR.
EXAMPLE_DIRis defined but never referenced in the script.Suggested fix
-const EXAMPLE_DIR = path.join(process.cwd(), "src/registry/example");
164-171: MissingregistryDependenciesfield in registry entries.The registry entries pushed here don't include a
registryDependenciesfield, butscripts/build-registry-json.tsexpects it (line 93). This could cause inconsistencies between the two scripts' outputs.Suggested fix
registry.push({ name: component, // kebab-case directory name type: "registry:ui", title: title, description: description, files: files, dependencies: dependencies, + registryDependencies: [], // Add for consistency with build-registry-json.ts });public/r/magnetic-button.json (1)
9-9: Document-level event listener always active.The embedded component adds a
mousemovelistener todocumentregardless of hover state. For pages with many Magnetic components, this could impact performance. Consider adding the listener only whenisMouseHoveredis true, or using passive event listeners.This is a minor optimization consideration and may not be necessary depending on typical usage patterns.
| @theme inline { | ||
| /* Fonts */ | ||
| --font-sans: var(--font-sans); | ||
| --font-mono: var(--font-mono); | ||
| --font-rubik: var(--font-rubik); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, let's look at the globals.css file to see the full context
echo "=== Content of src/app/globals.css (lines 70-85) ==="
if [ -f "src/app/globals.css" ]; then
sed -n '70,85p' src/app/globals.css
else
echo "File not found, searching for globals.css..."
find . -name "globals.css" -type f 2>/dev/null
fiRepository: Dinil-Thilakarathne/sona-ui
Length of output: 678
🏁 Script executed:
#!/bin/bash
# Search for font variable definitions in layout files and imports
echo "=== Layout files that might define fonts ==="
find . -path ./node_modules -prune -o -name "layout.*" -type f -print | head -10
echo -e "\n=== Searching for --font variable definitions ==="
rg -n '\-\-font-' --type=css --type=ts --type=tsx -g '!node_modules' | head -30Repository: Dinil-Thilakarathne/sona-ui
Length of output: 258
🏁 Script executed:
#!/bin/bash
# Search for Next.js font setup
echo "=== Searching for font imports and setup ==="
rg -n 'from.*font|import.*font|fontFamily|localFont|Inter|Rubik' --type=ts --type=tsx -g '!node_modules' -C1 | head -50Repository: Dinil-Thilakarathne/sona-ui
Length of output: 160
🏁 Script executed:
#!/bin/bash
# Search for font variable definitions without type flags
echo "=== Searching for --font- definitions across project ==="
rg '\-\-font-' -g '!node_modules' -C2 | head -40
echo -e "\n=== Checking root CSS for font definitions ==="
find . -path ./node_modules -prune -o -name "*.css" -type f -print | xargs grep -l "font" 2>/dev/nullRepository: Dinil-Thilakarathne/sona-ui
Length of output: 1739
🏁 Script executed:
#!/bin/bash
# Read layout.tsx to see how fonts are set up
echo "=== Content of src/app/layout.tsx ==="
head -100 src/app/layout.tsx
echo -e "\n=== Searching for font imports and setup in layout ==="
cat src/app/layout.tsx | grep -i "font" -C3Repository: Dinil-Thilakarathne/sona-ui
Length of output: 1950
🏁 Script executed:
#!/bin/bash
# Search more broadly for font setup
echo "=== All mentions of font setup ==="
rg -i 'localFont|font.*loader|@import.*font' -g '!node_modules' -C2Repository: Dinil-Thilakarathne/sona-ui
Length of output: 362
Fix font variable name mismatch: CSS references undefined variables.
Lines 78-80 define circular references (--font-sans: var(--font-sans), etc.) that can never resolve. The actual fonts injected by Next.js in src/app/layout.tsx use different variable names: --font-geist-sans, --font-geist-mono, and --font-clash-display. The CSS is attempting to reference --font-sans, --font-mono, and --font-rubik, which are never defined anywhere in the project. These should either:
- Match the injected variable names (
--font-geist-sans,--font-geist-mono,--font-clash-display), or - Have actual font stack definitions instead of self-references
🧰 Tools
🪛 Biome (2.3.13)
[error] 76-156: Tailwind-specific syntax is disabled.
Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.
(parse)
🤖 Prompt for AI Agents
In `@src/app/globals.css` around lines 76 - 80, The CSS defines circular font
variables (--font-sans, --font-mono, --font-rubik) that reference themselves;
update the assignments inside the `@theme` block to reference the actual
Next.js-injected variables (--font-geist-sans, --font-geist-mono,
--font-clash-display) used in src/app/layout.tsx (or replace them with real font
stacks), e.g. set --font-sans: var(--font-geist-sans), --font-mono:
var(--font-geist-mono), and --font-rubik: var(--font-clash-display) so the
variables resolve correctly.
| </CodeBlockPre> | ||
| </CodeBlock> | ||
| </TabsContent> | ||
| <ViewTransition> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n src/components/common/component-installation.tsx | head -100Repository: Dinil-Thilakarathne/sona-ui
Length of output: 3613
🏁 Script executed:
rg "ViewTransition" src/components/common/component-installation.tsx -B 5 -A 5Repository: Dinil-Thilakarathne/sona-ui
Length of output: 777
🌐 Web query:
ViewTransition React 19.2 stability
💡 Result:
In React 19.2 (stable channel), <ViewTransition /> is not stable/GA—it’s only available in React’s Canary and Experimental channels, not the regular react@19.2 / react-dom@19.2 packages. (react.dev)
React’s own React Labs update (Apr 23, 2025) describes View Transitions as “new experimental features” that are “ready for testing in react@experimental” and notes they’ve been tested in production and are stable, but the final API may still change. It also explicitly says <ViewTransition /> and addTransitionType are available in react@canary (while a different feature, <Activity />, shipped in react@19.2). (uk.react.dev)
Related API docs also label unstable_addTransitionType as an experimental feature not available in a stable version of React yet, recommending react@experimental. (es.react.dev)
Citations:
- 1: https://react.dev/reference/react/ViewTransition?utm_source=openai
- 2: https://uk.react.dev/blog/2025/04/23/react-labs-view-transitions-activity-and-more?utm_source=openai
- 3: https://es.react.dev/reference/react/addTransitionType?utm_source=openai
ViewTransition is not available in stable React 19.2—use only react@canary or react@experimental.
ViewTransition is imported and used here, but it's an experimental feature only available in the canary and experimental channels, not in the stable react@19.2 package. Additionally, ViewTransition wraps only the manual tab content (line 78) while the CLI tab content (line 70) is unwrapped, creating inconsistent view transition behavior.
Either ensure the project uses react@canary or react@experimental, or remove ViewTransition if stable React 19.2 compatibility is required. If keeping ViewTransition, apply it consistently to both tab contents for uniform animation behavior.
🤖 Prompt for AI Agents
In `@src/components/common/component-installation.tsx` at line 78, The code uses
the experimental ViewTransition component (ViewTransition) which is not
available in stable react@19.2 and is applied only to the manual tab content
(ManualInstallTab) while the CLI tab (CliInstallTab) remains unwrapped, causing
both compatibility and inconsistent animation behavior; either remove the
ViewTransition import and wrapper entirely from the component
(ComponentInstallation) to remain compatible with stable React, or switch the
project to react@canary/react@experimental and wrap both tab contents (the
ManualInstallTab and CliInstallTab render branches) with ViewTransition so the
behavior is consistent across tabs.
| /* Fonts */ | ||
| --font-sans: var(--font-sans); | ||
| --font-mono: var(--font-mono); | ||
| --font-rubik: var(--font-rubik); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Check where base font variables are defined
rg -n "font-sans:|font-mono:|font-rubik:" --type=css src/Repository: Dinil-Thilakarathne/sona-ui
Length of output: 425
🏁 Script executed:
# Also check the actual theme-data.css file to see the context
cat -n src/styles/theme-data.cssRepository: Dinil-Thilakarathne/sona-ui
Length of output: 6954
🏁 Script executed:
# Check if globals.css or other CSS files exist and contain font definitions
fd "\.(css|scss)$" src/styles/ | head -20Repository: Dinil-Thilakarathne/sona-ui
Length of output: 96
🏁 Script executed:
cat -n src/app/globals.css | head -100Repository: Dinil-Thilakarathne/sona-ui
Length of output: 5013
Remove or define the circular font variable references.
The font variables in lines 7-9 reference themselves (--font-sans: var(--font-sans), etc.), creating unresolvable circular references. The same pattern appears identically in src/app/globals.css at lines 78-80. No base definitions for these variables exist in the codebase—neither in globals.css nor elsewhere. This will result in fonts not being applied. Either define actual font values (e.g., --font-sans: "Arial", sans-serif;) or remove these unused variable declarations.
🤖 Prompt for AI Agents
In `@src/styles/theme-data.css` around lines 6 - 9, The CSS custom properties
--font-sans, --font-mono, and --font-rubik currently alias themselves (e.g.,
--font-sans: var(--font-sans)) causing circular, unresolved values; replace each
of those declarations with real font-family fallbacks (for example set
--font-sans to a stack like "Inter, system-ui, -apple-system, sans-serif") or
remove the unused variables entirely, and apply the same change to any duplicate
declarations elsewhere in the codebase to ensure fonts actually resolve.
…ton to the Hero section with updated text animations, and remove the "Documentation" navigation link.
… enhanced descriptions, and externalized code.
|
🎉 This PR is included in version 2.10.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
This pull request introduces significant improvements to Sona UI by integrating it as a Shadcn-compatible registry, updating component registry files, enhancing the build process, and updating dependencies for better compatibility and developer experience.
Shadcn Registry Integration and Component Registry Updates:
components.jsonand a detailed feature request template describing the integration goals and benefits. [1] [2]accordion,bubble-up-button,expandable-tabs,link-preview,magnetic-button,marquee) in thepublic/r/directory, specifying component metadata, file paths, and dependencies for seamless use with the Shadcn CLI. [1] [2] [3] [4] [5] [6]Build Process and Developer Tooling Improvements:
package.jsonto provide new commands for building the registry and syncing releases, replacing the oldcopy-sources.jsapproach..vscode/settings.jsonto improve Tailwind CSS IntelliSense for custom class functions (cva,cx).Dependency Updates:
next,lucide-react,motion,arktype,posthog-js,tailwindcss, and more).These changes collectively enhance the developer experience, streamline component consumption via the Shadcn ecosystem, and modernize the build and dependency setup.
Summary by CodeRabbit
New Features
Documentation
Improvements