Skip to content

feat(mobile): expand demo screen with all UI components#1262

Merged
saddlepaddle merged 5 commits into
mainfrom
mobile-components
Feb 6, 2026
Merged

feat(mobile): expand demo screen with all UI components#1262
saddlepaddle merged 5 commits into
mainfrom
mobile-components

Conversation

@saddlepaddle
Copy link
Copy Markdown
Collaborator

@saddlepaddle saddlepaddle commented Feb 6, 2026

Summary

  • Expanded the mobile demo screen to exercise every UI component brought into the project: Button (all variants/sizes), Badge, Alert, Avatar, Input, Textarea, Checkbox, Switch, RadioGroup, Select, Progress (animated with controls), Tabs, Accordion, Collapsible, Dialog, AlertDialog, Popover, Tooltip, Toggle, ToggleGroup, Skeleton, AspectRatio, and Separator
  • Added Expo MCP server to project .mcp.json for Expo documentation access
  • Includes biome lint auto-fixes across UI components (removed unnecessary <> fragments, added missing dependency to useEffect)

Test plan

  • All existing tests pass (bun run test — 0 failures)
  • Typecheck passes (only pre-existing errors in input.tsx/textarea.tsx unrelated to this PR)
  • Biome lint passes
  • Verified all components render correctly on iOS simulator via Maestro screenshots with zero Metro errors

Summary by CodeRabbit

  • New Features

    • Added comprehensive UI component library for mobile, including Accordion, Alert, Avatar, Badge, Dialog, Menu, Select, Tabs, Toggle, Tooltip, and many more components.
    • Introduced component demo screen showcasing all new UI elements with live data integration.
    • Added MCP server configurations for Expo and Maestro support.
  • Chores

    • Updated dependencies across packages, including React Native primitives suite.
    • Reformatted code selector expression.

Exercise every UI component brought into the project (Button, Badge, Alert,
Avatar, Input, Textarea, Checkbox, Switch, RadioGroup, Select, Progress,
Tabs, Accordion, Collapsible, Dialog, AlertDialog, Popover, Tooltip, Toggle,
ToggleGroup, Skeleton, AspectRatio, Separator) alongside existing live data
sections. Add Expo MCP server to project config. Includes biome lint fixes
across UI components (unnecessary fragments, missing deps).
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 6, 2026

📝 Walkthrough

Walkthrough

This PR introduces a comprehensive cross-platform mobile UI component library built on @rn-primitives, adds MCP server configurations, updates package dependencies, and completely redesigns the demo screen with interactive component showcases and live data bindings.

Changes

Cohort / File(s) Summary
MCP Server Configuration
.mcp.json
Added two new MCP server entries: expo-mcp (HTTP endpoint) and maestro (CLI command with args).
Desktop UI Updates
apps/desktop/src/renderer/screens/.../FilesView.tsx
Refactored showHiddenFiles selector from multi-line to single-line expression; no functional logic changes.
Mobile UI Components
apps/mobile/components/ui/accordion.tsx, alert.tsx, alert-dialog.tsx, aspect-ratio.tsx, avatar.tsx, badge.tsx, button.tsx, checkbox.tsx, collapsible.tsx, context-menu.tsx, dialog.tsx, dropdown-menu.tsx, hover-card.tsx, icon.tsx, label.tsx, menubar.tsx, native-only-animated-view.tsx, popover.tsx, progress.tsx, radio-group.tsx, select.tsx, separator.tsx, skeleton.tsx, tabs.tsx, textarea.tsx, toggle.tsx, toggle-group.tsx, tooltip.tsx
Added 28 new cross-platform React Native UI components wrapping @rn-primitives with platform-specific styling, animations, and context-aware text rendering. Components support web/native branching, Reanimated animations, and responsive className composition.
Mobile Package Dependencies
apps/mobile/package.json
Added 22 @rn-primitives packages (v1.2.0) as dependencies covering accordion, alert-dialog, aspect-ratio, avatar, checkbox, collapsible, context-menu, dialog, dropdown-menu, hover-card, label, menubar, popover, progress, radio-group, select, separator, tabs, toggle, toggle-group, and tooltip.
Mobile Demo Screen
apps/mobile/screens/(authenticated)/demo/DemoScreen.tsx
Completely redesigned component showcase with 13 Card-based demo sections, interactive state management for form inputs, live data bindings via useLiveQuery, and comprehensive display of all new UI components with sample data and pluralization handling.
Workspace Package Updates
apps/streams/package.json, packages/durable-session/package.json
Updated dependencies: @durable-streams/client (0.2.0→0.2.1), added @hono/node-server (1.13.0), updated @tanstack/db (0.5.22) and zod (4.1.12→4.3.5); adjusted peer dependencies in durable-session to include lucide-react and updated React version ranges.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • PR #843 — Introduces the same mobile app UI component scaffolding and @rn-primitives dependency setup across the mobile components directory.
  • PR #866 — Modifies the same DemoScreen with component showcase expansion and live data integration patterns.
  • PR #1229 — Touches the same FilesView.tsx showHiddenFiles selector logic in the desktop app.

Poem

🐰 Twenty-eight components hopped into place,
Cross-platform wrappers with elegant grace,
Primitives styled for web and for native,
A demo screen blooming, so interactive!
Animations and context, the rabbit approves—
This component library's got all the right moves! 🎨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.32% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description covers the main objectives, includes a test plan, and provides context, but does not follow the required template structure with explicit sections. Structure the description to match the template: add a Description section header, clearly separate Related Issues, Type of Change, Testing, and Additional Notes sections with checkbox selections.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the primary change: expanding the demo screen to showcase all UI components in the mobile app.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mobile-components

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.

Use the simple `maestro mcp` command instead of hardcoded user paths,
so it works for any developer with maestro on their PATH.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 6, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch
  • ✅ Electric Fly.io app

Thank you for your contribution! 🎉

Rename to `placeholderTextColorClassName` to match the actual uniwind
type augmentation. Remove unused destructured prop from input.tsx.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Caution

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

⚠️ Outside diff range comments (1)
apps/mobile/components/ui/input.tsx (1)

4-31: ⚠️ Potential issue | 🟡 Minor

placeholderClassName is destructured but never passed to TextInput.

The prop is extracted on Line 6 and silently discarded. Compare with textarea.tsx (Line 21) which correctly forwards it: placeholderClassName={cn("text-muted-foreground", placeholderClassName)}. This looks like an oversight.

🐛 Proposed fix
 		<TextInput
 			className={cn(
 				"dark:bg-input/30 border-input bg-background text-foreground flex h-10 w-full min-w-0 flex-row items-center rounded-md border px-3 py-1 text-base leading-5 shadow-sm shadow-black/5 sm:h-9",
 				props.editable === false &&
 					cn(
 						"opacity-50",
 						Platform.select({
 							web: "disabled:pointer-events-none disabled:cursor-not-allowed",
 						}),
 					),
 				Platform.select({
 					web: cn(
 						"placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground outline-none transition-[color,box-shadow] md:text-sm",
 						"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
 						"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
 					),
 					native: "placeholder:text-muted-foreground/50",
 				}),
 				className,
 			)}
+			placeholderClassName={cn("text-muted-foreground", placeholderClassName)}
 			{...props}
 		/>
🤖 Fix all issues with AI agents
In `@apps/mobile/components/ui/alert.tsx`:
- Around line 22-27: The provider value for TextClassContext currently includes
the Alert component's className (cn(..., className)), which leaks outer
View/layout classes into descendant text styling; remove className from the
TextClassContext.Provider value and instead keep only text-related classes
(e.g., cn("text-sm text-foreground", variant === "destructive" &&
"text-destructive")). If you need consumer control over text classes, add an
explicit prop like textClassName and include that in the provider value; ensure
the original className continues to be applied only to the outer View/container.

In `@apps/mobile/components/ui/dropdown-menu.tsx`:
- Around line 133-145: The DropdownMenuPrimitive.Content className uses
context-menu CSS variables incorrectly; update the CSS variable names inside the
className string for DropdownMenuPrimitive.Content (the block rendering
DropdownMenuContent) by replacing --radix-context-menu-content-available-height
and --radix-context-menu-content-transform-origin with their dropdown-menu
equivalents (--radix-dropdown-menu-content-available-height and
--radix-dropdown-menu-content-transform-origin) so the animation and max-height
origin use the correct variables while preserving the Platform.select logic and
existing props/className merging.
- Around line 86-99: The className uses the wrong Radix CSS variable name
causing incorrect transform origin; in the web platform class strings for
DropdownMenuPrimitive.SubContent (inside NativeOnlyAnimatedView) and the sibling
DropdownMenuContent component, replace occurrences of
"--radix-context-menu-content-transform-origin" with
"--radix-dropdown-menu-content-transform-origin" (i.e., update the origin-(...)
token) so the dropdown menu uses the correct per-component CSS custom property
for transform origin.

In `@apps/mobile/components/ui/icon.tsx`:
- Around line 24-37: Update the JSDoc example import path to match the actual
module export for the Icon component: locate the JSDoc block above the Icon
component (search for "A wrapper component for Lucide icons" and the Icon
symbol) and change the example import from
"@/registry/uniwind/registry/components/ui/icon" to the correct module path that
exports Icon (the actual path used in the codebase where Icon is exported), so
the example imports the Icon component from the real module.

In `@apps/mobile/components/ui/label.tsx`:
- Around line 1-13: The file uses React.RefAttributes in the Label component
signature but React is not imported; add the missing import (import * as React
from "react") at the top of the file so React.RefAttributes and any other React
types work correctly in the Label function declaration and its props handling.

In `@apps/mobile/components/ui/menubar.tsx`:
- Around line 155-169: The MenubarSubContent component uses the wrong Radix CSS
variable name; in the JSX returned by MenubarPrimitive.SubContent inside
NativeOnlyAnimatedView update the origin utility that currently references
--radix-context-menu-content-transform-origin to use the menubar-specific
variable (e.g., --radix-menubar-content-transform-origin) so the
transform-origin matches the Menubar primitives; locate the className string
inside the MenubarPrimitive.SubContent render (the Platform.select web branch)
and replace the context-menu variable with the menubar variant.
- Around line 195-217: The Menubar content CSS uses context-menu variables;
update MenubarPrimitive.Content's className to replace
--radix-context-menu-content-available-height and
--radix-context-menu-content-transform-origin with the menubar equivalents
--radix-menubar-content-available-height and
--radix-menubar-content-transform-origin (keep the surrounding cn(...)
composition, Platform.select block, and the props.side conditional logic intact
so only the variable names change).

In `@apps/mobile/components/ui/select.tsx`:
- Around line 169-194: SelectItem currently destructures children but never
renders them, so labels like "Apple" passed from DemoScreen are ignored; fix by
rendering children inside SelectPrimitive.ItemText (replace the self-closing
<SelectPrimitive.ItemText ... /> with <SelectPrimitive.ItemText className="..."
>{children}</SelectPrimitive.ItemText>) so the passed children are displayed;
alternatively, if children should not be accepted, remove children from the
SelectItem parameter list and its type (SelectPrimitive.ItemProps &
React.RefAttributes<SelectPrimitive.ItemRef>) to stop accepting them.

In `@apps/mobile/components/ui/separator.tsx`:
- Around line 9-10: Add a React type import so the type reference
React.RefAttributes compiles: update the imports at the top of the separator
component file to import React for types (e.g., import * as React from "react"
or import React from "react") so the annotation SeparatorPrimitive.RootProps &
React.RefAttributes<SeparatorPrimitive.RootRef> is valid; ensure the import is
present alongside any existing SeparatorPrimitive imports in
components/ui/separator.tsx.
🧹 Nitpick comments (8)
apps/streams/package.json (1)

15-24: Dependency changes appear unrelated to the mobile UI components PR scope.

These version bumps and the new @hono/node-server dependency are in apps/streams/, which doesn't seem connected to the stated PR objective of expanding the mobile demo screen. Consider splitting these into a separate PR to keep diffs minimal and focused. As per coding guidelines, "Keep diffs minimal with targeted edits only, avoiding unnecessary changes outside the scope of the task."

apps/mobile/components/ui/alert.tsx (1)

68-83: Fragile string matching on context class names.

textClass?.includes("text-destructive") (Line 77) is a brittle way to determine variant state — it could false-positive on classes like "text-destructive-foreground". Consider passing the variant through a dedicated context or prop instead.

apps/mobile/components/ui/progress.tsx (1)

65-75: Consider refactoring the animation pattern for better semantics.

Line 70-71: withSpring does accept string values (per API docs: AnimatableValue = number | string | number[]), so the current code is valid. However, for percentage-based numeric animations, it's more idiomatic to animate the numeric value and format it to a string afterwards, rather than animating a template string. This makes the animation semantics clearer.

Line 66: useDerivedValue(() => value ?? 0) is valid without a dependency array per the Reanimated docs (dependencies are optional for worklets reading props when the Babel plugin is configured). However, adding [value] would improve clarity and match the pattern in the useAnimatedStyle below.

Suggested refactoring
 function NativeIndicator({ value, className }: IndicatorProps) {
-	const progress = useDerivedValue(() => value ?? 0);
+	const progress = useDerivedValue(() => value ?? 0, [value]);
 
 	const indicator = useAnimatedStyle(() => {
+		const widthValue = interpolate(progress.value, [0, 100], [1, 100], Extrapolation.CLAMP);
 		return {
-			width: withSpring(
-				`${interpolate(progress.value, [0, 100], [1, 100], Extrapolation.CLAMP)}%`,
-				{ overshootClamping: true },
-			),
+			width: `${withSpring(widthValue, { overshootClamping: true })}%`,
 		};
 	}, [value]);
apps/mobile/components/ui/tooltip.tsx (1)

33-43: Native animation only distinguishes top vs. non-top sides.

On native, side === "left" or side === "right" will get FadeInUp (a vertical animation), while the web path correctly handles all four directions with distinct slide-in classes. If horizontal tooltips are ever used on native, the enter animation will feel slightly off. Fine to defer if horizontal tooltips aren't planned for mobile.

apps/mobile/components/ui/toggle-group.tsx (1)

50-104: Consider ?? instead of || for variant/size fallback.

Lines 79-80 use context.variant || variant and context.size || size. Since VariantProps can include falsy-but-defined values (e.g., a variant that maps to a default), nullish coalescing (??) would be more precise. In practice, variant/size are typically non-empty strings so || works here, but ?? better communicates intent.

Proposed change
 				toggleVariants({
-					variant: context.variant || variant,
-					size: context.size || size,
+					variant: context.variant ?? variant,
+					size: context.size ?? size,
 				}),
apps/mobile/components/ui/popover.tsx (1)

43-49: Web slide-in animations only cover top and bottom sides.

The tooltip component (tooltip.tsx, lines 53-56) handles all four sides (top, bottom, left, right) for web slide-in animations, but here left and right are omitted. If a popover is positioned to the left or right, it will still fade/zoom in but won't have the directional slide.

Add missing side animations for parity with tooltip
 									props.side === "bottom" && "slide-in-from-top-2",
 									props.side === "top" && "slide-in-from-bottom-2",
+									props.side === "left" && "slide-in-from-right-2",
+									props.side === "right" && "slide-in-from-left-2",
apps/mobile/screens/(authenticated)/demo/DemoScreen.tsx (2)

884-887: Invitation emails displayed in UI — verify this is demo-only.

Line 886 renders inv.email directly. Per coding guidelines, be cautious about displaying PII like email addresses. Since this is a demo screen, it's likely acceptable, but ensure this pattern doesn't leak into production-facing screens.


97-923: Large single-component file — consider extracting demo sections if this grows further.

At ~830 lines of JSX, the component is manageable for a demo showcase. If more components are added, consider splitting each Card demo into small extracted components (e.g., ButtonDemo, BadgeDemo) co-located in a components/ subfolder under this screen's directory.

Comment on lines +22 to +27
<TextClassContext.Provider
value={cn(
"text-sm text-foreground",
variant === "destructive" && "text-destructive",
className,
)}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

className leaks into TextClassContext, mixing View classes with text classes.

The Alert's className prop (intended for the outer View) is also spread into the TextClassContext.Provider value (Line 26). If a consumer passes layout classes like className="p-4 mt-2", those will be injected into all descendant text styling via the context, which is unintended.

Proposed fix
 		<TextClassContext.Provider
 			value={cn(
 				"text-sm text-foreground",
 				variant === "destructive" && "text-destructive",
-				className,
 			)}
 		>
📝 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
<TextClassContext.Provider
value={cn(
"text-sm text-foreground",
variant === "destructive" && "text-destructive",
className,
)}
<TextClassContext.Provider
value={cn(
"text-sm text-foreground",
variant === "destructive" && "text-destructive",
)}
🤖 Prompt for AI Agents
In `@apps/mobile/components/ui/alert.tsx` around lines 22 - 27, The provider value
for TextClassContext currently includes the Alert component's className (cn(...,
className)), which leaks outer View/layout classes into descendant text styling;
remove className from the TextClassContext.Provider value and instead keep only
text-related classes (e.g., cn("text-sm text-foreground", variant ===
"destructive" && "text-destructive")). If you need consumer control over text
classes, add an explicit prop like textClassName and include that in the
provider value; ensure the original className continues to be applied only to
the outer View/container.

Comment on lines +86 to +99
<NativeOnlyAnimatedView entering={FadeIn}>
<DropdownMenuPrimitive.SubContent
className={cn(
"bg-popover border-border overflow-hidden rounded-md border p-1 shadow-lg shadow-black/5",
Platform.select({
web: "animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 fade-in-0 data-[state=closed]:zoom-out-95 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-context-menu-content-transform-origin) z-50 min-w-[8rem]",
}),
className,
)}
{...props}
/>
</NativeOnlyAnimatedView>
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Copy-paste bug: references --radix-context-menu-* CSS variables instead of --radix-dropdown-menu-*.

Line 91 uses origin-(--radix-context-menu-content-transform-origin) — this should reference the dropdown-menu CSS variable. On web, Radix sets per-component CSS custom properties for positioning, so the dropdown menu content won't get the correct transform origin.

The same issue exists in DropdownMenuContent at line 138.

Proposed fix
 					Platform.select({
-						web: "animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 fade-in-0 data-[state=closed]:zoom-out-95 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-context-menu-content-transform-origin) z-50 min-w-[8rem]",
+						web: "animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 fade-in-0 data-[state=closed]:zoom-out-95 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-dropdown-menu-content-transform-origin) z-50 min-w-[8rem]",
 					}),
📝 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
<NativeOnlyAnimatedView entering={FadeIn}>
<DropdownMenuPrimitive.SubContent
className={cn(
"bg-popover border-border overflow-hidden rounded-md border p-1 shadow-lg shadow-black/5",
Platform.select({
web: "animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 fade-in-0 data-[state=closed]:zoom-out-95 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-context-menu-content-transform-origin) z-50 min-w-[8rem]",
}),
className,
)}
{...props}
/>
</NativeOnlyAnimatedView>
);
}
<NativeOnlyAnimatedView entering={FadeIn}>
<DropdownMenuPrimitive.SubContent
className={cn(
"bg-popover border-border overflow-hidden rounded-md border p-1 shadow-lg shadow-black/5",
Platform.select({
web: "animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 fade-in-0 data-[state=closed]:zoom-out-95 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-dropdown-menu-content-transform-origin) z-50 min-w-[8rem]",
}),
className,
)}
{...props}
/>
</NativeOnlyAnimatedView>
);
}
🤖 Prompt for AI Agents
In `@apps/mobile/components/ui/dropdown-menu.tsx` around lines 86 - 99, The
className uses the wrong Radix CSS variable name causing incorrect transform
origin; in the web platform class strings for DropdownMenuPrimitive.SubContent
(inside NativeOnlyAnimatedView) and the sibling DropdownMenuContent component,
replace occurrences of "--radix-context-menu-content-transform-origin" with
"--radix-dropdown-menu-content-transform-origin" (i.e., update the origin-(...)
token) so the dropdown menu uses the correct per-component CSS custom property
for transform origin.

Comment on lines +133 to +145
<DropdownMenuPrimitive.Content
className={cn(
"bg-popover border-border min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg shadow-black/5",
Platform.select({
web: cn(
"animate-in fade-in-0 zoom-in-95 max-h-(--radix-context-menu-content-available-height) origin-(--radix-context-menu-content-transform-origin) z-50 cursor-default",
props.side === "bottom" && "slide-in-from-top-2",
props.side === "top" && "slide-in-from-bottom-2",
),
}),
className,
)}
{...props}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Same copy-paste bug: DropdownMenuContent also references context-menu CSS variables.

Both --radix-context-menu-content-available-height and --radix-context-menu-content-transform-origin should be --radix-dropdown-menu-*.

Proposed fix
 								web: cn(
-									"animate-in fade-in-0 zoom-in-95 max-h-(--radix-context-menu-content-available-height) origin-(--radix-context-menu-content-transform-origin) z-50 cursor-default",
+									"animate-in fade-in-0 zoom-in-95 max-h-(--radix-dropdown-menu-content-available-height) origin-(--radix-dropdown-menu-content-transform-origin) z-50 cursor-default",
 									props.side === "bottom" && "slide-in-from-top-2",
 									props.side === "top" && "slide-in-from-bottom-2",
 								),
📝 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
<DropdownMenuPrimitive.Content
className={cn(
"bg-popover border-border min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg shadow-black/5",
Platform.select({
web: cn(
"animate-in fade-in-0 zoom-in-95 max-h-(--radix-context-menu-content-available-height) origin-(--radix-context-menu-content-transform-origin) z-50 cursor-default",
props.side === "bottom" && "slide-in-from-top-2",
props.side === "top" && "slide-in-from-bottom-2",
),
}),
className,
)}
{...props}
<DropdownMenuPrimitive.Content
className={cn(
"bg-popover border-border min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg shadow-black/5",
Platform.select({
web: cn(
"animate-in fade-in-0 zoom-in-95 max-h-(--radix-dropdown-menu-content-available-height) origin-(--radix-dropdown-menu-content-transform-origin) z-50 cursor-default",
props.side === "bottom" && "slide-in-from-top-2",
props.side === "top" && "slide-in-from-bottom-2",
),
}),
className,
)}
{...props}
🤖 Prompt for AI Agents
In `@apps/mobile/components/ui/dropdown-menu.tsx` around lines 133 - 145, The
DropdownMenuPrimitive.Content className uses context-menu CSS variables
incorrectly; update the CSS variable names inside the className string for
DropdownMenuPrimitive.Content (the block rendering DropdownMenuContent) by
replacing --radix-context-menu-content-available-height and
--radix-context-menu-content-transform-origin with their dropdown-menu
equivalents (--radix-dropdown-menu-content-available-height and
--radix-dropdown-menu-content-transform-origin) so the animation and max-height
origin use the correct variables while preserving the Platform.select logic and
existing props/className merging.

Comment on lines +24 to +37
/**
* A wrapper component for Lucide icons with Uniwind `className` support via `withUniwind`.
*
* This component allows you to render any Lucide icon while applying utility classes
* using `uniwind`. It avoids the need to wrap or configure each icon individually.
*
* @component
* @example
* ```tsx
* import { ArrowRight } from 'lucide-react-native';
* import { Icon } from '@/registry/uniwind/registry/components/ui/icon';
*
* <Icon as={ArrowRight} className="text-red-500 size-4" />
* ```
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Incorrect import path in JSDoc example.

Line 34 references @/registry/uniwind/registry/components/ui/icon which doesn't match the actual module path. This will confuse consumers.

Fix the import path
- * import { Icon } from '@/registry/uniwind/registry/components/ui/icon';
+ * import { Icon } from '@/components/ui/icon';
📝 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
/**
* A wrapper component for Lucide icons with Uniwind `className` support via `withUniwind`.
*
* This component allows you to render any Lucide icon while applying utility classes
* using `uniwind`. It avoids the need to wrap or configure each icon individually.
*
* @component
* @example
* ```tsx
* import { ArrowRight } from 'lucide-react-native';
* import { Icon } from '@/registry/uniwind/registry/components/ui/icon';
*
* <Icon as={ArrowRight} className="text-red-500 size-4" />
* ```
/**
* A wrapper component for Lucide icons with Uniwind `className` support via `withUniwind`.
*
* This component allows you to render any Lucide icon while applying utility classes
* using `uniwind`. It avoids the need to wrap or configure each icon individually.
*
* `@component`
* `@example`
*
🤖 Prompt for AI Agents
In `@apps/mobile/components/ui/icon.tsx` around lines 24 - 37, Update the JSDoc
example import path to match the actual module export for the Icon component:
locate the JSDoc block above the Icon component (search for "A wrapper component
for Lucide icons" and the Icon symbol) and change the example import from
"@/registry/uniwind/registry/components/ui/icon" to the correct module path that
exports Icon (the actual path used in the codebase where Icon is exported), so
the example imports the Icon component from the real module.

Comment on lines +1 to +13
import * as LabelPrimitive from "@rn-primitives/label";
import { Platform } from "react-native";
import { cn } from "@/lib/utils";

function Label({
className,
onPress,
onLongPress,
onPressIn,
onPressOut,
disabled,
...props
}: LabelPrimitive.TextProps & React.RefAttributes<LabelPrimitive.TextRef>) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Missing React import — same issue as separator.tsx.

React.RefAttributes is used on Line 13 without importing React. Add import * as React from "react" to match the convention used in other components.

🤖 Prompt for AI Agents
In `@apps/mobile/components/ui/label.tsx` around lines 1 - 13, The file uses
React.RefAttributes in the Label component signature but React is not imported;
add the missing import (import * as React from "react") at the top of the file
so React.RefAttributes and any other React types work correctly in the Label
function declaration and its props handling.

Comment on lines +155 to +169
return (
<NativeOnlyAnimatedView entering={FadeIn}>
<MenubarPrimitive.SubContent
className={cn(
"bg-popover border-border overflow-hidden rounded-md border p-1 shadow-lg shadow-black/5",
Platform.select({
web: "animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 fade-in-0 data-[state=closed]:zoom-out-95 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-context-menu-content-transform-origin) z-50 min-w-[8rem]",
}),
className,
)}
{...props}
/>
</NativeOnlyAnimatedView>
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Same copy-paste bug: MenubarSubContent references --radix-context-menu-* CSS variables.

Line 161 uses origin-(--radix-context-menu-content-transform-origin). This should reference menubar-specific Radix CSS variables.

Proposed fix
 					Platform.select({
-						web: "animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 fade-in-0 data-[state=closed]:zoom-out-95 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-context-menu-content-transform-origin) z-50 min-w-[8rem]",
+						web: "animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 fade-in-0 data-[state=closed]:zoom-out-95 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-menubar-content-transform-origin) z-50 min-w-[8rem]",
 					}),
📝 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
return (
<NativeOnlyAnimatedView entering={FadeIn}>
<MenubarPrimitive.SubContent
className={cn(
"bg-popover border-border overflow-hidden rounded-md border p-1 shadow-lg shadow-black/5",
Platform.select({
web: "animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 fade-in-0 data-[state=closed]:zoom-out-95 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-context-menu-content-transform-origin) z-50 min-w-[8rem]",
}),
className,
)}
{...props}
/>
</NativeOnlyAnimatedView>
);
}
return (
<NativeOnlyAnimatedView entering={FadeIn}>
<MenubarPrimitive.SubContent
className={cn(
"bg-popover border-border overflow-hidden rounded-md border p-1 shadow-lg shadow-black/5",
Platform.select({
web: "animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 fade-in-0 data-[state=closed]:zoom-out-95 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-menubar-content-transform-origin) z-50 min-w-[8rem]",
}),
className,
)}
{...props}
/>
</NativeOnlyAnimatedView>
);
}
🤖 Prompt for AI Agents
In `@apps/mobile/components/ui/menubar.tsx` around lines 155 - 169, The
MenubarSubContent component uses the wrong Radix CSS variable name; in the JSX
returned by MenubarPrimitive.SubContent inside NativeOnlyAnimatedView update the
origin utility that currently references
--radix-context-menu-content-transform-origin to use the menubar-specific
variable (e.g., --radix-menubar-content-transform-origin) so the
transform-origin matches the Menubar primitives; locate the className string
inside the MenubarPrimitive.SubContent render (the Platform.select web branch)
and replace the context-menu variable with the menubar variant.

Comment on lines +195 to +217
<MenubarPrimitive.Content
className={cn(
"bg-popover border-border min-w-[12rem] overflow-hidden rounded-md border p-1 shadow-lg shadow-black/5",
Platform.select({
web: cn(
"animate-in fade-in-0 zoom-in-95 max-h-(--radix-context-menu-content-available-height) origin-(--radix-context-menu-content-transform-origin) z-50 cursor-default",
props.side === "bottom" && "slide-in-from-top-2",
props.side === "top" && "slide-in-from-bottom-2",
),
}),
className,
)}
align={align}
alignOffset={alignOffset}
sideOffset={sideOffset}
{...props}
/>
</TextClassContext.Provider>
</NativeOnlyAnimatedView>
</FullWindowOverlay>
</MenubarPrimitive.Portal>
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Radix UI menubar CSS custom properties documentation

💡 Result:

Radix UI Menubar’s CSS custom properties are documented on the Menubar (Primitives) docs page, in the Content (and SubContent) sections under the “CSS Variable” table. (radix-ui.com)

Menubar CSS custom properties (React Primitives): (radix-ui.com)

  • --radix-menubar-content-transform-origin
  • --radix-menubar-content-available-width
  • --radix-menubar-content-available-height
  • --radix-menubar-trigger-width
  • --radix-menubar-trigger-height

Sources (numbered):
[1] Radix Primitives — Menubar docs (radix-ui.com)

Citations:


Replace --radix-context-menu-* CSS variables with --radix-menubar-* in MenubarContent.

Line 200 uses --radix-context-menu-content-available-height and --radix-context-menu-content-transform-origin, which are context menu variables. According to Radix UI documentation, menubar content should use --radix-menubar-content-available-height and --radix-menubar-content-transform-origin.

Proposed fix
 								web: cn(
-									"animate-in fade-in-0 zoom-in-95 max-h-(--radix-context-menu-content-available-height) origin-(--radix-context-menu-content-transform-origin) z-50 cursor-default",
+									"animate-in fade-in-0 zoom-in-95 max-h-(--radix-menubar-content-available-height) origin-(--radix-menubar-content-transform-origin) z-50 cursor-default",
 									props.side === "bottom" && "slide-in-from-top-2",
 									props.side === "top" && "slide-in-from-bottom-2",
 								),
📝 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
<MenubarPrimitive.Content
className={cn(
"bg-popover border-border min-w-[12rem] overflow-hidden rounded-md border p-1 shadow-lg shadow-black/5",
Platform.select({
web: cn(
"animate-in fade-in-0 zoom-in-95 max-h-(--radix-context-menu-content-available-height) origin-(--radix-context-menu-content-transform-origin) z-50 cursor-default",
props.side === "bottom" && "slide-in-from-top-2",
props.side === "top" && "slide-in-from-bottom-2",
),
}),
className,
)}
align={align}
alignOffset={alignOffset}
sideOffset={sideOffset}
{...props}
/>
</TextClassContext.Provider>
</NativeOnlyAnimatedView>
</FullWindowOverlay>
</MenubarPrimitive.Portal>
);
}
<MenubarPrimitive.Content
className={cn(
"bg-popover border-border min-w-[12rem] overflow-hidden rounded-md border p-1 shadow-lg shadow-black/5",
Platform.select({
web: cn(
"animate-in fade-in-0 zoom-in-95 max-h-(--radix-menubar-content-available-height) origin-(--radix-menubar-content-transform-origin) z-50 cursor-default",
props.side === "bottom" && "slide-in-from-top-2",
props.side === "top" && "slide-in-from-bottom-2",
),
}),
className,
)}
align={align}
alignOffset={alignOffset}
sideOffset={sideOffset}
{...props}
/>
</TextClassContext.Provider>
</NativeOnlyAnimatedView>
</MenubarPrimitive.Portal>
);
}
🤖 Prompt for AI Agents
In `@apps/mobile/components/ui/menubar.tsx` around lines 195 - 217, The Menubar
content CSS uses context-menu variables; update MenubarPrimitive.Content's
className to replace --radix-context-menu-content-available-height and
--radix-context-menu-content-transform-origin with the menubar equivalents
--radix-menubar-content-available-height and
--radix-menubar-content-transform-origin (keep the surrounding cn(...)
composition, Platform.select block, and the props.side conditional logic intact
so only the variable names change).

Comment on lines +169 to +194
function SelectItem({
className,
children,
...props
}: SelectPrimitive.ItemProps & React.RefAttributes<SelectPrimitive.ItemRef>) {
return (
<SelectPrimitive.Item
className={cn(
"active:bg-accent group relative flex w-full flex-row items-center gap-2 rounded-sm py-2 pl-2 pr-8 sm:py-1.5",
Platform.select({
web: "focus:bg-accent focus:text-accent-foreground *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 cursor-default outline-none data-[disabled]:pointer-events-none [&_svg]:pointer-events-none",
}),
props.disabled && "opacity-50",
className,
)}
{...props}
>
<View className="absolute right-2 flex size-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<Icon as={Check} className="text-muted-foreground size-4 shrink-0" />
</SelectPrimitive.ItemIndicator>
</View>
<SelectPrimitive.ItemText className="text-foreground group-active:text-accent-foreground select-none text-sm" />
</SelectPrimitive.Item>
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

children prop is accepted but silently discarded.

SelectItem destructures children from props (line 172) but never renders them. Only SelectPrimitive.ItemText is rendered. In the DemoScreen (lines 405–413), children like Apple are passed but silently ignored — the label prop drives the display.

Either remove children from the destructured props to make the API clearer, or render them if intended.

Option A: Stop accepting children
 function SelectItem({
 	className,
-	children,
 	...props
 }: SelectPrimitive.ItemProps & React.RefAttributes<SelectPrimitive.ItemRef>) {
📝 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
function SelectItem({
className,
children,
...props
}: SelectPrimitive.ItemProps & React.RefAttributes<SelectPrimitive.ItemRef>) {
return (
<SelectPrimitive.Item
className={cn(
"active:bg-accent group relative flex w-full flex-row items-center gap-2 rounded-sm py-2 pl-2 pr-8 sm:py-1.5",
Platform.select({
web: "focus:bg-accent focus:text-accent-foreground *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 cursor-default outline-none data-[disabled]:pointer-events-none [&_svg]:pointer-events-none",
}),
props.disabled && "opacity-50",
className,
)}
{...props}
>
<View className="absolute right-2 flex size-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<Icon as={Check} className="text-muted-foreground size-4 shrink-0" />
</SelectPrimitive.ItemIndicator>
</View>
<SelectPrimitive.ItemText className="text-foreground group-active:text-accent-foreground select-none text-sm" />
</SelectPrimitive.Item>
);
}
function SelectItem({
className,
...props
}: SelectPrimitive.ItemProps & React.RefAttributes<SelectPrimitive.ItemRef>) {
return (
<SelectPrimitive.Item
className={cn(
"active:bg-accent group relative flex w-full flex-row items-center gap-2 rounded-sm py-2 pl-2 pr-8 sm:py-1.5",
Platform.select({
web: "focus:bg-accent focus:text-accent-foreground *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 cursor-default outline-none data-[disabled]:pointer-events-none [&_svg]:pointer-events-none",
}),
props.disabled && "opacity-50",
className,
)}
{...props}
>
<View className="absolute right-2 flex size-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<Icon as={Check} className="text-muted-foreground size-4 shrink-0" />
</SelectPrimitive.ItemIndicator>
</View>
<SelectPrimitive.ItemText className="text-foreground group-active:text-accent-foreground select-none text-sm" />
</SelectPrimitive.Item>
);
}
🤖 Prompt for AI Agents
In `@apps/mobile/components/ui/select.tsx` around lines 169 - 194, SelectItem
currently destructures children but never renders them, so labels like "Apple"
passed from DemoScreen are ignored; fix by rendering children inside
SelectPrimitive.ItemText (replace the self-closing <SelectPrimitive.ItemText ...
/> with <SelectPrimitive.ItemText className="..."
>{children}</SelectPrimitive.ItemText>) so the passed children are displayed;
alternatively, if children should not be accepted, remove children from the
SelectItem parameter list and its type (SelectPrimitive.ItemProps &
React.RefAttributes<SelectPrimitive.ItemRef>) to stop accepting them.

Comment on lines +9 to +10
}: SeparatorPrimitive.RootProps &
React.RefAttributes<SeparatorPrimitive.RootRef>) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, view the actual separator.tsx file
echo "=== separator.tsx content ==="
cat -n apps/mobile/components/ui/separator.tsx

echo -e "\n=== Check for React imports in similar files ==="
# Check alert.tsx
echo "--- alert.tsx ---"
head -15 apps/mobile/components/ui/alert.tsx

# Check badge.tsx
echo -e "\n--- badge.tsx ---"
head -15 apps/mobile/components/ui/badge.tsx

Repository: superset-sh/superset

Length of output: 2051


🏁 Script executed:

#!/bin/bash
# Check tsconfig for JSX and type settings
echo "=== tsconfig configuration ==="
fd tsconfig -e json --exec cat {} \;

echo -e "\n=== Check for ambient React declarations ==="
rg "declare global" -A5 --type=ts

echo -e "\n=== Check if React is globally available ==="
rg "type React" --type=ts -l | head -5

Repository: superset-sh/superset

Length of output: 6698


🏁 Script executed:

#!/bin/bash
# Check package.json to understand React version and setup
echo "=== React and TypeScript configuration ==="
cat package.json | grep -A2 -B2 '"react"'

# Look for .d.ts files that might provide global types
echo -e "\n=== Global type definition files ==="
fd -e d.ts -x ls -la {}

Repository: superset-sh/superset

Length of output: 1007


Missing React import for type annotation.

React.RefAttributes is referenced in the type annotation on line 10 but React is not imported. While the new JSX transform (react-jsx) eliminates the need to import React for JSX elements, it does not apply to type references like React.RefAttributes. This will cause a TypeScript compilation error.

Proposed fix
 import * as SeparatorPrimitive from "@rn-primitives/separator";
+import * as React from "react";
 import { cn } from "@/lib/utils";
🤖 Prompt for AI Agents
In `@apps/mobile/components/ui/separator.tsx` around lines 9 - 10, Add a React
type import so the type reference React.RefAttributes compiles: update the
imports at the top of the separator component file to import React for types
(e.g., import * as React from "react" or import React from "react") so the
annotation SeparatorPrimitive.RootProps &
React.RefAttributes<SeparatorPrimitive.RootRef> is valid; ensure the import is
present alongside any existing SeparatorPrimitive imports in
components/ui/separator.tsx.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@apps/mobile/components/ui/textarea.tsx`:
- Around line 4-10: The component Textarea declares
React.RefAttributes<TextInput> in its props but doesn't use React.forwardRef, so
incoming refs are dropped; wrap Textarea with React.forwardRef (use
React.forwardRef<TextInput, TextInputProps>(...)) and change the function to
accept (props, ref) then pass that ref to the underlying TextInput element,
ensuring the ref type matches TextInput and update any export to use the
forwarded component.
🧹 Nitpick comments (1)
apps/mobile/components/ui/textarea.tsx (1)

27-28: {...props} spread after textAlignVertical allows silent override.

Because {...props} is spread after textAlignVertical="top", a caller passing textAlignVertical will override the default. If this is intentional for flexibility, consider adding a brief comment. If the default should always win, swap the order or destructure textAlignVertical like multiline.

Comment on lines +4 to +10
function Textarea({
className,
multiline = true,
numberOfLines = Platform.select({ web: 2, native: 8 }), // On web, numberOfLines also determines initial height. On native, it determines the maximum height.
placeholderTextColorClassName,
...props
}: TextInputProps & React.RefAttributes<TextInput>) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Ref will be silently dropped — forwardRef is missing.

The props type includes React.RefAttributes<TextInput>, which advertises that <Textarea ref={…} /> is valid. However, without wrapping in React.forwardRef, React strips the ref before it reaches the function body, so it never arrives on the underlying <TextInput>.

Proposed fix
-function Textarea({
+import * as React from "react";
+
+const Textarea = React.forwardRef<TextInput, TextInputProps & { placeholderTextColorClassName?: string }>(({
 	className,
 	multiline = true,
 	numberOfLines = Platform.select({ web: 2, native: 8 }),
 	placeholderTextColorClassName,
 	...props
-}: TextInputProps & React.RefAttributes<TextInput>) {
+}, ref) => {
 	return (
 		<TextInput
+			ref={ref}
 			className={cn(
 				...
 			)}
 			...
 		/>
 	);
-}
+});
+
+Textarea.displayName = "Textarea";
🤖 Prompt for AI Agents
In `@apps/mobile/components/ui/textarea.tsx` around lines 4 - 10, The component
Textarea declares React.RefAttributes<TextInput> in its props but doesn't use
React.forwardRef, so incoming refs are dropped; wrap Textarea with
React.forwardRef (use React.forwardRef<TextInput, TextInputProps>(...)) and
change the function to accept (props, ref) then pass that ref to the underlying
TextInput element, ensuring the ref type matches TextInput and update any export
to use the forwarded component.

@saddlepaddle saddlepaddle merged commit 4d39c1e into main Feb 6, 2026
14 checks passed
@Kitenite Kitenite deleted the mobile-components branch February 7, 2026 02:01
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