Skip to content

combine: add Menu action variant to buttons - #64

Merged
RCmerci merged 3 commits into
mainfrom
devin/1790500578-buttons-menu-action
Sep 27, 2026
Merged

RCmerci merged 3 commits into
mainfrom
devin/1790500578-buttons-menu-action

Conversation

@RCmerci

@RCmerci RCmerci commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Lui_element_combine.buttons actions are now polymorphic: Press (existing behavior) or Menu (press-to-open native dropdown). This is a breaking change to the young action record — callers wrap their record in Press (gallery and tests updated here; the journal V.buttons wrapper gets a matching wrap in its own PR).

type action =
  | Press of { label : string; icon : icon; text : string option; on_press : Lui_protocol.event -> unit }
  | Menu of { label : string; icon : icon; text : string option; menu : t list; on_dismiss : (Lui_protocol.event -> unit) option }

A Menu action mounts a menu_trigger + dropdown_menu inside a sizing cell (box ~height:44, icon-only → ~width:44) rather than in a bare button_group slot. MenuTrigger carries no surface properties in the wire protocol, so the capsule chrome (glass background, 999 corner radius) lives on the wrapping cell — no wire whitelist or schema changes needed; style-class was already supported on MenuTrigger.

Hit area: the trigger gets style_class:"capsule", which LUIMenuTriggerView uses to stretch its label to the full cell frame with .contentShape(Rectangle()) (same pattern as the PR #56 toolbar hit fix): icon-only cells greedy-fill the pinned 44×44 frame; text cells greedy-fill height and take 12pt horizontal padding inside the hit region.

buttons semantics unchanged: [] → invalid_arg; a single action (press or menu) gets its own glass capsule; multiple share a button_group capsule.

Gallery ("Glass Buttons" section) demos a standalone icon-only menu action and a fused press+menu capsule.

Caveat

Inside a hoisted toolbar capsule segment (ControlGroup), a Menu action renders a native Menu — it stays tappable but does not get the fused ControlGroup styling that Button members get. Acceptable for now since buttons isn't used there yet.

Verification

  • dune build + dune runtest: 29 tests pass, incl. new menu action test (single capsule → MenuTrigger → DropdownMenu → MenuItem; menu-item press dispatches its handler; group has Button + Box cells).
  • swift build --package-path platform/apple: clean.
  • iOS simulator evidence on the LUI gallery app: recorded separately in the session (menu opens on capsule tap incl. off-glyph area, item press fires handler, fused mixed capsule).

Link to Devin session: https://app.devin.ai/sessions/3bce435625ba4bc086c09520e0920db5
Open in Devin Desktop: https://app.devin.ai/desktop/session/3bce435625ba4bc086c09520e0920db5?variant=devin
Requested by: @RCmerci

A buttons action can now be a press-to-open native dropdown menu
(menu_trigger + dropdown_menu child) alongside plain press buttons.
The trigger rides in a sizing cell so the glass capsule chrome and
hit area match the sibling press capsules; a 'capsule' style class
tells the Apple backend to stretch the Menu label's frame and
contentShape across the cell.
@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration

Copy link
Copy Markdown
Contributor

iOS simulator verification — Menu action in Lui_element_combine.buttons ✅

Verified on iPhone 17 sim (iOS 27.0) in the LUIComponents gallery "Glass Buttons" section, driving real taps on the Simulator window with simctl io screenshots as pixel evidence.

Section overview — capsules render with glass parity
Native menu open on the standalone ellipsis capsule

  • Standalone icon-only menu capsule → native dropdown opens with Duplicate/Rename/Archive; "Rename" → trailing paragraph shows "Context action: Rename"
  • Off-glyph tap inside capsule bounds still opens the menu (capsule contentShape hit region works)
  • Mixed press+menu capsule renders fused; ellipsis half opens the menu ("Duplicate" → "Context action: Duplicate"), plus half fires press ("Context action: New note")

Full annotated recording: /Users/devin/screencasts/rec-2c51cc96-1476-4132-9711-3d1540bc23de/rec-2c51cc96-1476-4132-9711-3d1540bc23de-edited.mp4

The menu trigger's sizing cell is a box, which is not a legal toolbar
child — wrapping it in a button_group keeps lone menu capsules mountable
inside toolbars like the press capsules.
@devin-ai-integration

Copy link
Copy Markdown
Contributor

Icon-size fix (83bcb3a) verified on iOS sim ✅

LUIMenuTriggerView's LUIIconImage is .resizable() — unlike every other call site it had no frame constraint, so the glyph expanded to fill the 44pt capsule cell. Now constrained to LUIButtonVisualPolicy.iconExtent (~18pt), matching sibling buttons:

Gallery capsules — ellipsis matches +/gear/info size
Journal account capsule — person icon normal size

  • Gallery: standalone "…" capsule and mixed "+"+"…" capsule both show matching icon extents; menu still opens and "Rename" fires → "Context action: Rename"
  • Journal: account capsule person icon normal size next to info capsule; menu opens with all 5 items

@RCmerci
RCmerci merged commit df9fddb into main Sep 27, 2026
4 checks passed
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