From 22626b02a5d5f52210a989a9279481fb6c1c24b8 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Mon, 4 May 2026 10:22:23 -0300 Subject: [PATCH 1/3] fix(button): centre icons via flex gap instead of margin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ` ) }, From 7784a90be75244c48e520d9fa17c5114ade47e65 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Wed, 6 May 2026 09:02:18 -0300 Subject: [PATCH 2/3] fix(button): only wrap content in flex span when iconLeft/iconRight is used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous fix wrapped the button content in a flex span unconditionally to centre icon-only buttons (theme='icon' iconLeft='copy'). That changed inner layout from inline (driven by line-height) to flex (driven by child dimensions), shrinking buttons that pass the icon as children directly — the .btn-with-icon trash/edit affordances used in table rows came out a few pixels shorter than on main. Make the wrapper conditional: only kicks in when the iconLeft or iconRight props are present (the case the original fix targeted). Children-only consumers render as before. Adds an IconAsChildren story covering the .btn-with-icon pattern so this class of regression is snapshotted next time. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../components/Button.stories.tsx | 25 ++++++++++++ frontend/web/components/base/forms/Button.tsx | 40 +++++++++++-------- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/frontend/documentation/components/Button.stories.tsx b/frontend/documentation/components/Button.stories.tsx index d7be200780d3..4b4423209b82 100644 --- a/frontend/documentation/components/Button.stories.tsx +++ b/frontend/documentation/components/Button.stories.tsx @@ -7,6 +7,7 @@ import { sizeClassNames, } from 'components/base/forms/Button' import type { ButtonType } from 'components/base/forms/Button' +import Icon from 'components/icons/Icon' const themeOptions = Object.keys(themeClassNames) as Array< keyof typeof themeClassNames @@ -81,6 +82,30 @@ export const Variants: Story = { ), } +export const IconAsChildren: Story = { + parameters: { + docs: { + description: { + story: + 'Pattern used by `btn-with-icon` consumers (e.g. table-row delete affordances): the icon is passed as `children`, not via the `iconLeft`/`iconRight` props. Layout must match the iconLeft/iconRight rendering for visual consistency. Snapshotted to catch wrapper-introduced height/width drift.', + }, + }, + }, + render: () => ( +
+ + + +
+ ), +} + export const Sizes: Story = { parameters: { docs: { diff --git a/frontend/web/components/base/forms/Button.tsx b/frontend/web/components/base/forms/Button.tsx index 4d5d9f013260..8170218d01b9 100644 --- a/frontend/web/components/base/forms/Button.tsx +++ b/frontend/web/components/base/forms/Button.tsx @@ -106,23 +106,29 @@ export const Button = React.forwardRef< )} ref={ref as React.RefObject} > - - {!!iconLeft && ( - - )} - {children} - {!!iconRight && ( - - )} - + {iconLeft || iconRight ? ( + + {!!iconLeft && ( + + )} + {children} + {!!iconRight && ( + + )} + + ) : ( + children + )} ) }, From e4b242d6331e338be3844ba17aa7ed2e99711867 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Wed, 6 May 2026 09:10:52 -0300 Subject: [PATCH 3/3] docs(button): add IconAndLabel and AsAnchor stories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes the two coverage gaps that let #7402's children-rendering regression slip through Chromatic: - **IconAndLabel** — dedicated snapshot for `iconLeft`/`iconRight` paired with a text label. The most common real-world icon-button shape, but previously only visible inside the Themes story where spacing regressions on the icon-label gap would drown in the wider diff. - **AsAnchor** — covers the `
` rendering branch (`href` prop). Button has two render paths; before this story, every snapshot exercised only the ` + + + + ), +} + +export const AsAnchor: Story = { + parameters: { + docs: { + description: { + story: + "Button renders as an `` element when `href` is set — a separate code path from the ` + + + + ), +} + export const Sizes: Story = { parameters: { docs: {