8000 feat(dialog): implement dialog v2 by kilbot · Pull Request #93 · roninoss/rn-primitives · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat(dialog): implement dialog v2 #93

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: @zach/v2
Choose a base branch
from
Open

Conversation

kilbot
Copy link
@kilbot kilbot commented Jun 2, 2025

Summary by CodeRabbit

  • New Features

    • Introduced a comprehensive, cross-platform dialog component suite with unified styling and enhanced animations for web and native environments.
    • Added accessible dialog overlays, content areas, headers, footers, titles, descriptions, and close buttons with consistent behavior and appearance.
    • Included dialog usage examples in multiple application templates for easier adoption.
  • Refactor

    • Simplified and unified dialog component implementations by consolidating platform-specific logic and improving animation handling.
    • Streamlined dialog footer button structure by reducing unnecessary nesting.
  • Chores

    • Updated package dependencies and build configurations to support modular platform-specific dialog components.
  • Bug Fixes

    • Enhanced dialog accessibility and interaction by refining close button behavior and component structure.

Copy link
vercel bot commented Jun 2, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
rn-primitives ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 2, 2025 0:07am

Copy link
coderabbitai bot commented Jun 2, 2025

Walkthrough

This change introduces a major refactor and platform abstraction for the dialog component system across multiple apps and the @rn-primitives/dialog package. It modularizes dialog primitives for native, web, and universal environments, restructures exports, adds new component implementations, updates dependencies, and adapts consuming apps to the new dialog API.

Changes

File(s) / Path(s) Change Summary
apps/expo-nativewind/app/(components)/dialog.tsx,
apps/nextjs-nativewind/src/app/page.tsx
Simplified dialog close button structure by removing asChild and nested Button in DialogClose.
apps/expo-nativewind/components/ui/dialog.tsx,
apps/nextjs-nativewind/src/components/ui/dialog.tsx
Refactored dialog implementation to unify platform-specific logic, improve animation handling, and standardize styling; added new DialogClose component.
apps/nextjs-no-rn/src/app/page.tsx,
apps/vite-tanstack-router/src/routes/index.tsx
Added new DialogExample component demonstrating dialog usage; updated imports accordingly.
apps/nextjs-no-rn/src/components/ui/dialog.tsx,
apps/vite-tanstack-router/src/components/ui/dialog.tsx
Introduced new dialog component modules exporting dialog primitives with platform-specific styling, animation, and utility usage.
apps/nextjs-no-rn/src/components/ui/alert-dialog.tsx Reordered import of mergeProps for clarity; no functional changes.
apps/nextjs-no-rn/package.json,
apps/vite-tanstack-router/package.json
Added @rn-primitives/dialog as a workspace dependency.
packages/dialog/package.json Bumped version to 2.0.0-alpha.1, split exports for native/web, updated dependencies.
packages/dialog/tsup.config.ts Updated build config to support new universal, native, and web entry points.
packages/dialog/src/base-types.ts Added base type aliases for dialog props and context.
packages/dialog/src/dialog.tsx,
packages/dialog/src/dialog.web.tsx,
packages/dialog/src/types.ts
Deleted old dialog component and type definitions (now replaced by modularized platform-specific implementations).
packages/dialog/src/index.ts Changed exports to explicitly export components and types from ./universal.
packages/dialog/src/native/dialog-native.native.tsx,
packages/dialog/src/native/dialog-native.tsx,
packages/dialog/src/native/index.ts,
packages/dialog/src/native/types.ts
Introduced native dialog component implementations, types, and index for React Native environments.
packages/dialog/src/universal/dialog.tsx,
packages/dialog/src/universal/dialog.web.tsx,
packages/dialog/src/universal/index.ts,
packages/dialog/src/universal/types.ts
Added universal dialog wrappers and types for cross-platform usage.
packages/dialog/src/utils/contexts.ts Introduced RootContext and useRootContext hook for dialog state/context management.
packages/dialog/src/web/dialog-web.tsx,
packages/dialog/src/web/dialog-web.web.tsx,
packages/dialog/src/web/index.ts,
packages/dialog/src/web/types.ts
Added web-specific dialog components, wrappers, types, and index for Radix UI-based web dialogs.

Sequence Diagram(s)

sequenceDiagram
    participant App
    participant Dialog
    participant Trigger
    participant Portal
    participant Overlay
    participant Content
    participant Close

    App->>Dialog: Render Dialog (Root)
    Dialog->>Trigger: Render Trigger
    Trigger->>Dialog: onPress → open dialog
    Dialog->>Portal: Render Portal (if open)
    Portal->>Overlay: Render Overlay (with animation)
    Portal->>Content: Render Content (with animation)
    Content->>Close: Render Close Button
    Close->>Dialog: onPress → close dialog
    Dialog->>Portal: Unmount Portal (if closed)
Loading

Suggested reviewers

  • mrzachnugent

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cea272f and bdf298f.

📒 Files selected for processing (2)
  • packages/dialog/src/native/dialog-native.tsx (1 hunks)
  • packages/dialog/src/web/dialog-web.tsx (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
packages/dialog/src/native/dialog-native.tsx

[error] 73-73: This code is unreachable

... because this statement will throw an exception beforehand

(lint/correctness/noUnreachable)

packages/dialog/src/web/dialog-web.tsx

[error] 73-73: This code is unreachable

... because this statement will throw an exception beforehand

(lint/correctness/noUnreachable)

🔇 Additional comments (7)
packages/dialog/src/native/dialog-native.tsx (4)

1-11: LGTM: Clean import structure

The imports are well-organized, separating context types from component prop types with clear, descriptive naming.


13-67: LGTM: Consistent stub implementation pattern

All component functions follow a consistent and appropriate pattern for platform-specific stubs:

  • Development-only console warnings to guide developers
  • Null return for non-native platforms
  • Proper TypeScript typing with imported prop interfaces

This design effectively prevents native-only components from rendering on web while providing clear feedback during development.


48-53: LGTM: Log message issue has been resolved

The Close function now correctly references "Close" in its log message, fixing the previous issue where it incorrectly referenced "Cancel".


76-76: LGTM: Complete and properly ordered exports

All components and the hook are exported with clear, consistent naming that matches the function definitions.

packages/dialog/src/web/dialog-web.tsx (3)

1-11: LGTM! Clean type imports for dialog components.

The imports are well-organized and correctly typed, importing necessary Radix UI dialog types and local context types.


13-67: Excellent fix! All log messages now correctly reference their component names.

All the component stub implementations now have consistent and accurate log messages that properly identify the component being referenced. The pattern is well-implemented with development-only warnings and proper type casting.


76-76: LGTM! Comprehensive and well-organized exports.

The exports include all the dialog components and the hook, providing a complete API surface for the stub implementation.

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
@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: 17

🧹 Nitpick comments (7)
packages/dialog/package.json (1)

42-47: Remove Duplicate @rn-primitives/portal Declaration
@rn-primitives/portal is listed in both dependencies (line 44) and devDependencies (line 49). Keep it only under dependencies to avoid redundancy.

Also applies to: 48-50

packages/dialog/src/utils/contexts.ts (2)

4-4: Consider more explicit typing for the context.

The context is initialized with null but the type doesn't explicitly indicate nullability. Consider making this more explicit:

-const RootContext = React.createContext<BaseDialogRootContext>(null);
+const RootContext = React.createContext<BaseDialogRootContext | null>(null);

This makes the nullable nature of the context more apparent to TypeScript and developers.


5-11: Improve error message specificity.

The current error message is helpful but could be more specific about which components are considered compound components.

-    throw new Error('Dialog compound components cannot be rendered outside the Dialog component');
+    throw new Error('Dialog compound components (Close, Content, Description, Overlay, Portal, Title, Trigger) cannot be rendered outside the Dialog.Root component');

This provides clearer guidance on which components require the context and what the proper parent should be.

packages/dialog/src/native/dialog-native.native.tsx (1)

35-35: Remove unnecessary Fragment wrapper.

The Fragment is redundant as it only contains a single child element.

Apply this diff:

-        <>{children}</>
+        {children}
🧰 Tools
🪛 Biome (1.9.4)

[error] 35-35: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)

apps/nextjs-nativewind/src/components/ui/dialog.tsx (1)

19-41: Minor formatting issue: trailing space

There's a trailing space after "absolute" in the native styles.

-          native: 'bg-black/50 dark:bg-black/80 flex justify-center items-center p-2 absolute ',
+          native: 'bg-black/50 dark:bg-black/80 flex justify-center items-center p-2 absolute',
apps/nextjs-no-rn/src/components/ui/dialog.tsx (1)

18-40: Minor formatting issue: trailing space

Same as in the other dialog implementation - there's a trailing space after "absolute" in the native styles.

-          native: 'bg-black/50 dark:bg-black/80 flex justify-center items-center p-2 absolute ',
+          native: 'bg-black/50 dark:bg-black/80 flex justify-center items-center p-2 absolute',
apps/expo-nativewind/components/ui/dialog.tsx (1)

74-83: Extract close button className for better readability.

The close button has a complex inline className that would be more maintainable as a constant.

Consider extracting the className:

+const CLOSE_BUTTON_CLASS = 'absolute right-4 top-4 p-0.5 web:group rounded-sm opacity-70 web:ring-offset-background web:transition-opacity web:hover:opacity-100 web:focus:outline-none web:focus:ring-2 web:focus:ring-ring web:focus:ring-offset-2 web:disabled:pointer-events-none';
+
 function DialogContent({
   className,
   children,
   native: { portalHost, ...nativeProp } = {},
   ...props
 }: Omit<DialogPrimitive.ContentProps, 'native'> & {
   native?: DialogPrimitive.ContentProps['native'] & { portalHost?: string };
 }) {
   const { open } = DialogPrimitive.useRootContext();
   return (
     <DialogPortal native={portalHost ? { hostName: portalHost } : undefined}>
       <DialogOverlay>
         <DialogPrimitive.Content asChild={Platform.OS === 'web'}>
           {/* DialogPrimitive.Content uses `nativeID` for accessibility, so it prevents the entering animation from working https://docs.swmansion.com/react-native-reanimated/docs/layout-animations/entering-exiting-animations/#remarks */}
           <View
             className={cn(
               Platform.select({
                 web: 'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
                 native:
                   'z-50 max-w-lg gap-4 border bg-background p-6 shadow-lg border-border rounded-lg',
               }),
               className
             )}
             native={mergeProps(CONTENT_NATIVE_PROPS, nativeProp)}
             {...props}
           >
             {children}
             <DialogPrimitive.Close
-              className={
-                'absolute right-4 top-4 p-0.5 web:group rounded-sm opacity-70 web:ring-offset-background web:transition-opacity web:hover:opacity-100 web:focus:outline-none web:focus:ring-2 web:focus:ring-ring web:focus:ring-offset-2 web:disabled:pointer-events-none'
-              }
+              className={CLOSE_BUTTON_CLASS}
             >
               <X
                 size={Platform.OS === 'web' ? 16 : 18}
                 className={cn('text-muted-foreground', open && 'text-accent-foreground')}
               />
             </DialogPrimitive.Close>
           </View>
         </DialogPrimitive.Content>
       </DialogOverlay>
     </DialogPortal>
   );
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between afa881a and cea272f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (31)
  • apps/expo-nativewind/app/(components)/dialog.tsx (1 hunks)
  • apps/expo-nativewind/components/ui/dialog.tsx (2 hunks)
  • apps/nextjs-nativewind/src/app/page.tsx (3 hunks)
  • apps/nextjs-nativewind/src/components/ui/dialog.tsx (2 hunks)
  • apps/nextjs-no-rn/package.json (1 hunks)
  • apps/nextjs-no-rn/src/app/page.tsx (3 hunks)
  • apps/nextjs-no-rn/src/components/ui/alert-dialog.tsx (1 hunks)
  • apps/nextjs-no-rn/src/components/ui/dialog.tsx (1 hunks)
  • apps/vite-tanstack-router/package.json (1 hunks)
  • apps/vite-tanstack-router/src/components/ui/dialog.tsx (1 hunks)
  • apps/vite-tanstack-router/src/routes/index.tsx (3 hunks)
  • packages/dialog/package.json (3 hunks)
  • packages/dialog/src/base-types.ts (1 hunks)
  • packages/dialog/src/dialog.tsx (0 hunks)
  • packages/dialog/src/dialog.web.tsx (0 hunks)
  • packages/dialog/src/index.ts (1 hunks)
  • packages/dialog/src/native/dialog-native.native.tsx (1 hunks)
  • packages/dialog/src/native/dialog-native.tsx (1 hunks)
  • packages/dialog/src/native/index.ts (1 hunks)
  • packages/dialog/src/native/types.ts (1 hunks)
  • packages/dialog/src/types.ts (0 hunks)
  • packages/dialog/src/universal/dialog.tsx (1 hunks)
  • packages/dialog/src/universal/dialog.web.tsx (1 hunks)
  • packages/dialog/src/universal/index.ts (1 hunks)
  • packages/dialog/src/universal/types.ts (1 hunks)
  • packages/dialog/src/utils/contexts.ts (1 hunks)
  • packages/dialog/src/web/dialog-web.tsx (1 hunks)
  • packages/dialog/src/web/dialog-web.web.tsx (1 hunks)
  • packages/dialog/src/web/index.ts (1 hunks)
  • packages/dialog/src/web/types.ts (1 hunks)
  • packages/dialog/tsup.config.ts (1 hunks)
💤 Files with no reviewable changes (3)
  • packages/dialog/src/types.ts
  • packages/dialog/src/dialog.web.tsx
  • packages/dialog/src/dialog.tsx
🧰 Additional context used
🧬 Code Graph Analysis (6)
packages/dialog/src/utils/contexts.ts (10)
packages/dialog/src/base-types.ts (1)
  • BaseDialogRootContext (33-33)
packages/dialog/src/native/dialog-native.tsx (1)
  • useRootContext (76-76)
packages/dialog/src/native/index.ts (1)
  • useRootContext (10-10)
packages/dialog/src/index.ts (1)
  • useRootContext (10-10)
packages/dialog/src/universal/index.ts (1)
  • useRootContext (10-10)
packages/dialog/src/universal/dialog.tsx (1)
  • useRootContext (58-58)
packages/dialog/src/native/dialog-native.native.tsx (1)
  • useRootContext (196-196)
packages/dialog/src/web/index.ts (1)
  • useRootContext (10-10)
packages/dialog/src/web/dialog-web.tsx (1)
  • useRootContext (76-76)
packages/dialog/src/web/dialog-web.web.tsx (1)
  • useRootContext (48-48)
apps/vite-tanstack-router/src/routes/index.tsx (3)
apps/vite-tanstack-router/src/components/ui/dialog.tsx (8)
  • Dialog (131-131)
  • DialogTrigger (140-140)
  • DialogContent (133-133)
  • DialogHeader (136-136)
  • DialogTitle (139-139)
  • DialogDescription (134-134)
  • DialogFooter (135-135)
  • DialogClose (132-132)
apps/vite-tanstack-router/src/components/ui/button.tsx (1)
  • Button (114-114)
apps/vite-tanstack-router/src/components/ui/text.tsx (1)
  • Text (21-21)
apps/nextjs-nativewind/src/app/page.tsx (2)
apps/nextjs-nativewind/src/components/ui/dialog.tsx (1)
  • DialogClose (136-136)
apps/nextjs-nativewind/src/components/ui/text.tsx (1)
  • Text (31-31)
packages/dialog/src/web/dialog-web.tsx (1)
packages/dialog/src/utils/contexts.ts (2)
  • useRootContext (15-15)
  • RootContextReturnType (17-17)
packages/dialog/src/native/types.ts (2)
packages/dialog/src/native/index.ts (8)
  • RootProps (19-19)
  • CloseProps (14-14)
  • ContentProps (15-15)
  • DescriptionProps (16-16)
  • OverlayProps (17-17)
  • PortalProps (18-18)
  • TitleProps (20-20)
  • TriggerProps (21-21)
packages/dialog/src/base-types.ts (8)
  • BaseDialogRootProps (34-34)
  • BaseDialogCloseProps (28-28)
  • BaseDialogContentProps (29-29)
  • BaseDialogDescriptionProps (30-30)
  • BaseDialogOverlayProps (31-31)
  • BaseDialogPortalProps (32-32)
  • BaseDialogTitleProps (35-35)
  • BaseDialogTriggerProps (36-36)
packages/dialog/src/universal/dialog.tsx (5)
packages/dialog/src/native/dialog-native.tsx (8)
  • Root (76-76)
  • Content (76-76)
  • Description (76-76)
  • Overlay (76-76)
  • Portal (76-76)
  • Title (76-76)
  • Trigger (76-76)
  • Close (76-76)
packages/dialog/src/native/index.ts (16)
  • Root (7-7)
  • RootProps (19-19)
  • Content (3-3)
  • ContentProps (15-15)
  • Description (4-4)
  • DescriptionProps (16-16)
  • Overlay (5-5)
  • OverlayProps (17-17)
  • Portal (6-6)
  • PortalProps (18-18)
  • Title (8-8)
  • TitleProps (20-20)
  • Trigger (9-9)
  • TriggerProps (21-21)
  • Close (2-2)
  • CloseProps (14-14)
packages/dialog/src/native/dialog-native.native.tsx (8)
  • Root (196-196)
  • Content (196-196)
  • Description (196-196)
  • Overlay (196-196)
  • Portal (196-196)
  • Title (196-196)
  • Trigger (196-196)
  • Close (196-196)
packages/dialog/src/universal/dialog.web.tsx (8)
  • Root (97-97)
  • Content (97-97)
  • Description (97-97)
  • Overlay (97-97)
  • Portal (97-97)
  • Title (97-97)
  • Trigger (97-97)
  • Close (97-97)
packages/dialog/src/universal/types.ts (8)
  • RootProps (103-103)
  • ContentProps (99-99)
  • DescriptionProps (100-100)
  • OverlayProps (101-101)
  • PortalProps (102-102)
  • TitleProps (104-104)
  • TriggerProps (105-105)
  • CloseProps (98-98)
🪛 Biome (1.9.4)
packages/dialog/src/web/dialog-web.web.tsx

[error] 35-35: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

packages/dialog/src/web/dialog-web.tsx

[error] 73-73: This code is unreachable

... because this statement will throw an exception beforehand

(lint/correctness/noUnreachable)

packages/dialog/src/base-types.ts

[error] 11-11: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


[error] 17-17: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


[error] 19-19: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


[error] 21-21: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

packages/dialog/src/native/dialog-native.tsx

[error] 73-73: This code is unreachable

... because this statement will throw an exception beforehand

(lint/correctness/noUnreachable)

packages/dialog/src/native/dialog-native.native.tsx

[error] 35-35: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)

🔇 Additional comments (39)
packages/dialog/src/base-types.ts (1)

9-10: Well-structured base types with proper abstraction.

The type definitions properly abstract the core dialog functionality while maintaining flexibility for platform-specific implementations. The use of Pick and Omit utilities ensures only relevant properties are exposed in each base type.

Also applies to: 13-16, 23-26

apps/nextjs-no-rn/src/components/ui/alert-dialog.tsx (1)

6-6: Good import organization.

Moving the mergeProps utility import before the React import follows common import ordering conventions and improves code organization.

apps/expo-nativewind/app/(components)/dialog.tsx (1)

33-35: Improved component abstraction with simplified usage.

The simplified DialogClose usage without the asChild prop and Button wrapper indicates better abstraction in the dialog v2 implementation. The DialogClose component now handles button styling internally, making the API cleaner and more consistent.

apps/nextjs-no-rn/package.json (1)

20-20: Necessary dependency addition for dialog v2 support.

Adding the @rn-primitives/dialog workspace dependency is required to support the new modular dialog implementation. The dependency is properly placed and follows the existing workspace dependency pattern.

apps/vite-tanstack-router/package.json (1)

21-21: LGTM! Dependency addition is correctly implemented.

The workspace dependency for @rn-primitives/dialog follows the established pattern and is properly positioned alphabetically within the dependencies list.

packages/dialog/tsup.config.ts (2)

4-15: LGTM! Build configuration properly supports modular architecture.

The expanded entry points correctly reflect the new platform-specific structure with separate universal, native, and web implementations. The file extensions (.tsx, .native.tsx, .web.tsx) follow React Native conventions for platform-specific modules.


21-29: External dependencies properly configured for modular structure.

The external array correctly includes the new internal module paths to prevent them from being bundled, which is essential for the platform-specific import resolution to work properly.

apps/nextjs-nativewind/src/app/page.tsx (3)

2-2: Minor: Import reordering.

The CollapsibleExample import was moved to an earlier position. This is a minor organizational change with no functional impact.


106-106: Dialog example now actively rendered.

Good to see the DialogExample component is now uncommented and actively displayed, allowing users to test the new dialog functionality.


246-248: DialogClose API simplified correctly.

The removal of the asChild prop and nested Button wrapper indicates that DialogClose now has built-in button styling and behavior. This simplification improves the API ergonomics while maintaining the same visual result.

apps/nextjs-no-rn/src/app/page.tsx (3)

26-35: Dialog component imports properly added.

The dialog component imports are complete and follow the established naming conventions. All necessary components are imported for the dialog example.


60-60: Dialog example correctly added to component list.

The DialogExample is properly positioned in the component rendering sequence, allowing users to interact with and test the dialog functionality.


210-234: Dialog example implementation follows established patterns.

The DialogExample implementation is well-structured and consistent with dialog usage in other apps:

  • Uses DialogTrigger with asChild pattern for the trigger button
  • Properly structured with DialogHeader, DialogTitle, and DialogDescription
  • Uses the simplified DialogClose API without nested button wrapper
  • Includes appropriate styling classes for responsive design

This provides a good demonstration of the new dialog v2 API.

packages/dialog/src/universal/index.ts (2)

1-11: Modular Re-exports of Universal Components
The universal entrypoint cleanly re-exports all React primitives (Close, Content, etc.) from ./dialog. This makes your public API surface explicit and maintainable.


13-22: Explicit Type Re-exports
Re-exporting the prop types from ./types aligns perfectly with the component exports above. Everything needed for consuming apps is exposed.

packages/dialog/src/web/index.ts (2)

1-11: Web-Specific Component Exports
Exporting Close, Content, Description, etc. from ./dialog-web correctly surfaces the web implementations.


13-22: Web-Specific Type Re-exports
Re-exporting the prop types from ./types mirrors the component exports, keeping the API consistent.

packages/dialog/package.json (1)

3-27: Version Bump & Platform Entrypoints
Bumping to 2.0.0-alpha.1 and adding ./native/./web under exports matches the new build outputs and modular structure.

packages/dialog/src/native/index.ts (1)

1-22: LGTM! Clean export organization.

The native dialog index file follows standard practices for component library organization. The explicit named exports provide clear visibility into what's available from the native module.

packages/dialog/src/utils/contexts.ts (1)

13-17: LGTM! Clean type exports.

The type alias and exports are well-organized and follow TypeScript best practices.

apps/vite-tanstack-router/src/routes/index.tsx (2)

21-30: LGTM! Comprehensive dialog imports.

The dialog component imports are well-organized and include all necessary components for a complete dialog implementation.


64-64: Good integration of the new DialogExample.

The DialogExample is properly integrated into the component showcase alongside other examples.

packages/dialog/src/index.ts (1)

1-22: Excellent improvement to explicit exports!

The change from wildcard exports (export * from) to explicit named exports is a significant improvement that provides:

  • Better tree-shaking for bundlers
  • Clearer API surface documentation
  • More control over the public interface
  • Better TypeScript intellisense

The explicit exports create a clean, predictable API surface for consumers of the dialog package.

packages/dialog/src/web/dialog-web.web.tsx (2)

17-39: Excellent implementation of the Root component with controllable state.

The implementation properly handles both controlled and uncontrolled state patterns using the useControllableState hook, and provides the state via React context for child components. The integration with Radix UI primitives is well-structured.

🧰 Tools
🪛 Biome (1.9.4)

[error] 35-35: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


41-46: Good use of primitive wrapping for cross-platform compatibility.

The wrapping of Radix UI components with withRNPrimitives provides a clean abstraction layer that enables consistent prop interfaces across platforms while maintaining the underlying Radix UI functionality.

packages/dialog/src/native/types.ts (1)

1-49: Excellent type definition structure with clear platform separation.

This type definition file demonstrates excellent TypeScript practices:

  • Clear separation between native-only props and combined props
  • Proper composition using intersection types
  • Consistent naming conventions
  • Comprehensive exports for both individual and combined types

The approach of extending base dialog props with platform-specific primitive props provides good type safety and flexibility for native implementations.

packages/dialog/src/native/dialog-native.tsx (1)

13-67: Good platform guard implementation pattern.

The stub component pattern effectively prevents misuse of native components on unsupported platforms while providing clear developer feedback. This approach helps maintain platform boundaries in the dialog system.

packages/dialog/src/universal/dialog.tsx (1)

1-59: Well-structured universal dialog implementation!

The implementation correctly forwards props to native components while ignoring web-specific props. The consistent pattern across all components and proper ref forwarding with type casting ensures TypeScript compatibility.

packages/dialog/src/native/dialog-native.native.tsx (3)

1-197: Excellent accessibility implementation!

The dialog components provide comprehensive accessibility features including:

  • Proper ARIA attributes (aria-modal, aria-labelledby, aria-describedby)
  • Hardware back button handling for Android
  • Accessibility escape gesture support
  • Semantic roles for all interactive elements
🧰 Tools
🪛 Biome (1.9.4)

[error] 35-35: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)


117-160: ⚠️ Potential issue

Fix missing dependency and property access error.

Two issues need to be addressed:

  1. Missing onOpenChange dependency in useEffect
  2. Incorrect boolean check on line 144

Apply this diff:

   React.useEffect(() => {
     const backHandler = BackHandler.addEventListener('hardwareBackPress', () => {
       onOpenChange(false);
       return true;
     });
 
     return () => {
       backHandler.remove();
     };
-  }, []);
+  }, [onOpenChange]);
   if (!forceMount) {
-    if (!value) {
+    if (!value.open) {
       return null;
     }
   }

Likely an incorrect or invalid review comment.


94-115: ⚠️ Potential issue

Fix variable reference and property access errors.

There are two critical issues in this component:

  1. Line 102 references an undefined variable onAccessibilityEscape
  2. Line 109 incorrectly checks !value instead of !value.open

Apply this diff to fix both issues:

 const  => {
-    if (typeof  'function') {
-      onAccessibilityEscape();
+    if (typeof  'function') {
+      onAccessibilityEscapeProp();
     }
     onOpenChange(false);
   }, [onAccessibilityEscapeProp, onOpenChange]);
 
   if (!forceMount) {
-    if (!value) {
+    if (!value.open) {
       return null;
     }
   }

Likely an incorrect or invalid review comment.

apps/vite-tanstack-router/src/components/ui/dialog.tsx (1)

1-142: Excellent platform-aware dialog implementation!

The dialog components demonstrate:

  • Thoughtful platform-specific styling with proper use of Platform.select
  • Smooth animations using react-native-reanimated
  • Proper prop merging for native animation configuration
  • Clear documentation explaining the View wrapper necessity for animations
  • Responsive design with Tailwind classes
apps/nextjs-nativewind/src/components/ui/dialog.tsx (2)

48-91: Well-structured platform abstraction with helpful documentation

The refactored DialogContent component effectively handles platform differences with:

  • Clear separation of native animation props
  • Helpful comment explaining the nativeID animation conflict
  • Proper portal host configuration support
  • Consistent platform-specific styling

The integration of the close button within the content view is clean and maintains proper styling across platforms.


104-123: Good simplification of title and description components

The refactoring from arrow functions with ref forwarding to plain function components is a good architectural decision. This simplification aligns with the component usage patterns and reduces unnecessary complexity.

packages/dialog/src/universal/dialog.web.tsx (2)

30-77: Consistent and well-structured web wrapper implementations

The implementation follows a consistent pattern across all components:

  • Proper handling of web/native prop separation
  • Conditional wrapping with View/Text when styles are needed
  • Clean destructuring to ignore native props on web platform

This approach provides good flexibility for styling while maintaining the Radix UI primitive behavior.


79-95: Good use of composition with Pressable wrappers

The Trigger and Close components effectively use the asChild pattern to wrap Radix primitives with Pressable, providing:

  • Proper button semantics on web with as: 'button'
  • Consistent prop merging with mergeProps
  • Clean separation of concerns

This pattern maintains accessibility while adding React Native compatibility.

apps/nextjs-no-rn/src/components/ui/dialog.tsx (1)

1-141: Excellent consistency across dialog implementations

This implementation maintains excellent consistency with the nextjs-nativewind dialog component, demonstrating:

  • Shared animation and styling patterns
  • Consistent platform abstraction approach
  • Appropriate variations (lucide-react icons, Button component usage) for the app context

The code reuse and architectural alignment across apps shows good engineering practices.

apps/expo-nativewind/components/ui/dialog.tsx (2)

17-39: LGTM! Well-structured overlay component with platform-specific animations.

The implementation properly handles platform differences and allows customization through prop merging while maintaining sensible animation defaults.


91-130: LGTM! Clean implementation of dialog sub-components.

The header, footer, title, description, and close components are well-structured with appropriate platform-specific styling and consistent use of the design system through button variants and text contexts.


type BaseDialogTitleProps = {};

type BaseDialogDescriptionProps = {};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Replace empty object type with a more specific type definition.

Replace the {} type with a more specific type definition to improve type safety.

-type BaseDialogDescriptionProps = {};
+type BaseDialogDescriptionProps = Record<string, never>;
📝 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
type BaseDialogDescriptionProps = {};
type BaseDialogDescriptionProps = Record<string, never>;
🧰 Tools
🪛 Biome (1.9.4)

[error] 21-21: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

🤖 Prompt for AI Agents
In packages/dialog/src/base-types.ts at line 21, replace the empty object type
`{}` in the BaseDialogDescriptionProps type alias with a more specific type
definition that accurately reflects the expected properties. Define explicit
properties or use an appropriate interface to improve type safety and clarity.


type BaseDialogOverlayProps = Pick<DialogOverlayProps, 'forceMount'>;

type BaseDialogCloseProps = {};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Replace empty object type with a more specific type definition.

Same issue as with BaseDialogTriggerProps - the {} type reduces type safety.

-type BaseDialogCloseProps = {};
+type BaseDialogCloseProps = Record<string, never>;
📝 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
type BaseDialogCloseProps = {};
type BaseDialogCloseProps = Record<string, never>;
🧰 Tools
🪛 Biome (1.9.4)

[error] 17-17: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

🤖 Prompt for AI Agents
In packages/dialog/src/base-types.ts at line 17, replace the empty object type
{} for BaseDialogCloseProps with a more specific type definition to improve type
safety, similar to the approach used for BaseDialogTriggerProps. Define explicit
properties or use a more precise type instead of an empty object.


type BaseDialogRootProps = Omit<Prettify<DialogProps>, 'children'>;

type BaseDialogTriggerProps = {};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Replace empty object type with a more specific type definition.

The {} type is overly permissive and means "any non-nullable value", which reduces type safety. Consider defining the actual shape of trigger props or using Record<string, never> for truly empty objects.

-type BaseDialogTriggerProps = {};
+type BaseDialogTriggerProps = Record<string, never>;

Alternatively, if trigger props are expected to have specific properties, define them explicitly:

-type BaseDialogTriggerProps = {};
+type BaseDialogTriggerProps = {
+  asChild?: boolean;
+  // Add other expected trigger props
+};
📝 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
type BaseDialogTriggerProps = {};
-type BaseDialogTriggerProps = {};
+type BaseDialogTriggerProps = Record<string, never>;
🧰 Tools
🪛 Biome (1.9.4)

[error] 11-11: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

🤖 Prompt for AI Agents
In packages/dialog/src/base-types.ts at line 11, the type BaseDialogTriggerProps
is currently defined as an empty object type {}, which is too permissive and
reduces type safety. Replace the {} with a more specific type definition that
accurately represents the expected properties of trigger props. If no properties
are expected, use Record<string, never> to indicate an empty object type
explicitly. Otherwise, define the exact properties and their types that trigger
props should have.


type BaseDialogCloseProps = {};

type BaseDialogTitleProps = {};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Replace empty object type with a more specific type definition.

The {} type should be replaced with a more specific type definition for better type safety.

-type BaseDialogTitleProps = {};
+type BaseDialogTitleProps = Record<string, never>;
📝 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
type BaseDialogTitleProps = {};
type BaseDialogTitleProps = Record<string, never>;
🧰 Tools
🪛 Biome (1.9.4)

[error] 19-19: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

🤖 Prompt for AI Agents
In packages/dialog/src/base-types.ts at line 19, replace the empty object type
`{}` in the BaseDialogTitleProps type alias with a more specific type definition
that accurately reflects the expected properties for better type safety.
Identify the actual properties needed for BaseDialogTitleProps and define them
explicitly instead of using an empty object type.

Comment on lines +1 to +7
import type {
PressablePropsUniversal,
TextPropsUniversal,
ViewPropsUniversal,
} from '@rn-primitives/core';
import type { Prettify } from '@rn-primitives/types';
import type {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Missing React Type Import for ReactNode
You're using React.ReactNode in RootProps but haven't imported React or ReactNode. This will error in TS. Please add a type import and switch to ReactNode:

+import type { ReactNode } from 'react';
 
 type RootProps = Prettify<
   BaseDialogRootProps & {
-    children?: React.ReactNode;
+    children?: ReactNode;
   }
 >;

Also applies to: 44-48

🤖 Prompt for AI Agents
In packages/dialog/src/universal/types.ts around lines 1 to 7 and also lines 44
to 48, the type ReactNode is used without importing it, causing TypeScript
errors. Add an import statement to import ReactNode as a type from 'react' at
the top of the file, then replace all instances of React.ReactNode with just
ReactNode to fix the issue.

Comment on lines +69 to +74
const useRootContext = () => {
throw new Error(
'Cannot access the native useRootContext on the web. Please import from `@rn-primitives/dialog` or `@rn-primitives/dialog/web`'
);
return {} as RootContextReturnType;
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove unreachable code after throw statement.

The static analysis tool correctly identifies that the return statement after the throw is unreachable and will never execute.

Apply this diff to remove the unreachable code:

const useRootContext = () => {
  throw new Error(
    'Cannot access the native useRootContext on the web. Please import from `@rn-primitives/dialog` or `@rn-primitives/dialog/web`'
  );
- return {} as RootContextReturnType;
};
📝 Committable suggestion

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

Suggested change
const useRootContext = () => {
throw new Error(
'Cannot access the native useRootContext on the web. Please import from `@rn-primitives/dialog` or `@rn-primitives/dialog/web`'
);
return {} as RootContextReturnType;
};
const useRootContext = () => {
throw new Error(
'Cannot access the native useRootContext on the web. Please import from `@rn-primitives/dialog` or `@rn-primitives/dialog/web`'
);
};
🧰 Tools
🪛 Biome (1.9.4)

[error] 73-73: This code is unreachable

... because this statement will throw an exception beforehand

(lint/correctness/noUnreachable)

🤖 Prompt for AI Agents
In packages/dialog/src/native/dialog-native.tsx around lines 69 to 74, remove
the return statement after the throw error because it is unreachable code and
will never execute. Simply delete the line containing "return {} as
RootContextReturnType;" to fix the issue.

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
0