Make the formula bar mouse-resizable and wrapping

Switches the formula bar from a single-line <input> to a <textarea>:

- A plain <textarea> gets a free, native mouse-draggable resize handle in
  its bottom-right corner (CSS resize: vertical) -- exactly the "erweiterbar/
  erhöhbar mit der Maus" ask, no custom drag code needed.
- Unlike the old <input>, it actually wraps a long formula instead of just
  scrolling it sideways, so dragging the handle taller has something to
  show (min-height keeps the collapsed case looking like before; max-height
  caps it at half the viewport).
- Brought its keyboard handling in line with the in-cell editor from the
  last two changes: Alt+Enter/Cmd+Enter insert a literal newline, F4 cycles
  every reference a selection overlaps, Escape reverts and blurs.
- .formula-bar switches to align-items: flex-start (with matching top
  margins on the labels) so the cell-name/fx labels stay pinned to the
  first line instead of vertically centering in a now-tall box.

Verified interactively: dragging the handle down 80px grows the bar from
~34px to ~113px; Alt+Enter inserts a real newline in the (now multi-line-
capable) field.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
wkh
2026-09-02 11:11:01 +02:00
co-authored by Claude Sonnet 5
parent 8c9f3bbc87
commit 67b011637d
2 changed files with 49 additions and 8 deletions
+6
View File
@@ -112,6 +112,12 @@ Ein Zeilenumbruch bleibt auch nach dem Committen erhalten und wird in der
Zelle als solcher dargestellt (umbrechend statt einzeiliger Ellipse), auf die Zelle als solcher dargestellt (umbrechend statt einzeiliger Ellipse), auf die
Zeilenhöhe der Tabelle geklemmt. Zeilenhöhe der Tabelle geklemmt.
**Formelleiste** (`fx`, oben): ein `<textarea>` statt eines einzeiligen Felds
— dadurch **umbricht** eine lange Formel statt seitwärts wegzuscrollen, und
an der unteren Kante lässt sie sich per **Maus** (natives `resize: vertical`)
auf beliebig viele Zeilen aufziehen, um mehr auf einmal zu sehen. `Alt`+`Enter`
bzw. `Cmd`+`Enter`, `F4` und `Esc` verhalten sich wie im In-Zellen-Editor.
### Zell-Formatierung ### Zell-Formatierung
Auswahl (Zelle, Bereich, Mehrfachauswahl, ganze Zeile/Spalte über den Kopf) → im Auswahl (Zelle, Bereich, Mehrfachauswahl, ganze Zeile/Spalte über den Kopf) → im
+43 -8
View File
@@ -35,8 +35,7 @@ function onEscape() {
/** F4: cycle relative -> absolute -> row-locked -> col-locked (Excel/Numbers /** F4: cycle relative -> absolute -> row-locked -> col-locked (Excel/Numbers
* "Bezug sperren") -- for the reference at the caret, or every reference a * "Bezug sperren") -- for the reference at the caret, or every reference a
* real text selection overlaps at once. */ * real text selection overlaps at once. */
function onF4(e: KeyboardEvent) { function onF4(el: HTMLTextAreaElement) {
const el = e.target as HTMLInputElement;
const start = el.selectionStart ?? draft.value.length; const start = el.selectionStart ?? draft.value.length;
const end = el.selectionEnd ?? start; const end = el.selectionEnd ?? start;
const res = cycleReferenceLocks(draft.value, start, end); const res = cycleReferenceLocks(draft.value, start, end);
@@ -44,6 +43,31 @@ function onF4(e: KeyboardEvent) {
draft.value = res.text; draft.value = res.text;
nextTick(() => el.setSelectionRange(res.start, res.end)); nextTick(() => el.setSelectionRange(res.start, res.end));
} }
function onKeydown(e: KeyboardEvent) {
const el = e.target as HTMLTextAreaElement;
// Alt+Enter (Windows/Excel-365-Mac) or Cmd+Enter (a macOS-safe fallback --
// Option is a compose key there, so `altKey` alone isn't fully reliable;
// `e.code` sidesteps `key` being altered by that composition).
const isEnter = e.key === 'Enter' || e.code === 'Enter' || e.code === 'NumpadEnter';
if (isEnter && (e.altKey || e.metaKey)) {
e.preventDefault();
const start = el.selectionStart ?? draft.value.length;
const end = el.selectionEnd ?? start;
draft.value = draft.value.slice(0, start) + '\n' + draft.value.slice(end);
nextTick(() => el.setSelectionRange(start + 1, start + 1));
return;
}
if (isEnter) {
e.preventDefault();
onEnter();
} else if (e.key === 'Escape') {
e.preventDefault();
onEscape();
} else if (e.key === 'F4') {
e.preventDefault();
onF4(el);
}
}
</script> </script>
<template> <template>
@@ -52,17 +76,16 @@ function onF4(e: KeyboardEvent) {
{{ store.activeCellName.value }} {{ store.activeCellName.value }}
</span> </span>
<span class="fx">fx</span> <span class="fx">fx</span>
<input <textarea
v-model="draft" v-model="draft"
class="formula-input" class="formula-input"
type="text"
spellcheck="false" spellcheck="false"
rows="1"
placeholder="Wert oder =Formel" placeholder="Wert oder =Formel"
title="Ziehen an der unteren Kante, um mehr Zeilen zu zeigen"
@focus="focused = true" @focus="focused = true"
@blur="onBlur" @blur="onBlur"
@keydown.enter.prevent="onEnter" @keydown="onKeydown"
@keydown.esc.prevent="onEscape"
@keydown.f4.prevent="onF4"
/> />
</div> </div>
</template> </template>
@@ -70,7 +93,7 @@ function onF4(e: KeyboardEvent) {
<style scoped> <style scoped>
.formula-bar { .formula-bar {
display: flex; display: flex;
align-items: center; align-items: flex-start;
gap: 10px; gap: 10px;
padding: 6px 12px; padding: 6px 12px;
background: var(--surface); background: var(--surface);
@@ -79,6 +102,7 @@ function onF4(e: KeyboardEvent) {
.cell-name { .cell-name {
min-width: 128px; min-width: 128px;
max-width: 128px; max-width: 128px;
margin-top: 6px;
font-weight: 600; font-weight: 600;
font-size: 12px; font-size: 12px;
color: var(--text-dim); color: var(--text-dim);
@@ -97,12 +121,19 @@ function onF4(e: KeyboardEvent) {
} }
} }
.fx { .fx {
margin-top: 6px;
font-style: italic; font-style: italic;
color: var(--text-dim); color: var(--text-dim);
font-size: 13px; font-size: 13px;
} }
/* a plain <textarea> gives a free, native mouse-draggable resize handle
(bottom-right corner) -- exactly the "erweiterbar/erhöhbar mit der Maus"
ask -- and, unlike the old <input>, actually wraps a long formula instead
of just scrolling it sideways, so growing the box has something to show. */
.formula-input { .formula-input {
flex: 1; flex: 1;
min-height: 30px;
max-height: 50vh;
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: var(--radius-sm); border-radius: var(--radius-sm);
padding: 6px 10px; padding: 6px 10px;
@@ -110,6 +141,10 @@ function onF4(e: KeyboardEvent) {
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
color: var(--text); color: var(--text);
background: var(--surface-2); background: var(--surface-2);
resize: vertical;
overflow-y: auto;
white-space: pre-wrap;
word-break: break-word;
} }
.formula-input:focus { .formula-input:focus {
outline: none; outline: none;