From fb400798d19c1597cebce459728c7bd225a7f9f9 Mon Sep 17 00:00:00 2001 From: Steffen Becker Date: Wed, 2 Sep 2026 15:55:53 +0000 Subject: [PATCH] fix: a ribbon button is no wider than its label's longest line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A wrapped label kept the full 78px it was allowed to wrap at, so the two-word labels of Review and References made every button there 90px wide against 40–70px elsewhere. One- and two-word labels now hug their longest line — a longer one keeps the cap, or it would break into a third line and run out of the band. The split button's arrow follows the narrower label instead of overlapping it, so each half tints only its own surface. --- src/lib/components/ribbon/RibbonButton.svelte | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/lib/components/ribbon/RibbonButton.svelte b/src/lib/components/ribbon/RibbonButton.svelte index 65bd930..5b6b473 100644 --- a/src/lib/components/ribbon/RibbonButton.svelte +++ b/src/lib/components/ribbon/RibbonButton.svelte @@ -37,6 +37,10 @@ } = $props(); const ICON_SIZE = { big: 28, small: 14, icon: 20 } as const; + + // One or two words wrap into the same two lines whether the box is the full cap or + // just its longest word, so those hug it — a longer label keeps the cap to wrap at. + const hug = $derived(!!label && label.trim().split(/\s+/).length <= 2); {#snippet face()} @@ -47,7 +51,7 @@ {/if} - {#if label && variant !== 'icon'}{label}{/if} + {#if label && variant !== 'icon'}{label}{/if} {#if caret && !onCaret && variant === 'small'}{/if} {/snippet} @@ -160,13 +164,17 @@ } /* The cap is what makes the wrap happen: unwrapped, a three-word label is twice - the width of the icon above it. Two lines fit the band, a third is clipped. */ + the width of the icon above it. Two lines fit the band, a third is clipped. + A hugging label drops the width it wrapped at, or it would push its neighbours a + word's width apart. */ .rb-big .rb-label { max-width: 78px; white-space: normal; text-align: center; } + .rb-big .rb-label.hug { width: min-content; } + /* Split button: the two halves read as one control, so the hover outline sits on the wrapper and each half only tints its own surface. */ .rb-split { @@ -207,9 +215,9 @@ .caret-primary .rb-caret { width: 16px; color: var(--w-text); } .caret-primary .rb-caret :global(svg) { transform: scale(1.15); } - /* That command half gives up its right padding, so the arrow sits against the label - rather than at the far edge of a button the label does not fill. */ - .caret-primary .rb-big { padding-right: 0; } + /* That command half keeps only a hair of right padding, so the arrow sits against + the label rather than at the far edge of a button the label does not fill. */ + .caret-primary .rb-big { padding-right: 4px; } .caret-primary .rb-big .rb-face { margin-right: 0; } .rb-caret:hover:not(:disabled) { background: var(--w-pressed); }