Skip to content

feat(menu): enable keeping the menu open after selection#4004

Merged
Kiarokh merged 1 commit intomainfrom
menu-keep-open
Apr 14, 2026
Merged

feat(menu): enable keeping the menu open after selection#4004
Kiarokh merged 1 commit intomainfrom
menu-keep-open

Conversation

@Kiarokh
Copy link
Copy Markdown
Contributor

@Kiarokh Kiarokh commented Apr 7, 2026

fix https://github.com/Lundalogik/crm-client/issues/864

Summary by CodeRabbit

  • New Features

    • Menus can stay open after selecting items to enable fluid multi-selection workflows with continued searching, preserved search terms, and keyboard hotkeys for quick actions (including an "Apply all" option).
  • Documentation

    • Added an example demonstrating persistent menu behavior with live filtering, hotkey support, and a visible list of applied filters.

Review:

  • Commits are atomic
  • Commits have the correct type for the changes made
  • Commits with breaking changes are marked as such

Browsers tested:

(Check any that applies, it's ok to leave boxes unchecked if testing something didn't seem relevant.)

Windows:

  • Chrome
  • Edge
  • Firefox

Linux:

  • Chrome
  • Firefox

macOS:

  • Chrome
  • Firefox
  • Safari

Mobile:

  • Chrome on Android
  • iOS

@Kiarokh Kiarokh requested a review from a team as a code owner April 7, 2026 15:16
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 7, 2026

Warning

Rate limit exceeded

@Kiarokh has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 22 minutes and 36 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 22 minutes and 36 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: efe8d78d-0e31-4744-9fd3-ccc30d26c839

📥 Commits

Reviewing files that changed from the base of the PR and between 7ac69e4 and 3632d84.

⛔ Files ignored due to path filters (1)
  • etc/lime-elements.api.md is excluded by !etc/lime-elements.api.md
📒 Files selected for processing (2)
  • src/components/menu/examples/menu-keep-open.tsx
  • src/components/menu/menu.tsx
📝 Walkthrough

Walkthrough

Adds a new boolean prop keepOpenOnSelect to the menu component to optionally keep the menu open after leaf selection and re-run the configured async searcher; introduces a new example component demonstrating keep-open behavior, async searching, hotkeys, and an “Apply all” action.

Changes

Cohort / File(s) Summary
Menu component enhancement
src/components/menu/menu.tsx
Added public @Prop({ reflect: true }) keepOpenOnSelect: boolean = false; added private async refreshSearch() to re-run the searcher, set loadingSubItems, update searchResults, and preserve focus; modified handleSelect to, when keepOpenOnSelect is true and search is active, call refreshSearch() and avoid closing the menu / clearing submenu / restoring focus.
Example component
src/components/menu/examples/menu-keep-open.tsx
New Stencil example component limel-example-menu-keep-open demonstrating keepOpenOnSelect={true}: maintains appliedFilters, implements async searcher that filters ALL_PROPERTIES, returns MenuItems preserving searchTerm, assigns hotkeys (first result and “Apply all”), and handles single or “Apply all” selections.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant User
participant Example as Example Component
participant Menu as Menu Component
participant Searcher
User->>Example: open menu / type query
Example->>Menu: render with searcher, keepOpenOnSelect=true
Menu->>Searcher: call(searchTerm)
Searcher-->>Menu: results (with hotkeys / "Apply all")
User->>Menu: select item
Menu->>Menu: emit select
alt keepOpenOnSelect && searchTerm non-empty && has searcher
Menu->>Menu: refreshSearch() (loadingSubItems=true)
Menu->>Searcher: call(current searchTerm)
Searcher-->>Menu: updated results
Menu->>Example: selection handled (appliedFilters updated) — menu remains open
else
Menu->>Menu: close menu, clear submenu, restore focus
end

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • adrianschmidt
  • omaralweli
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main feature: enabling the menu to stay open after selection, which is the core change across both the menu component and the example.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch menu-keep-open

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.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 7, 2026

Documentation has been published to https://lundalogik.github.io/lime-elements/versions/PR-4004/

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/menu/examples/menu-keep-open.tsx`:
- Around line 161-164: The code pushes selectedItem.value.propertyName (typed
string | undefined) into appliedFilters (string[]), causing a type-safety
mismatch; update the logic around appliedFilters (where you modify
this.appliedFilters) to ensure propertyName is narrowed or guarded before
adding: check selectedItem.value.propertyName is a string (e.g., if
(selectedItem.value.propertyName) ...) or assert its presence when applyAll is
false (use a non-null assertion only if certain from handleSearch), so that
appliedFilters only ever receives a string; reference the variables
appliedFilters, selectedItem.value.propertyName, applyAll, and handleSearch when
making the change.

In `@src/components/menu/menu.tsx`:
- Around line 192-196: Update the JSDoc for the public property keepOpenOnSelect
to state that the menu only remains open after selection when a searcher is
configured and the current searchValue is non-empty; reference the component's
searcher and searchValue behavior so readers know that without a searcher or
when searchValue is empty the menu will close normally.
- Around line 781-793: The refreshSearch method can leave loadingSubItems true
if this.searcher(query) throws; wrap the await this.searcher(query) call in a
try/catch/finally so errors are caught, loadingSubItems is set back to false in
the finally block, and any error is logged or handled in the catch; ensure you
still check this.searchValue !== query before assigning this.searchResults or
calling this.setFocus so cancelled searches don't overwrite state. Use the
existing symbols refreshSearch, this.searcher, loadingSubItems, searchValue,
searchResults, and setFocus to implement the fix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: cb89ff82-9aaa-4b6e-b079-c53b3a16711c

📥 Commits

Reviewing files that changed from the base of the PR and between 2cc095c and afb9aea.

⛔ Files ignored due to path filters (1)
  • etc/lime-elements.api.md is excluded by !etc/lime-elements.api.md
📒 Files selected for processing (2)
  • src/components/menu/examples/menu-keep-open.tsx
  • src/components/menu/menu.tsx

Comment thread src/components/menu/examples/menu-keep-open.tsx Outdated
Comment thread src/components/menu/menu.tsx
Comment thread src/components/menu/menu.tsx
@Kiarokh Kiarokh enabled auto-merge (rebase) April 8, 2026 07:16
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/menu/examples/menu-keep-open.tsx`:
- Around line 8-10: The current isApple detection relies on
navigator.userAgentData?.platform with a fallback to deprecated
navigator.platform; update the detection to be more robust by preferring
navigator.userAgentData?.platform, then falling back to navigator.userAgent
(inspect the userAgent string for Mac/iPhone/iPad/iPod), and only use
navigator.platform as the final fallback; update the const isApple declaration
so it checks these sources in that order (refer to the existing isApple constant
and its userAgent/userAgentData/platform references).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f44ae042-9362-4181-bb5d-56cb1250dea9

📥 Commits

Reviewing files that changed from the base of the PR and between afb9aea and 83d7b7e.

⛔ Files ignored due to path filters (1)
  • etc/lime-elements.api.md is excluded by !etc/lime-elements.api.md
📒 Files selected for processing (2)
  • src/components/menu/examples/menu-keep-open.tsx
  • src/components/menu/menu.tsx

Comment thread src/components/menu/examples/menu-keep-open.tsx
Copy link
Copy Markdown
Contributor

@adrianschmidt adrianschmidt left a comment

Choose a reason for hiding this comment

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

External API approved.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (2)
src/components/menu/menu.tsx (2)

781-793: 🧹 Nitpick | 🔵 Trivial

Consider adding error handling for resilience.

If this.searcher(query) throws, loadingSubItems remains true, leaving the menu in a permanent loading state. While this mirrors the existing handleTextInput behavior (lines 626-630), adding try/finally would improve robustness.

🛡️ Optional: Add error handling
 private readonly refreshSearch = async () => {
     const query = this.searchValue;
     this.loadingSubItems = true;

+    try {
         const result = await this.searcher(query);
         if (this.searchValue !== query) {
             return;
         }

         this.searchResults = result;
+    } finally {
         this.loadingSubItems = false;
+    }
     this.setFocus();
 };

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/menu/menu.tsx` around lines 781 - 793, The refreshSearch
method can leave loadingSubItems true if this.searcher(query) throws; wrap the
await this.searcher(query) call in a try/finally so loadingSubItems is always
set to false, and keep the existing stale-query check (this.searchValue !==
query) and the setFocus() call only after the finally block (or inside it after
confirming the query is still current). Also optionally catch/log the error from
this.searcher to avoid unhandled rejections. Ensure you modify the refreshSearch
function (referenced by name) and mirror the defensive pattern used in
handleTextInput for consistency.

192-196: 🧹 Nitpick | 🔵 Trivial

Documentation should clarify the searcher requirement.

The JSDoc says the menu stays open after selection, but reviewing lines 938-944 reveals this only applies when a searcher is provided AND searchValue is non-empty. Without these conditions, the menu closes normally.

📝 Suggested documentation improvement
 /**
- * When `true`, the menu stays open after an item is selected.
+ * When `true`, the menu stays open after an item is selected,
+ * provided that a `searcher` is configured and the search field
+ * contains a query. In this case, the search is re-executed so
+ * the result list can be updated (e.g. to exclude the selected item).
  */
 `@Prop`({ reflect: true })
 public keepOpenOnSelect = false;

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/menu/menu.tsx` around lines 192 - 196, Update the JSDoc for
the keepOpenOnSelect Prop to reflect the actual behavior: state that it only
keeps the menu open after selection when a searcher is configured and the
component's searchValue is non-empty (otherwise the menu closes normally);
reference the keepOpenOnSelect property and the searcher and searchValue
conditions to make the requirement explicit.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/components/menu/menu.tsx`:
- Around line 781-793: The refreshSearch method can leave loadingSubItems true
if this.searcher(query) throws; wrap the await this.searcher(query) call in a
try/finally so loadingSubItems is always set to false, and keep the existing
stale-query check (this.searchValue !== query) and the setFocus() call only
after the finally block (or inside it after confirming the query is still
current). Also optionally catch/log the error from this.searcher to avoid
unhandled rejections. Ensure you modify the refreshSearch function (referenced
by name) and mirror the defensive pattern used in handleTextInput for
consistency.
- Around line 192-196: Update the JSDoc for the keepOpenOnSelect Prop to reflect
the actual behavior: state that it only keeps the menu open after selection when
a searcher is configured and the component's searchValue is non-empty (otherwise
the menu closes normally); reference the keepOpenOnSelect property and the
searcher and searchValue conditions to make the requirement explicit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 48c4857b-b9cb-415e-a925-9e817d51f1fe

📥 Commits

Reviewing files that changed from the base of the PR and between 83d7b7e and 7ac69e4.

⛔ Files ignored due to path filters (1)
  • etc/lime-elements.api.md is excluded by !etc/lime-elements.api.md
📒 Files selected for processing (2)
  • src/components/menu/examples/menu-keep-open.tsx
  • src/components/menu/menu.tsx

@Kiarokh Kiarokh merged commit 5564114 into main Apr 14, 2026
11 of 18 checks passed
@Kiarokh Kiarokh deleted the menu-keep-open branch April 14, 2026 13:18
@lime-opensource
Copy link
Copy Markdown
Collaborator

🎉 This PR is included in version 39.13.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants