Skip to content

Conversation

@kaifcoder
Copy link

@kaifcoder kaifcoder commented Sep 9, 2025

Summarize the changes made and the motivation behind them.
Addressed issue number #1617
Reference related issues using # followed by the issue number.

If there are breaking API changes - like adding or removing props, or changing the structure of the theme - describe them, and provide steps to update existing code.

Summary by CodeRabbit

  • New Features

    • Dropdown gains an onToggle callback to notify when the menu opens or closes, with consistent notifications for programmatic opens, user toggles, and item selection.
  • Documentation

    • Added a Storybook example ("onToggle handlers") demonstrating the onToggle behavior with multiple items and action logging.

✏️ Tip: You can customize this high-level summary in your review settings.

@changeset-bot
Copy link

changeset-bot bot commented Sep 9, 2025

⚠️ No Changeset found

Latest commit: d2417c9

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Sep 9, 2025

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

Project Deployment Preview Comments Updated (UTC)
flowbite-react Ready Ready Preview Comment Dec 9, 2025 4:06pm
flowbite-react-storybook Ready Ready Preview Comment Dec 9, 2025 4:06pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 9, 2025

Walkthrough

Adds an onToggle?: (open: boolean) => void prop to Dropdown and centralizes open/close updates via handleOpenChange so all open-state changes (trigger, selection, programmatic) notify onToggle. Adds a Storybook story onToggleHandler demonstrating the callback.

Changes

Cohort / File(s) Summary
Dropdown component logic and API
packages/ui/src/components/Dropdown/Dropdown.tsx
Adds onToggle?: (open: boolean) => void to DropdownProps; updates props typing to omit "onToggle" from inherited ButtonProps; introduces handleOpenChange and routes all open/close updates (including selection and setOpen from floating logic) through it to invoke onToggle.
Storybook demo for onToggle
apps/storybook/src/Dropdown.stories.tsx
Adds export const onToggleHandler = Template.bind({}); story named "onToggle handlers" that passes an onToggle action and renders items with individual onClick actions.

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant Dropdown
  participant Floating as useBaseFloating
  participant Consumer as onToggle(callback)

  rect rgb(240,248,255)
  note right of Dropdown: User opens dropdown
  User->>Dropdown: Click trigger
  Dropdown->>Floating: setOpen(true)
  Floating-->>Dropdown: open=true
  Dropdown->>Dropdown: handleOpenChange(true)
  Dropdown-->>Consumer: onToggle(true)
  end

  rect rgb(245,245,245)
  note right of Dropdown: User selects an item (closes)
  User->>Dropdown: Select item
  Dropdown->>Dropdown: handleOpenChange(false)
  Dropdown->>Floating: setOpen(false)
  Dropdown-->>Consumer: onToggle(false)
  end

  rect rgb(250,240,230)
  note right of Dropdown: Programmatic open/close
  Floating-->>Dropdown: open state change
  Dropdown->>Dropdown: handleOpenChange(open)
  Dropdown-->>Consumer: onToggle(open)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review focus: handleOpenChange correctness, ensuring all setOpen/selection paths call it; prop-type change (omitting "onToggle" from ButtonProps) and Storybook story wiring.

Poem

I twitch my ears at toggles’ tune,
A dropdown blooms, then sleeps so soon.
Click—awake! Select—goodnight.
onToggle whispers left and right.
In stories bright, I hop with glee—
State flips once, then returns to me.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding an onToggle prop to the Dropdown component and updating related handlers.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 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 61afc97 and 89358a9.

📒 Files selected for processing (2)
  • apps/storybook/src/Dropdown.stories.tsx (1 hunks)
  • packages/ui/src/components/Dropdown/Dropdown.tsx (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/storybook/src/Dropdown.stories.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
packages/ui/src/components/Dropdown/Dropdown.tsx (2)
packages/ui/src/components/Button/Button.tsx (1)
  • ButtonProps (48-59)
packages/ui/src/types/index.ts (1)
  • ThemingProps (20-46)
🔇 Additional comments (4)
packages/ui/src/components/Dropdown/Dropdown.tsx (4)

46-59: LGTM! Clean API design.

The type changes correctly prevent prop conflicts by omitting "onToggle" from ButtonProps, and the new onToggle callback follows React conventions with a clear signature.


148-154: Excellent centralization of open state changes.

The handleOpenChange function correctly:

  • Updates local state via setOpen
  • Notifies the parent via onToggle
  • Uses useCallback to avoid unnecessary recreations

This ensures all open/close operations consistently trigger the callback.


156-162: Correct routing of selection close events.

By calling handleOpenChange(false) instead of setOpen(false), item selections now properly trigger the onToggle callback. The dependency array correctly includes handleOpenChange.


175-182: Proper integration with Floating UI.

The custom setOpen callback ensures that all programmatic open state changes (including those from Floating UI interactions) route through handleOpenChange. The function form handling on line 178 correctly supports React's functional update pattern.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (7)
packages/ui/src/components/Dropdown/Dropdown.tsx (6)

48-49: Don’t Omit a non-existent key from ButtonProps

onToggle isn’t a member of ButtonProps, so including it in the Omit adds noise. Keeping the Omit minimal improves clarity.

-  extends Pick<FloatingProps, "placement" | "trigger">,
-    Omit<ButtonProps, keyof ThemingProps<DropdownTheme> | "onToggle">,
+  extends Pick<FloatingProps, "placement" | "trigger">,
+    Omit<ButtonProps, keyof ThemingProps<DropdownTheme>>,

57-57: Add concise TSDoc to define onToggle semantics

Document when onToggle fires (only on state changes vs. every call). This avoids consumer confusion.

-  onToggle?: (open: boolean) => void;
+  /**
+   * Called when the open state changes due to user interaction or programmatic updates.
+   * Receives the next `open` value.
+   */
+  onToggle?: (open: boolean) => void;

148-155: Fire onToggle only when state actually changes

Currently onToggle is invoked even if newOpen equals the current state, causing redundant callbacks (extra Storybook actions, potential double logs in StrictMode). Guard and include open in deps.

-  const handleOpenChange = useCallback(
-    (newOpen: boolean) => {
-      setOpen(newOpen);
-      onToggle?.(newOpen);
-    },
-    [onToggle],
-  );
+  const handleOpenChange = useCallback(
+    (newOpen: boolean) => {
+      if (newOpen === open) return;
+      setOpen(newOpen);
+      onToggle?.(newOpen);
+    },
+    [open, onToggle],
+  );

156-162: Avoid closing (and notifying) when already closed

When typeahead selects while closed, handleSelect calls handleOpenChange(false), which triggers onToggle(false) unnecessarily. Close only if open.

-  const handleSelect = useCallback(
-    (index: number | null) => {
-      setSelectedIndex(index);
-      handleOpenChange(false);
-    },
-    [handleOpenChange],
-  );
+  const handleSelect = useCallback(
+    (index: number | null) => {
+      setSelectedIndex(index);
+      if (open) handleOpenChange(false);
+    },
+    [open, handleOpenChange],
+  );

177-181: Minor: stabilize the setOpen bridge to avoid new function per render

Not critical, but passing a stable callback reduces churn if useBaseFLoating tracks handler identity.

-  const { context, floatingStyles, refs } = useBaseFLoating<HTMLButtonElement>({
-    open,
-    setOpen: (value) => {
-      const newOpen = typeof value === "function" ? value(open) : value;
-      handleOpenChange(newOpen);
-    },
-    placement,
-  });
+  const setOpenWithNotify = useCallback(
+    (value: SetStateAction<boolean>) => {
+      const next = typeof value === "function" ? (value as (prev: boolean) => boolean)(open) : value;
+      handleOpenChange(next);
+    },
+    [open, handleOpenChange],
+  );
+
+  const { context, floatingStyles, refs } = useBaseFLoating<HTMLButtonElement>({
+    open,
+    setOpen: setOpenWithNotify,
+    placement,
+  });

46-59: API addition: ensure docs and migration notes are updated

This is a new public prop. Please add it to the component docs (Props table), mention behavior in “Events”, and note in the PR description whether it’s a breaking change (it isn’t) and any migration hints.

I can open a docs PR. If helpful, I’ll also add a brief “onToggle” example mirroring the Storybook story.

apps/storybook/src/Dropdown.stories.tsx (1)

133-146: Nice addition; covers the new callback

Story cleanly demonstrates onToggle. Consider capitalizing the story name for consistency with others (“OnToggle handlers”) and optionally adding a quick note in the story description about firing on open/close.

-onToggleHandler.storyName = "onToggle handlers";
+onToggleHandler.storyName = "OnToggle handlers";
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 51621a1 and 61afc97.

📒 Files selected for processing (2)
  • apps/storybook/src/Dropdown.stories.tsx (1 hunks)
  • packages/ui/src/components/Dropdown/Dropdown.tsx (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/ui/src/components/Dropdown/Dropdown.tsx (2)
packages/ui/src/components/Button/Button.tsx (1)
  • ButtonProps (48-59)
packages/ui/src/types/index.ts (1)
  • ThemingProps (20-46)

Copilot AI review requested due to automatic review settings December 9, 2025 16:01
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@vercel
Copy link

vercel bot commented Dec 9, 2025

@SutuSebastian is attempting to deploy a commit to the Themesberg Team on Vercel.

A member of the Team first needs to authorize it.

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