feat(plugins): expose radius and padding on button nodes - #3355
Closed
gegnep wants to merge 1 commit into
Closed
Conversation
Button already inherits Flex's setRadius/setPadding; allowlist the props and apply them the same way the row/column branch does, so plugin chips can render as capsules without giving up click handling. Written with AI assistance (Claude Fable 5).
gegnep
force-pushed
the
plugin-button-shape
branch
from
July 12, 2026 02:58
c5c2737 to
452cc58
Compare
Contributor
Author
|
rebased onto main |
Collaborator
|
Thanks for the PR, but I'm gonna pass on this one, we wanna keep our button cohesive with proper padding, we already support different button "controlSize". The main issue here as per your screenshot: you are trying to use buttons to create pills and that's not the right control for the job. To achieve the look you want you can simply use ui.box + ui.row. ui.box supports onClick. |
18 tasks
gegnep
added a commit
to gegnep/noctalia
that referenced
this pull request
Jul 20, 2026
Plugin pills need a clickable, hoverable container with a text child: box supports onClick but is a leaf, and buttons are the wrong control for pill shapes (noctalia-dev#3355 review). Rows and columns already carry fill/ radius/padding, so let them take the same onClick/onHover props as box and image. Wrapped containers use a new ClickWrap InputArea that forwards measure/arrange to its single child: a plain InputArea never self-sizes, and the explicit size mirroring box/image rely on cannot work for a content-sized flex. Clickable wrappers also gain keyboard activation to keep parity with Button: focusable, and the Validate keybind fires onClick. The same activation applies to existing clickable box/image wrappers, which now use ClickWrap and enter the tab order. No visual focus state is drawn or exposed for containers yet. Wrapper input handlers deviate from the reconciler's retain-absent-props default: an empty callback name counts as unset, and removing onClick/onHover while the other callback keeps the wrapper alive clears the stale handler, button mask, and focusability — a retained one would leave an invisible node that swallows clicks and sits in tab order as a keyboard-activatable ghost. Container onHover fires only while the container itself is the innermost hovered input area — interactive descendants receive enter/leave instead, matching existing dispatcher behavior. Assisted with AI tooling.
ItsLemmy
added a commit
that referenced
this pull request
Jul 22, 2026
…3470) * feat(plugins): expose onHover callback on button, box, and image nodes Delivers pointer enter/leave to plugin UI trees as an onHover callback with a "true"/"false" argument, mirroring the toggle onChange convention. Buttons use their existing enter/leave hooks; box/image reuse the click wrapper, which now carries an empty button mask when hover-only so it never swallows clicks meant for ancestors. Assisted with AI tooling. * feat(plugins): expose onClick and onHover on row and column nodes Plugin pills need a clickable, hoverable container with a text child: box supports onClick but is a leaf, and buttons are the wrong control for pill shapes (#3355 review). Rows and columns already carry fill/ radius/padding, so let them take the same onClick/onHover props as box and image. Wrapped containers use a new ClickWrap InputArea that forwards measure/arrange to its single child: a plain InputArea never self-sizes, and the explicit size mirroring box/image rely on cannot work for a content-sized flex. Clickable wrappers also gain keyboard activation to keep parity with Button: focusable, and the Validate keybind fires onClick. The same activation applies to existing clickable box/image wrappers, which now use ClickWrap and enter the tab order. No visual focus state is drawn or exposed for containers yet. Wrapper input handlers deviate from the reconciler's retain-absent-props default: an empty callback name counts as unset, and removing onClick/onHover while the other callback keeps the wrapper alive clears the stale handler, button mask, and focusability — a retained one would leave an invisible node that swallows clicks and sits in tab order as a keyboard-activatable ghost. Container onHover fires only while the container itself is the innermost hovered input area — interactive descendants receive enter/leave instead, matching existing dispatcher behavior. Assisted with AI tooling. * fix(plugins): balance hover callbacks and dedupe wrapper callback wiring --------- Co-authored-by: Lemmy <studio@quadbyte.net>
bennypowers
pushed a commit
to bennypowers/noctalia-shell
that referenced
this pull request
Jul 22, 2026
…octalia-dev#3470) * feat(plugins): expose onHover callback on button, box, and image nodes Delivers pointer enter/leave to plugin UI trees as an onHover callback with a "true"/"false" argument, mirroring the toggle onChange convention. Buttons use their existing enter/leave hooks; box/image reuse the click wrapper, which now carries an empty button mask when hover-only so it never swallows clicks meant for ancestors. Assisted with AI tooling. * feat(plugins): expose onClick and onHover on row and column nodes Plugin pills need a clickable, hoverable container with a text child: box supports onClick but is a leaf, and buttons are the wrong control for pill shapes (noctalia-dev#3355 review). Rows and columns already carry fill/ radius/padding, so let them take the same onClick/onHover props as box and image. Wrapped containers use a new ClickWrap InputArea that forwards measure/arrange to its single child: a plain InputArea never self-sizes, and the explicit size mirroring box/image rely on cannot work for a content-sized flex. Clickable wrappers also gain keyboard activation to keep parity with Button: focusable, and the Validate keybind fires onClick. The same activation applies to existing clickable box/image wrappers, which now use ClickWrap and enter the tab order. No visual focus state is drawn or exposed for containers yet. Wrapper input handlers deviate from the reconciler's retain-absent-props default: an empty callback name counts as unset, and removing onClick/onHover while the other callback keeps the wrapper alive clears the stale handler, button mask, and focusability — a retained one would leave an invisible node that swallows clicks and sits in tab order as a keyboard-activatable ghost. Container onHover fires only while the container itself is the innermost hovered input area — interactive descendants receive enter/leave instead, matching existing dispatcher behavior. Assisted with AI tooling. * fix(plugins): balance hover callbacks and dedupe wrapper callback wiring --------- Co-authored-by: Lemmy <studio@quadbyte.net>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Exposes
radius,padding,paddingH, andpaddingVon declarativebuttonnodes in the plugin UI tree.Buttonalready inherits thesesetters from
Flex; this change adds the four keys to the button propallowlist and applies them mirroring the existing
row/columnhandling. Application happens after the compact-host chrome block, so
explicit props win over the bar-widget padding/min-height reset. No
behavior change for trees that do not pass the new props.
Motivation
Plugin bar widgets can't shape their buttons:
buttonis the onlyclickable text-bearing node, but its corner radius and padding are fixed
by the control's chrome. A widget that wants capsule chips visually
consistent with the built-in workspaces widget's pills (fully rounded,
active pill wider via a larger horizontal inset) has no way to express
that — the workaround is padding the label with literal spaces. With
this change a plugin passes
radius/paddingHper node with the samesemantics and scaling as the flex containers.
Type of Change
Testing
main@ 3137323), full shell run.chips (
height+radius), wider active chip viapaddingH, propsre-applied correctly across re-renders, and confirmed the compact-host
ordering: explicit padding survives the bar-widget chrome reset.
just format(clang-format 22) — no diff.Manual Coverage
Screenshots / Videos
before
after
Checklist
CONTRIBUTING.md.just formatwith clang-format v22+ installed, or this PR has no code changes.assets/translations/en.json, or this PR adds no new user-facing strings.Additional Notes
Prop names and application semantics are copied verbatim from the
row/columnbranch (paddingfallback forpaddingV/paddingH,values through
scaled()) — one consistent vocabulary across nodetypes. Docs follow-up after merge: add the props to the declarative-UI
button section.
Disclaimer: AI-assisted tooling was used.