Skip to content

feat: Add password field component with reveal/hide functionality#113

Merged
jaruesink merged 5 commits intomainfrom
codegen-bot/password-field-with-reveal-hide-1754193293
Aug 3, 2025
Merged

feat: Add password field component with reveal/hide functionality#113
jaruesink merged 5 commits intomainfrom
codegen-bot/password-field-with-reveal-hide-1754193293

Conversation

@codegen-sh
Copy link
Copy Markdown
Contributor

@codegen-sh codegen-sh Bot commented Aug 3, 2025

🔐 Password Field Component

This PR adds a new password field component with reveal/hide functionality and comprehensive validation support.

✨ Features Added

  • PasswordField UI Component: Base component with eye/eye-off toggle icons from Lucide React
  • RemixHookForm Wrapper: Seamless integration with the existing form system
  • Comprehensive Storybook Story: Create account form example with password confirmation
  • Zod Schema Validation: Password strength and confirmation matching validation
  • Accessibility: Proper ARIA labels and keyboard navigation
  • TypeScript Support: Full type safety and IntelliSense support

🎯 Key Components

UI Components

  • packages/components/src/ui/password-field.tsx - Base password field with toggle
  • packages/components/src/remix-hook-form/password-field.tsx - Remix Hook Form wrapper

Storybook Story

  • apps/docs/src/remix-hook-form/password-field.stories.tsx - Complete create account form example

🧪 Validation Features

The story demonstrates:

  • Password strength validation (minimum 8 characters)
  • Password confirmation matching using Zod's refine method
  • Real-time validation feedback with clear error messages
  • Server-side validation integration following existing patterns

🎨 UI/UX Features

  • Toggle visibility with eye/eye-off icons
  • Smooth transitions and hover states
  • Consistent styling with existing form components
  • Prefix support for additional customization
  • Ref forwarding for programmatic focus control

📋 Usage Example

import { PasswordField } from '@lambdacurry/forms/remix-hook-form/password-field';

// In your form schema
const formSchema = z.object({
  password: z.string().min(8, 'Password must be at least 8 characters'),
  confirmPassword: z.string().min(1, 'Please confirm your password'),
}).refine((data) => data.password === data.confirmPassword, {
  message: "Passwords don't match",
  path: ["confirmPassword"],
});

// In your component
<PasswordField 
  name="password" 
  label="Password" 
  description="Must be at least 8 characters long"
  placeholder="Enter your password"
/>

<PasswordField 
  name="confirmPassword" 
  label="Confirm Password" 
  description="Re-enter your password to confirm"
  placeholder="Confirm your password"
/>

✅ Testing

The story includes comprehensive tests for:

  • Default values and form state
  • Password visibility toggle functionality
  • Weak password validation
  • Password mismatch validation
  • Successful form submission
  • Ref functionality

🔧 Technical Details

  • Follows existing form component patterns from .cursor/rules/form-component-patterns.mdc
  • Uses Lucide React icons (Eye, EyeOff) for consistency
  • Maintains proper TypeScript interfaces and exports
  • Integrates with existing FormField, FormControl, and validation systems
  • Supports all existing TextField features (prefix, custom components, etc.)

Ready for review! 🚀


💻 View my workAbout Codegen
⛔ Remove Codegen from PR🚫 Ban action checks

Summary by CodeRabbit

  • New Features
    • Introduced a customizable password field component with support for password visibility toggle and integration with form validation.
    • Added Storybook examples and tests demonstrating password field usage, validation scenarios, and UI behaviors.
  • Improvements
    • Made the password field component available in both UI and Remix Hook Form modules for broader usage.
    • Updated package version to reflect new features.
  • Chores
    • Reformatted workspace configuration for improved readability.

- Add PasswordField UI component with eye/eye-off toggle icons
- Add RemixHookForm wrapper for PasswordField
- Create comprehensive Storybook story with create account form example
- Include Zod schema validation for password confirmation
- Add proper TypeScript types and accessibility features
- Export components in index files for easy import
@bolt-new-by-stackblitz
Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Aug 3, 2025

Walkthrough

A new password field component was introduced for both react-hook-form and remix-hook-form contexts, along with supporting Storybook stories and validation logic. The component supports password visibility toggling, custom subcomponents, and integrates with form state management. Package exports and dependencies were updated to make the new component available.

Changes

Cohort / File(s) Change Summary
Remix Password Field Storybook
apps/docs/src/remix-hook-form/password-field.stories.tsx
Added Storybook story for the new password field component with Remix Hook Form and Zod validation, including test scenarios and a form submission handler.
Remix-Hook-Form PasswordField Integration
packages/components/src/remix-hook-form/index.ts, packages/components/src/remix-hook-form/password-field.tsx
Added and exported a new PasswordField component for Remix Hook Form, integrating with form context and supporting custom UI subcomponents.
UI PasswordField Component
packages/components/src/ui/password-field.tsx, packages/components/src/ui/index.ts
Introduced and exported a new PasswordField UI component with password visibility toggle, form integration, and customizable subcomponents.
Component Package Version
packages/components/package.json
Updated @lambdacurry/forms dependency version from 0.18.1 to 0.19.0.
Root Package Workspaces Formatting
package.json
Reformatted the workspaces array for improved readability; no functional change.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Storybook UI
    participant CreateAccountForm
    participant PasswordField
    participant RemixFormContext
    participant ZodValidator
    participant handleFormSubmission

    User->>Storybook UI: Interacts with CreateAccountExample story
    Storybook UI->>CreateAccountForm: Renders form
    CreateAccountForm->>PasswordField: Renders password input fields
    PasswordField->>RemixFormContext: Retrieves form control
    User->>PasswordField: Enters passwords / toggles visibility
    User->>CreateAccountForm: Submits form
    CreateAccountForm->>ZodValidator: Validates input
    ZodValidator-->>CreateAccountForm: Returns validation result
    CreateAccountForm->>handleFormSubmission: Submits validated data
    handleFormSubmission-->>CreateAccountForm: Returns success or error
    CreateAccountForm-->>Storybook UI: Displays result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

Hopping through code with a password to guard,
I built a new field—reviewing wasn’t hard!
Toggle to peek, or keep secrets tight,
With Remix and Zod, your form feels just right.
From UI to stories, the changes are neat—
This rabbit’s new field is secure and sweet! 🥕🔒


📜 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 de0cacf and a78b152.

📒 Files selected for processing (1)
  • packages/components/src/ui/password-field.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/components/src/ui/password-field.tsx
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codegen-bot/password-field-with-reveal-hide-1754193293

🪧 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 generate unit tests to generate unit tests for 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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Aug 3, 2025

📝 Storybook Preview: View Storybook

This preview will be updated automatically when you push new changes to this PR.

Note: The preview will be available after the workflow completes and the PR is approved for deployment.

@codegen-sh
Copy link
Copy Markdown
Contributor Author

codegen-sh Bot commented Aug 3, 2025

🔍 Check Suite Status for PR #113

Check Status Commit Time Check Suite Agent trace
test ⚪ No action 93bfc60 Just now Run
GitHub Actions ⚪ No action 93bfc60 Just now Run Agent Work
Results & Findings

test: ✅ Fixed the failing test on PR #113! The issue was in the password field Storybook test.

💻 View my work🛑 Stop🚫 Ban all checks

@jaruesink
Copy link
Copy Markdown
Contributor

jaruesink commented Aug 3, 2025

@codegen-sh the test failed "Unable to find a label with the text of: Hide password", please fix the issue so that test can pass

I'll fix the test issue so it can pass! 🛠️

💻 View my work🛑 Stop

The test was expecting 'Hide password' label initially, but the component
correctly shows 'Show password' when password is hidden (isVisible = false).
Updated test to match the correct component behavior.
@codegen-sh
Copy link
Copy Markdown
Contributor Author

codegen-sh Bot commented Aug 3, 2025

✅ Fixed the test issue! The problem was that the test expected "Hide password" as the initial aria-label, but the component correctly shows "Show password" when the password is hidden (initial state).

I've updated the test expectations to match the correct component behavior:

  • Initial state: "Show password" (when password is hidden)
  • After clicking: "Hide password" (when password is visible)

The test should now pass! 🎯

🔄 View Updated PR #113 on Github 🔄

💻 View my work🛑 Stop • React 👍 or 👎

@jaruesink
Copy link
Copy Markdown
Contributor

jaruesink commented Aug 3, 2025

@codegen-sh now I'm getting this error in my tests Found multiple elements with the text of: Show password

I'll investigate the "multiple elements" test error for you... 🕵️‍♂️

💻 View my work🛑 Stop

… expectations

The test was expecting 'Hide password' initially, but the component correctly
starts with 'Show password' when the password is hidden. Updated the test to
use proper DOM traversal to find the correct toggle button for each password
field, avoiding conflicts with multiple password fields in the form.
@codegen-sh
Copy link
Copy Markdown
Contributor Author

codegen-sh Bot commented Aug 3, 2025

✅ Fixed the "multiple elements" test error! 🎯

The Issue:
The test was failing because there are 3 password fields in the form (password, confirmPassword, and refExample), which means 3 toggle buttons all with the same aria-label "Show password".

The Solution:
Instead of using getByLabelText('Show password') which fails when multiple elements exist, I used DOM traversal to find the specific toggle button within the same form container as the password input:

// Find the toggle button within the same form item as the password input
const formItem = passwordInput.closest('[class*="FormItem"], .form-item, [data-testid="form-item"]') || 
                 passwordInput.parentElement?.parentElement;
const toggleButton = formItem?.querySelector('button[aria-label="Show password"]') as HTMLElement;

This approach ensures we're testing the correct toggle button that belongs to the "Password" field specifically, rather than accidentally clicking the wrong one.

The tests should now pass! 🚀

🔄 View Updated PR #113 on Github 🔄

💻 View my work🛑 Stop • React 👍 or 👎

@jaruesink
Copy link
Copy Markdown
Contributor

jaruesink commented Aug 3, 2025

@codegen-sh let's bump the components package up a minor version using npm cli with a summary message of the work we did. no need to publish, just do the version bump. run a yarn install to make sure the yarn lock is clean after as well. push up once you're done.

On it! I'll bump the minor version, update yarn lock, and push. 🔼

💻 View my work🛑 Stop

- Bump minor version for password field component release
- Update yarn.lock with latest dependencies
- Version includes new PasswordField component with reveal/hide functionality
@codegen-sh
Copy link
Copy Markdown
Contributor Author

codegen-sh Bot commented Aug 3, 2025

Version bump complete! 🎉

What I did:

  • 🔼 Bumped @lambdacurry/forms from v0.18.1v0.19.0 (minor version)
  • 📝 Added comprehensive commit message summarizing the password field component work
  • 🧹 Ran yarn install to clean up the yarn.lock file
  • 🚀 Pushed all changes to the PR

Version Summary:

feat: add password field component with reveal/hide functionality

- Add PasswordField UI component with eye/eye-off toggle icons
- Add RemixHookForm wrapper for seamless form integration  
- Add comprehensive Storybook story with create account form example
- Add Zod schema validation for password strength and confirmation matching
- Add full accessibility support with proper ARIA labels
- Add TypeScript support with complete type safety

The package is now ready at v0.19.0 with all the new password field functionality! 🔐

🔄 View Updated PR #113 on Github 🔄

💻 View my work🛑 Stop • React 👍 or 👎

@jaruesink jaruesink marked this pull request as ready for review August 3, 2025 04:20
Copy link
Copy Markdown

@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

🔭 Outside diff range comments (1)
packages/components/src/ui/password-field.tsx (1)

125-126: Add missing exports for component and props type

According to the coding guidelines, both the component and its props type should be exported at the end of the file.

 PasswordField.displayName = 'PasswordField';
+
+export { PasswordField };
+export type { PasswordInputProps };
🧹 Nitpick comments (2)
apps/docs/src/remix-hook-form/password-field.stories.tsx (1)

1-11: Fix import ordering according to coding guidelines

Imports should be ordered as: 1) external libraries, 2) internal package imports, 3) cross-package imports, 4) type-only imports.

-import { zodResolver } from '@hookform/resolvers/zod';
-import { PasswordField } from '@lambdacurry/forms/remix-hook-form/password-field';
-import { Button } from '@lambdacurry/forms/ui/button';
-import type { Meta, StoryContext, StoryObj } from '@storybook/react-vite';
-import { expect, userEvent } from '@storybook/test';
-import { useRef } from 'react';
-import { type ActionFunctionArgs, useFetcher } from 'react-router';
-import { RemixFormProvider, getValidatedFormData, useRemixForm } from 'remix-hook-form';
-import { z } from 'zod';
-import { withReactRouterStubDecorator } from '../lib/storybook/react-router-stub';
+import { zodResolver } from '@hookform/resolvers/zod';
+import type { Meta, StoryContext, StoryObj } from '@storybook/react-vite';
+import { expect, userEvent } from '@storybook/test';
+import { useRef } from 'react';
+import { type ActionFunctionArgs, useFetcher } from 'react-router';
+import { RemixFormProvider, getValidatedFormData, useRemixForm } from 'remix-hook-form';
+import { z } from 'zod';
+import { PasswordField } from '@lambdacurry/forms/remix-hook-form/password-field';
+import { Button } from '@lambdacurry/forms/ui/button';
+import { withReactRouterStubDecorator } from '../lib/storybook/react-router-stub';
packages/components/src/ui/password-field.tsx (1)

17-39: Define and export PasswordToggleButtonProps interface

According to the coding guidelines, components should export both the component and its props type. The props are currently defined inline.

+export interface PasswordToggleButtonProps {
+  isVisible: boolean;
+  onToggle: () => void;
+  className?: string;
+}
+
 export const PasswordToggleButton = ({
   isVisible,
   onToggle,
   className,
-}: {
-  isVisible: boolean;
-  onToggle: () => void;
-  className?: string;
-}) => {
+}: PasswordToggleButtonProps) => {

Also add the export at the end of the file:

export type { PasswordToggleButtonProps };
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b004b8a and de0cacf.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (7)
  • apps/docs/src/remix-hook-form/password-field.stories.tsx (1 hunks)
  • package.json (1 hunks)
  • packages/components/package.json (1 hunks)
  • packages/components/src/remix-hook-form/index.ts (1 hunks)
  • packages/components/src/remix-hook-form/password-field.tsx (1 hunks)
  • packages/components/src/ui/index.ts (1 hunks)
  • packages/components/src/ui/password-field.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (19)
{package.json,packages/**/package.json,apps/**/package.json}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo-organization.mdc)

Use consistent versioning across packages

Files:

  • packages/components/package.json
  • package.json
{packages/**/package.json,apps/**/package.json}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo-organization.mdc)

Define peerDependencies, dependencies, and devDependencies appropriately in package.json

Files:

  • packages/components/package.json
**/*.ts

📄 CodeRabbit Inference Engine (.cursor/rules/form-component-patterns.mdc)

Handle server-side validation using getValidatedFormData with zodResolver and return errors as needed

Files:

  • packages/components/src/ui/index.ts
  • packages/components/src/remix-hook-form/index.ts
packages/components/src/ui/*.{tsx,ts}

📄 CodeRabbit Inference Engine (.cursor/rules/form-component-patterns.mdc)

Base UI components should be named as ComponentName in ui/ directory

Files:

  • packages/components/src/ui/index.ts
  • packages/components/src/ui/password-field.tsx
**/*.{tsx,ts}

📄 CodeRabbit Inference Engine (.cursor/rules/form-component-patterns.mdc)

**/*.{tsx,ts}: Props interfaces should be named as ComponentNameProps
Form schemas should be named formSchema or componentNameSchema

Files:

  • packages/components/src/ui/index.ts
  • packages/components/src/remix-hook-form/index.ts
  • packages/components/src/remix-hook-form/password-field.tsx
  • packages/components/src/ui/password-field.tsx
  • apps/docs/src/remix-hook-form/password-field.stories.tsx
packages/components/src/{remix-hook-form,ui}/*.{tsx,ts}

📄 CodeRabbit Inference Engine (.cursor/rules/form-component-patterns.mdc)

Always export both the component and its props type

Files:

  • packages/components/src/ui/index.ts
  • packages/components/src/remix-hook-form/index.ts
  • packages/components/src/remix-hook-form/password-field.tsx
  • packages/components/src/ui/password-field.tsx
{apps,packages}/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo-organization.mdc)

{apps,packages}/**/*.{ts,tsx}: Use package name imports for published packages (e.g., import { TextField } from '@lambdacurry/forms/remix-hook-form')
Import from specific entry points (e.g., import { TextField } from '@lambdacurry/forms/remix-hook-form/text-field')
Do not use relative imports across packages (e.g., avoid import { TextField } from '../../packages/components/src/remix-hook-form/text-field')
Order imports: 1) external libraries, 2) internal package imports, 3) cross-package imports, 4) type-only imports (grouped separately)

Files:

  • packages/components/src/ui/index.ts
  • packages/components/src/remix-hook-form/index.ts
  • packages/components/src/remix-hook-form/password-field.tsx
  • packages/components/src/ui/password-field.tsx
  • apps/docs/src/remix-hook-form/password-field.stories.tsx
{apps,packages}/**/src/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo-organization.mdc)

{apps,packages}/**/src/**/*.{ts,tsx}: Use relative imports within the same package (e.g., import { FormControl } from './form')
Use relative imports for sibling directories (e.g., import { Button } from '../ui/button')

Files:

  • packages/components/src/ui/index.ts
  • packages/components/src/remix-hook-form/index.ts
  • packages/components/src/remix-hook-form/password-field.tsx
  • packages/components/src/ui/password-field.tsx
  • apps/docs/src/remix-hook-form/password-field.stories.tsx
packages/components/src/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo-organization.mdc)

packages/components/src/**/*.{ts,tsx}: Always export both component and props type (e.g., export { ComponentName }; export type { ComponentNameProps };)
Use named exports for components for better tree-shaking (e.g., export const ComponentName = ...; avoid default exports)
Avoid default exports for components
Use tree-shaking friendly exports

Files:

  • packages/components/src/ui/index.ts
  • packages/components/src/remix-hook-form/index.ts
  • packages/components/src/remix-hook-form/password-field.tsx
  • packages/components/src/ui/password-field.tsx
{apps,packages}/**/src/**/*.{tsx,ts}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo-organization.mdc)

{apps,packages}/**/src/**/*.{tsx,ts}: Use kebab-case for component file names (e.g., text-field.tsx, data-table.tsx)
Match component name in PascalCase to the exported component from the file (e.g., text-field.tsx exports TextField)

Files:

  • packages/components/src/ui/index.ts
  • packages/components/src/remix-hook-form/index.ts
  • packages/components/src/remix-hook-form/password-field.tsx
  • packages/components/src/ui/password-field.tsx
  • apps/docs/src/remix-hook-form/password-field.stories.tsx
packages/components/src/ui/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo-organization.mdc)

Don't import from remix-hook-form package in ui components

Files:

  • packages/components/src/ui/index.ts
  • packages/components/src/ui/password-field.tsx
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo-organization.mdc)

Avoid circular dependencies

Files:

  • packages/components/src/ui/index.ts
  • packages/components/src/remix-hook-form/index.ts
  • packages/components/src/remix-hook-form/password-field.tsx
  • packages/components/src/ui/password-field.tsx
  • apps/docs/src/remix-hook-form/password-field.stories.tsx
packages/components/src/**/*index.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo-organization.mdc)

Re-export with explicit names and types; avoid mixing default and named exports

Files:

  • packages/components/src/ui/index.ts
  • packages/components/src/remix-hook-form/index.ts
packages/components/src/remix-hook-form/*.{tsx,ts}

📄 CodeRabbit Inference Engine (.cursor/rules/form-component-patterns.mdc)

Form-aware components should be named as ComponentName (e.g., TextField, Checkbox)

Files:

  • packages/components/src/remix-hook-form/index.ts
  • packages/components/src/remix-hook-form/password-field.tsx
packages/components/src/remix-hook-form/**/*.tsx

📄 CodeRabbit Inference Engine (.cursor/rules/form-component-patterns.mdc)

packages/components/src/remix-hook-form/**/*.tsx: Use remix-hook-form for form state management and validation
Maintain FormField consistency for all form inputs
Ensure proper accessibility and validation integration in form components
Always define Zod schemas with proper error messages for form validation
Use the required imports for Remix Hook Form integration, Zod, and base UI components in form-aware components
Follow the wrapper component pattern for all form-aware components
Use the form setup pattern for form initialization in Remix
Use Zod schemas for all form validation
Provide clear, user-friendly error messages in validation
Validate on blur and submit, not on every keystroke
Always display field-level errors using FormMessage
Handle both client-side and server-side validation errors in form components
Provide loading states during form submission
Clear errors appropriately when fields are corrected
Use React.memo for expensive form components
Avoid unnecessary re-renders by properly structuring form state
Consider field-level subscriptions for large forms
All form fields must have proper labels
Use ARIA attributes for complex form interactions
Ensure keyboard navigation works correctly in form components
Provide clear error announcements for screen readers

Files:

  • packages/components/src/remix-hook-form/password-field.tsx
packages/components/src/ui/**/*.tsx

📄 CodeRabbit Inference Engine (.cursor/rules/form-component-patterns.mdc)

packages/components/src/ui/**/*.tsx: Build on @radix-ui components as the foundation for base UI components
Follow the component composition pattern for UI components that accept form integration

Files:

  • packages/components/src/ui/password-field.tsx
apps/docs/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/monorepo-organization.mdc)

In apps/docs, import from package name instead of relative paths for cross-package dependencies

Files:

  • apps/docs/src/remix-hook-form/password-field.stories.tsx
apps/docs/src/remix-hook-form/**/*.stories.tsx

📄 CodeRabbit Inference Engine (.cursor/rules/storybook-testing.mdc)

apps/docs/src/remix-hook-form/**/*.stories.tsx: Always place decorators on individual stories, not in meta configuration.
Never place decorators in meta configuration.
Use kebab-case for story file names in 'apps/docs/src/remix-hook-form/'.
Always include all three test phases in stories: default state, invalid submission, and valid submission.
Use play functions for comprehensive interaction testing in Storybook stories.
Always use fetcher.Form instead of regular form elements in stories that require React Router integration.
Always click before clearing inputs with userEvent in interaction tests.
Use findBy* queries for async elements instead of getBy* in Storybook interaction tests.
Never use CSS selectors when semantic queries (role, label, etc.) are available in canvas queries.
Each story should test one primary workflow and not multiple unrelated scenarios.
Group related test functions together and export individual test functions for reusability.
Use semantic queries (getByRole, getByLabelText, etc.) as the preferred method for selecting elements in interaction tests.
Meta configuration in stories should be kept clean and minimal, avoiding unnecessary parameters and decorators.
Always import required testing utilities: Meta, StoryObj, expect, userEvent, and withReactRouterStubDecorator in Storybook test stories.
Test both client-side and server-side validation in form stories.
Stories should serve as both documentation and automated tests.
Tests should complete in under 10 seconds for fast feedback.
Use step grouping in play functions for better debugging and organization of complex interactions.
Never use getBy* queries for async elements in Storybook interaction tests.
Never clear inputs without clicking first in userEvent interactions.
Never use regular forms instead of fetcher.Form in stories that require React Router integration.
Never test multiple unrelated scenarios in one story.
Never use CSS selectors when semantic queries are available.
Group rel...

Files:

  • apps/docs/src/remix-hook-form/password-field.stories.tsx
apps/docs/**

📄 CodeRabbit Inference Engine (.cursor/rules/storybook-testing.mdc)

apps/docs/**: Build Storybook static files before running Playwright tests locally.
Install Playwright browsers and system dependencies before running interaction tests.

Files:

  • apps/docs/src/remix-hook-form/password-field.stories.tsx
🔇 Additional comments (8)
package.json (1)

5-8: LGTM! Formatting improvement for better readability.

The workspaces array formatting change improves readability while maintaining the same functionality.

packages/components/package.json (1)

3-3: Version bump is appropriate for new feature addition.

The minor version bump from 0.18.1 to 0.19.0 correctly follows semantic versioning for the addition of the new password field components.

packages/components/src/ui/index.ts (1)

20-20: Export addition follows established patterns.

The password-field export is correctly placed and follows the existing wildcard export pattern used throughout the file.

packages/components/src/remix-hook-form/index.ts (1)

7-7: Export addition is consistent with established patterns.

The password-field export follows the existing wildcard export pattern and is logically placed among other field components.

packages/components/src/remix-hook-form/password-field.tsx (4)

1-9: Import structure follows coding guidelines correctly.

The imports are properly organized with external libraries first, followed by internal package imports. The import ordering and naming conventions align with the established patterns.


10-10: Type definition correctly omits control prop.

The PasswordFieldProps type appropriately omits the control prop since it's provided by the remix form context, following the established pattern for remix-hook-form wrappers.


12-31: Component implementation follows established wrapper pattern.

The component correctly:

  • Extracts control from remix form context
  • Merges default form components with custom ones
  • Forwards all props to the base component
  • Maintains proper TypeScript integration

The implementation is consistent with other remix-hook-form wrapper components in the codebase.


33-33: Display name assignment aids debugging.

Setting the display name helps with React DevTools debugging and follows the established pattern for form components.

Comment thread apps/docs/src/remix-hook-form/password-field.stories.tsx
@jaruesink
Copy link
Copy Markdown
Contributor

jaruesink commented Aug 3, 2025

@codegen-sh

implement this suggestion

17-39: Define and export PasswordToggleButtonProps interface

According to the coding guidelines, components should export both the component and its props type. The props are currently defined inline.

+export interface PasswordToggleButtonProps {

  • isVisible: boolean;
  • onToggle: () => void;
  • className?: string;
    +}

export const PasswordToggleButton = ({
isVisible,
onToggle,
className,
-}: {

  • isVisible: boolean;
  • onToggle: () => void;
  • className?: string;
    -}) => {
    +}: PasswordToggleButtonProps) => {

I'll implement the exported props interface update! 🛠️

💻 View my work🛑 Stop

- Define and export PasswordToggleButtonProps interface according to coding guidelines
- Components should export both the component and its props type
- Replace inline props definition with exported interface for better reusability
@codegen-sh
Copy link
Copy Markdown
Contributor Author

codegen-sh Bot commented Aug 3, 2025

Exported props interface implemented! 🎯

Changes Made:

  • ✅ Defined and exported PasswordToggleButtonProps interface
  • ✅ Replaced inline props definition with the exported interface
  • ✅ Follows coding guidelines for component exports

Before:

export const PasswordToggleButton = ({
  isVisible,
  onToggle,
  className,
}: {
  isVisible: boolean;
  onToggle: () => void;
  className?: string;
}) => {

After:

export interface PasswordToggleButtonProps {
  isVisible: boolean;
  onToggle: () => void;
  className?: string;
}

export const PasswordToggleButton = ({
  isVisible,
  onToggle,
  className,
}: PasswordToggleButtonProps) => {

Now the component properly exports both the component and its props type, making it more reusable and following the established coding guidelines! 🚀

🔄 View Updated PR #113 on Github 🔄

💻 View my work🛑 Stop • React 👍 or 👎

@jaruesink jaruesink merged commit f96eec7 into main Aug 3, 2025
5 checks passed
@jaruesink jaruesink deleted the codegen-bot/password-field-with-reveal-hide-1754193293 branch August 3, 2025 04:47
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