fix: a big ribbon button's label wraps onto two lines

Capped at 78px, so "Display for review" costs the group a column of width
instead of one of the widest buttons in the band. The caret moves up beside
the icon to free that second line, which lets the split button drop its
stacked layout and read as a row again.
This commit is contained in:
Steffen Becker committed 2026-09-04 19:30:03 +02:00
1 parent de71830922
commit 90a1a03fc6
3 files changed
+13 -37

No files matched your search

+1 -1
View File
@@ -100,7 +100,7 @@ at every height. A flex row cannot reserve width in part of its height, so it mo
| --- | --- |
| `Ribbon.svelte` | Shell, tab state, the File menu, which contextual tabs are shown |
| `RibbonGroup.svelte` | A group: its controls, its visible label, Word's ↘ dialog launcher |
| `RibbonButton.svelte` | `big` / `small` / `icon`, plus the split button. Hover paints the **icon box**, not the whole button |
| `RibbonButton.svelte` | `big` / `small` / `icon`, plus the split button. Hover paints the **icon box**, not the whole button. A big label wraps onto two lines at a 78px cap and its caret rides beside the icon, so a three-word label costs width instead of a third row |
| `RibbonMenu.svelte` | The dropdown panel; its look is global CSS, since its rows come from a caller's snippet |
| `Icon.svelte`, `icons.ts` | Path data on a 16-unit canvas. `pinnedStroke(size)` holds the painted stroke at ~1.5px on large glyphs and ~1.1px on small ones, so 14px and 28px icons read as one family |
| `menu.svelte.ts` | The one open-menu id, `anchored`, `pinPanels`, `clickOutside` |
+11 -32
View File
@@ -36,29 +36,23 @@
const ICON_SIZE = { big: 28, small: 14, icon: 20 } as const;
</script>
{#snippet face(withLabel = true)}
{#snippet face()}
<span class="rb-face">
{#if content}{@render content()}
{:else if icon}<Icon name={icon} size={ICON_SIZE[variant]} />{/if}
{#if caret && !onCaret && variant === 'icon'}
{#if caret && !onCaret && variant !== 'small'}
<Icon name="chevronDown" size={10} />
{/if}
</span>
{#if withLabel && label && variant !== 'icon'}<span class="rb-label">{label}</span>{/if}
{#if label && variant !== 'icon'}<span class="rb-label">{label}</span>{/if}
<!-- A row reads left to right, so its caret follows the label rather than the icon. -->
{#if caret && !onCaret && variant === 'small'}<Icon name="chevronDown" size={10} />{/if}
<!-- Held open on every big button, carrying a caret or nothing: the group centres
its controls, so one taller button lifts its own icon and label off the row. -->
{#if variant === 'big' && !onCaret}
<span class="rb-stack-caret">{#if caret}<Icon name="chevronDown" size={10} />{/if}</span>
{/if}
{/snippet}
{#if caret && onCaret}
{@const stacked = variant === 'big'}
<span class="rb-split" class:rb-split-col={stacked} class:rb-split-active={active || caretActive}>
<span class="rb-split" class:rb-split-active={active || caretActive}>
<button class="rb rb-{variant}" class:active {disabled} {title} {onclick}>
{@render face(!stacked)}
{@render face()}
</button>
<button
class="rb-caret"
@@ -69,7 +63,6 @@
aria-expanded={caretActive}
onclick={onCaret}
>
{#if stacked && label}<span class="rb-label">{label}</span>{/if}
<Icon name="chevronDown" size={10} />
</button>
</span>
@@ -163,12 +156,12 @@
color: inherit;
}
/* Rides closer to the label than the 4px column gap: the two read as one line. */
.rb-stack-caret {
display: flex;
height: 8px;
margin-top: -3px;
color: var(--w-text-dim);
/* 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. */
.rb-big .rb-label {
max-width: 78px;
white-space: normal;
text-align: center;
}
/* Split button: the two halves read as one control, so the hover outline sits on
@@ -194,20 +187,6 @@
cursor: pointer;
}
/* A big split button stacks, as in Word: the icon runs the command, the label
and the caret under it open the menu. Icon, label and caret each get their
own line — abreast, the caret widens the button by its own width. */
.rb-split-col { flex-direction: column; }
.rb-split-col .rb-big { padding: 2px 6px 0; }
.rb-split-col .rb-caret {
flex-direction: column;
width: auto;
padding: 0 6px 1px;
border-radius: 0 0 3px 3px;
color: var(--w-text);
}
.rb-caret:hover:not(:disabled) { background: var(--w-pressed); }
.rb-caret:disabled { opacity: 0.4; cursor: default; }
.rb-caret.active { background: var(--w-active); }
@@ -338,8 +338,7 @@
.rb-menu-wrap { position: relative; }
/* Wrapped onto two lines, as in Word — on one they are half the group's width.
`min-content` is what keeps the button off the label's unwrapped width, and
the caret slot goes because the two lines already reach the group's foot. */
`min-content` breaks at every space, tighter than the button's own cap. */
.inserts {
display: flex;
align-items: stretch;
@@ -355,8 +354,6 @@
line-height: 13px;
}
.inserts :global(.rb-stack-caret) { display: none; }
/* A big button wrapped in the trigger the popover hangs from; `anchored` drops
the popover below the whole band, like every other ribbon menu. */
.split-trigger {