Skip to content

Conversation

@arjunkomath
Copy link
Member

@arjunkomath arjunkomath commented Aug 21, 2025

Summary by CodeRabbit

  • New Features
    • Added global keyboard shortcut: press “N” to start creating a new task or calendar event. Shortcut is ignored while typing in inputs or editable fields.
  • Style
    • Updated “New” button in the calendar to display a “N” keyboard hint (visible on medium+ screens), replacing the previous icon.
  • Refactor
    • Unified shortcut handling across the app for a more consistent, reliable create experience.

@coderabbitai
Copy link

coderabbitai bot commented Aug 21, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Introduces a reusable useKeyboardShortcut hook and refactors components to use it. Adds global “n” key handling to open create modes in task form and calendar. Updates the calendar’s “New” button to show a Kbd “N” hint on larger screens. Removes inline keydown logic from task component.

Changes

Cohort / File(s) Summary
Keyboard shortcut hook introduction
hooks/use-keyboard-shortcut.ts
New hook that registers a document keydown listener for a given key; ignores modifier keys, repeats, and typing/editing contexts; invokes callback; cleans up on unmount or dependency change.
Task form: refactor to hook
components/form/task.tsx
Replaces in-component keydown effect for “n” with useKeyboardShortcut to trigger setIsCreating(true). Removes local guard logic; now delegated to the hook.
Project calendar: shortcut + UI hint
components/project/events/full-calendar.tsx
Adds useKeyboardShortcut for “n” to set create mode. Replaces PlusCircleIcon with a Kbd “N” hint on the New button (hidden on small screens). Updates imports accordingly.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant U as User
  participant D as Document
  participant H as useKeyboardShortcut
  participant C1 as TaskForm
  participant C2 as Calendar

  U->>D: Press "n"
  D-->>H: keydown event
  H->>H: Validate key, modifiers, repeat, and editing context
  alt Valid "n" and not typing
    H-->>C1: callback() (if mounted) -> setIsCreating(true)
    H-->>C2: callback() (if mounted) -> setCreate(true)
    C1->>C1: Open create dialog (task)
    C2->>C2: Open create state (calendar)
  else Ignored
    H-->>D: No action
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

A tap of “n” and doors appear,
I thump my paws—creation near!
From fields of forms to dates that gleam,
A shortcut hops into the stream.
Hooks abound; I twitch with glee—
New things sprout as quick as me.
(。•̀🐇•́)✧

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch main

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.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

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

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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.

@vercel
Copy link

vercel bot commented Aug 21, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
manage Ready Ready Preview Aug 22, 2025 8:19am

@arjunkomath
Copy link
Member Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Aug 21, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-advanced-security
Copy link

This pull request sets up GitHub code scanning for this repository. Once the scans have completed and the checks have passed, the analysis results for this pull request branch will appear on this overview. Once you merge this pull request, the 'Security' tab will show more code scanning analysis results (for example, for the default branch). Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results. For more information about GitHub code scanning, check out the documentation.

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: 0

🧹 Nitpick comments (6)
hooks/use-keyboard-shortcut.ts (3)

3-3: Drop the explicit boolean type on enabled (Biome hint).

The default value makes the type trivially inferrable. This quiets the linter without changing behavior.

-export function useKeyboardShortcut(key: string, callback: () => void, enabled: boolean = true) {
+export function useKeyboardShortcut(key: string, callback: () => void, enabled = true) {

7-23: Stabilize callback, make key matching case-insensitive via normalization, and guard IME composition.

  • Avoid re-subscribing on every render by storing the latest callback in a ref.
  • Normalize both e.key and key to lowercase instead of comparing both cases.
  • Ignore events while composing (e.isComposing) to play nice with IMEs.
  • Add a defensive instanceof Element check before calling closest.
-import { useEffect } from "react";
+import { useEffect, useRef } from "react";
 
-export function useKeyboardShortcut(key: string, callback: () => void, enabled: boolean = true) {
-	useEffect(() => {
-		if (!enabled) return;
+export function useKeyboardShortcut(key: string, callback: () => void, enabled = true) {
+	const cbRef = useRef(callback);
+	// Keep latest callback without resubscribing
+	useEffect(() => {
+		cbRef.current = callback;
+	}, [callback]);
+
+	useEffect(() => {
+		if (!enabled) return;
+		const normalized = key.toLowerCase();
 
 		const handleKeyDown = (e: KeyboardEvent) => {
-			if ((e.key === key || e.key === key.toUpperCase()) && !e.metaKey && !e.ctrlKey && !e.altKey && !e.repeat) {
-				const target = e.target as HTMLElement;
+			if (e.isComposing) return;
+			const pressed = (e.key || "").toLowerCase();
+			if (pressed === normalized && !e.metaKey && !e.ctrlKey && !e.altKey && !e.repeat) {
+				const target = e.target;
 				
-				if (
-					target.tagName === "INPUT" || 
-					target.tagName === "TEXTAREA" ||
-					target.isContentEditable ||
-					target.closest('[contenteditable="true"]')
-				) {
-					return;
-				}
+				if (target && target instanceof Element) {
+					const tag = (target as HTMLElement).tagName;
+					if (
+						tag === "INPUT" || 
+						tag === "TEXTAREA" ||
+						(target as HTMLElement).isContentEditable ||
+						target.closest('[contenteditable="true"]')
+					) {
+						return;
+					}
+				}
 				
 				e.preventDefault();
-				callback();
+				cbRef.current();
 			}
 		};
 
 		document.addEventListener("keydown", handleKeyDown);
 		return () => document.removeEventListener("keydown", handleKeyDown);
-	}, [key, callback, enabled]);
+	}, [key, enabled]);
 }

11-16: Consider broadening the “typing context” guard (optional).

If you expect rich editors that render as role="textbox" without contentEditable, or custom inputs (combobox, select), you could expand the guard to also skip [role="textbox"], SELECT, and elements with aria-haspopup="listbox". Not required for this PR, but it’ll make the hook safer to reuse across the app.

components/form/task.tsx (1)

21-21: Scope the shortcut to when the dialog is closed and use a stable callback.

Prevents redundant re-subscriptions and avoids firing “N” while the create dialog is already open.

-	useKeyboardShortcut("n", () => setIsCreating(true));
+	const openCreate = useCallback(() => setIsCreating(true), []);
+	useKeyboardShortcut("n", openCreate, !isCreating);
components/project/events/full-calendar.tsx (2)

80-81: Stabilize the callback (and optionally disable on mobile).

  • Using a memoized handler avoids listener churn.
  • If you prefer not to advertise/use keyboard shortcuts on small screens, you can gate with !isMobile (optional).

If both the calendar and the inline task form can be mounted together, pressing “N” will trigger both create flows. Confirm they don’t co-exist; if they do, gate one via the enabled flag based on active context/route.

-	useKeyboardShortcut("n", () => setCreate(true));
+	const openCreate = useCallback(() => setCreate(true), [setCreate]);
+	// If desired, disable on mobile keyboards:
+	useKeyboardShortcut("n", openCreate /*, !isMobile */);

237-243: Expose the shortcut to assistive technologies.

Add aria-keyshortcuts="N" to the New button so screen readers and ATs can announce the shortcut.

-					<Button
+					<Button
+						aria-keyshortcuts="N"
 						className="w-full gap-2 md:w-auto"
 						onClick={() => setCreate(true)}
 					>
 						<span>New</span>
 						<Kbd className="hidden md:inline-flex">N</Kbd>
📜 Review details

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

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 09712e3 and afbbc04.

📒 Files selected for processing (3)
  • components/form/task.tsx (2 hunks)
  • components/project/events/full-calendar.tsx (4 hunks)
  • hooks/use-keyboard-shortcut.ts (1 hunks)
🧰 Additional context used
🪛 Biome (2.1.2)
hooks/use-keyboard-shortcut.ts

[error] 3-3: This type annotation is trivially inferred from its initialization.

Safe fix: Remove the type annotation.

(lint/style/noInferrableTypes)

🔇 Additional comments (3)
hooks/use-keyboard-shortcut.ts (1)

3-27: Solid, reusable shortcut hook.

Clean lifecycle management and sensible default guards (meta/ctrl/alt/repeat and text-entry contexts). Good foundation for app-wide shortcuts.

components/form/task.tsx (1)

9-9: LGTM: Using the shared hook improves consistency and reduces duplication.

Moving to a common hook removes bespoke listeners and centralizes the input guards.

components/project/events/full-calendar.tsx (1)

5-6: Consistency and UX win.

Importing and displaying the Kbd “N” hint alongside wiring the shortcut via the shared hook is a nice, discoverable pattern.

Also applies to: 35-36, 242-243

@arjunkomath arjunkomath merged commit 0ccd7d8 into release Aug 22, 2025
3 of 4 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Aug 26, 2025
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.

2 participants