docs: remove word as placeholder for general text editor

This commit is contained in:
Steffen Becker committed 2026-08-07 18:08:20 +02:00
1 parent ad38994c65
commit 7c09727cda
18 files changed
+33 -33

No files matched your search

+6 -6
View File
@@ -61,8 +61,8 @@
});
// A header/footer that reaches past the body's margin (its distance from the edge plus
// its line count) pushes the body's content area in so text doesn't overlap it — Word
// grows the margin to fit the zone. ~18.4px = one 12pt line.
// its line count) pushes the body's content area in so text doesn't overlap it: the
// margin grows to fit the zone. ~18.4px = one 12pt line.
const HF_LINE_PX = 16 * 1.15;
function hfReachPx(doc: HfDoc, distPx: number): number {
if (!doc || hfIsEmpty(doc)) return 0;
@@ -193,7 +193,7 @@
return (Number.isFinite(ph) ? ph : 1123) + 20;
}
// --- Right-click context menu (Word's text menu, spelling suggestions merged in) ---
// --- Right-click context menu (text menu, spelling suggestions merged in) ---
let ctxMenu = $state<{ top: number; left: number; items: MenuEntry[] } | null>(null);
// The misspelled range the open menu's suggestions belong to.
let spellTarget: { from: number; to: number; word: string } | null = null;
@@ -212,7 +212,7 @@
const view = ed.view;
const coords = view.posAtCoords({ left: event.clientX, top: event.clientY });
const sel = view.state.selection;
// Word keeps a selection the click lands inside, otherwise it moves the caret.
// A selection the click lands inside is kept, otherwise the caret moves.
if (coords && (sel.empty || coords.pos < sel.from || coords.pos > sel.to)) {
view.dispatch(view.state.tr.setSelection(TextSelection.near(view.state.doc.resolve(coords.pos))));
}
@@ -294,7 +294,7 @@
// Shown when the selection is inside a table; positioned just above that table.
let tableUi = $state<{ visible: boolean; top: number; left: number }>({ visible: false, top: 0, left: 0 });
let tableUiRaf = 0;
// Word-style "Split Cells…" popover, opened from the table toolbar.
// "Split Cells…" popover, opened from the table toolbar.
let splitDialogOpen = $state(false);
// Drop the dialog if the selection leaves the table (toolbar hidden).
$effect(() => {
@@ -738,7 +738,7 @@
saveDocument(e.getJSON());
},
onFocus: () => {
// Clicking back into the body ends header/footer editing (Word behaviour).
// Clicking back into the body ends header/footer editing.
hfActive = null;
},
});
+1 -1
View File
@@ -307,7 +307,7 @@
flex-direction: column;
pointer-events: auto;
/* Content taller than the margin band spills into the margin (footer up, header
down), like Word's auto-growing zones; the anchored edge stays put. */
down) — the zone auto-grows; the anchored edge stays put. */
overflow: visible;
font-family: var(--font-serif);
font-size: 12pt;
@@ -6,7 +6,7 @@
let { editor, tick }: { editor: Editor | null; tick: number } = $props();
let open = $state(false);
// Pen settings (Word-style): presets apply with the currently chosen width/color.
// Pen settings: presets apply with the currently chosen width/color.
let widthPt = $state(0.5);
let color = $state('#000000');
+2 -2
View File
@@ -6,7 +6,7 @@
let { editor, tick }: { editor: Editor | null; tick: number } = $props();
let open = $state(false);
// Pen settings (Word-style): presets apply with the currently chosen width/color.
// Pen settings: presets apply with the currently chosen width/color.
let widthPt = $state(0.5);
let color = $state('#000000');
@@ -45,7 +45,7 @@
);
// Clicking an inactive preset applies the pen; clicking an active one toggles those
// borders off (Word behavior). The panel stays open so the states visibly update.
// borders off. The panel stays open so the states visibly update.
function apply(id: BorderPreset | 'none') {
if (!editor) return;
if (id === 'none') editor.chain().focus().setTableBorders('all', null).run();
+1 -1
View File
@@ -189,7 +189,7 @@
user-select: none;
}
/* Tiles and options side by side, as in Word's Table Design tab. */
/* Tiles and options side by side. */
.tsp-body {
display: flex;
align-items: flex-start;
+1 -1
View File
@@ -274,7 +274,7 @@
return mixed ? '' : (c ?? null);
});
// Sub/superscript are mutually exclusive (Word-style): toggling one clears the
// Sub/superscript are mutually exclusive: toggling one clears the
// other. odf-kit maps these marks to text:position (round-trips with LibreOffice
// and Word). See export/odt.ts applyRuns for the custom-attr-paragraph path.
let isSuperscript = $derived(tick >= 0 && !!editor?.isActive('superscript'));
+1 -1
View File
@@ -4,7 +4,7 @@ import { withShortcut } from '../i18n/shortcut';
import { shortcutHint } from './shortcuts';
import { OPEN_LINK_DIALOG_EVENT } from './extensions/link';
// The right-click menu's contents, Word's text menu mapped onto this editor. Pure
// The right-click menu's contents, the usual text menu mapped onto this editor. Pure
// data + closures — ContextMenu.svelte only renders it.
export type MenuEntry =
| { kind: 'sep' }
+2 -2
View File
@@ -123,11 +123,11 @@ export const extensions = [
TableCell,
TableColumnResize,
TableRowResize,
// Word-style "Split Cells…" (N×M); merge uses extension-table's built-in mergeCells.
// "Split Cells…" (N×M); merge uses extension-table's built-in mergeCells.
TableSplit,
// Cell shading: backgroundColor attr on tableCell/tableHeader (→ fo:background-color).
TableCellBackground,
// Word-style border presets: per-side border attrs on cells (→ fo:border-*).
// Border presets: per-side border attrs on cells (→ fo:border-*).
TableCellBorders,
// "Header row" styling preset: bold + light shading on the first row (toggle).
TableHeaderRow,
+2 -2
View File
@@ -125,7 +125,7 @@ export function mergeJoinedBlocks(blocks: PMNode[]): PMNode[] {
return out;
}
// Word's no-selection behavior: apply columns to the whole document. Wrappable runs
// With no selection, columns apply to the whole document. Wrappable runs
// (absorbing existing sections) become one section each; tables/boxes/TOCs stay
// between them. Replacements run bottom-up so earlier positions stay valid.
function applyToWholeDoc(state: EditorState, tr: Transaction, attrs: ColumnsAttrs): boolean {
@@ -221,7 +221,7 @@ export const Columns = Node.create({
return {
// Inside a section: 1 unwraps the whole chain, 2/3 update its count. Outside:
// with a selection, 2/3 wrap the covered top-level blocks (fails on tables
// etc.); with a bare cursor, the whole document gets columns (Word behavior).
// etc.); with a bare cursor, the whole document gets columns.
setColumns:
(count: number) =>
({ state, dispatch }) => {
+2 -2
View File
@@ -197,7 +197,7 @@ export const ColumnsFlow = Extension.create({
return open;
}
// Split the paragraph at `blockIndex` at the line consuming `budgetPx` (Word's
// Split the paragraph at `blockIndex` at the line consuming `budgetPx` (a
// mid-paragraph page break); the second part is marked joinPrev so joins/export
// restore the original. `force` takes at least one line for an over-tall paragraph.
function splitParagraphInBlock(
@@ -289,7 +289,7 @@ export const ColumnsFlow = Extension.create({
if (first + COLUMNS_FIT_MARGIN_PX > available) {
// First block alone doesn't fit. Mid-page, pageBreaks pushes the
// fragment; at a page top pushing can't help — split the paragraph
// at a line boundary instead (Word's mid-paragraph page break).
// at a line boundary instead (a mid-paragraph page break).
if (
available >= vm.contentHeight - 1 &&
splitParagraphInBlock(frags[i], children, 0, count * (available - SAFETY_PX), scale, true)
+1 -1
View File
@@ -28,7 +28,7 @@ import { Shortcuts } from './shortcuts';
const HfDocument = Document.extend({ content: 'paragraph' });
// The single-paragraph schema can't split, so plain Enter inserts a line break instead
// (Word: Enter in a footer adds a blank line, growing the zone into the page). Shift-/
// (Enter in a footer adds a blank line, growing the zone into the page). Shift-/
// Mod-Enter keep their default break binding.
const HfHardBreak = HardBreak.extend({
addKeyboardShortcuts() {
+1 -1
View File
@@ -23,7 +23,7 @@ declare module '@tiptap/core' {
export const MIN_SIZE_PX = 24;
// Corners keep aspect (Word-style); edges (n/s/e/w) change one dimension only.
// Corners keep aspect; edges (n/s/e/w) change one dimension only.
// Shared with textBox.ts, whose node view uses the same handle set.
export const HANDLES: { k: string; x: -1 | 0 | 1; y: -1 | 0 | 1; aspect: boolean }[] = [
{ k: 'nw', x: -1, y: -1, aspect: true },
+4 -4
View File
@@ -46,7 +46,7 @@ function innermostList($from: ResolvedPos): { node: PMNode; depth: number; depth
}
// The type-defining attr an explicit same-kind list at `depth0` already uses in this
// tree (DFS-first), so a freshly nested list can reuse it — Word's per-level memory.
// tree (DFS-first), so a freshly nested list can reuse it — the per-level memory.
function rememberedListStyle(root: PMNode, kind: string, depth0: number): Record<string, unknown> | null {
let found: Record<string, unknown> | null = null;
const walk = (list: PMNode, d: number) => {
@@ -104,7 +104,7 @@ function clampIndent(cm: number): number {
return Math.round(Math.max(0, Math.min(INDENT_MAX_CM, cm)) * 100) / 100;
}
// A first-line indent is signed (negative = Word's hanging indent).
// A first-line indent is signed (negative = a hanging indent).
function clampFirst(cm: number): number {
return Math.round(Math.max(-INDENT_MAX_CM, Math.min(INDENT_MAX_CM, cm)) * 100) / 100;
}
@@ -115,7 +115,7 @@ function parseIndent(value: string | null): number | null {
return Number.isFinite(n) && n > 0 ? n : null;
}
// A first-line indent may be negative (Word's hanging indent), unlike a left margin.
// A first-line indent may be negative (a hanging indent), unlike a left margin.
function parseSignedIndent(value: string | null): number | null {
if (value == null || value === '') return null;
const n = parseFloat(value);
@@ -153,7 +153,7 @@ export const Indent = Extension.create({
};
},
},
// First-line indent in cm; negative is Word's hanging indent. Independent of
// First-line indent in cm; negative is a hanging indent. Independent of
// `indent`, which is the whole block's left margin.
indentFirst: {
default: null,
+1 -1
View File
@@ -9,7 +9,7 @@ import { columnWeightsFromRow } from './tableView';
// cell selection) into `cols` × `rows` sub-cells. prosemirror-tables only ships
// splitCell (un-merge), so this is custom. The table is a strict rectangular grid,
// so adding sub-columns/rows means inserting grid lines and letting every other
// cell that crosses a new line grow its span (bridge) — exactly what Word does.
// cell that crosses a new line grow its span (bridge).
// Implemented by reading the grid via TableMap, expanding it, partitioning the
// cell's region, and rebuilding the table node in one step.
+1 -1
View File
@@ -364,7 +364,7 @@ class TextBoxView {
);
}
// Word-like frame hit test: the border plus a few px of the inner padding ring
// Frame hit test: the border plus a few px of the inner padding ring
// select the box; anywhere further inside is text area. Rotation-aware (the point
// is un-rotated into the rotor's own axes) and zoom-aware.
private isFrameHit(e: MouseEvent): boolean {
+1 -1
View File
@@ -25,7 +25,7 @@ export interface DtFormat {
tokens: Token[];
}
// Word-style catalog. Samples in the picker render the current time, so the exact
// Format catalog. Samples in the picker render the current time, so the exact
// ordering/separators are visible when choosing.
export const DATE_FORMATS: DtFormat[] = [
{ key: 'iso', kind: 'date', tokens: [
+2 -2
View File
@@ -280,7 +280,7 @@
.paper .tiptap .image-resize-sw { bottom: -5px; left: -5px; cursor: nesw-resize; }
.paper .tiptap .image-resize-w { top: 50%; left: -5px; margin-top: -5px; cursor: ew-resize; }
/* Rotate grip floats above top-centre with a short connector line; the icon is a
circular rotation arrow (like Word). */
circular rotation arrow. */
.paper .tiptap .image-rotate-handle {
display: none;
position: absolute;
@@ -579,7 +579,7 @@
height: 0;
}
/* Paragraph mark (). Reserved in the layout at all times (Word's model) so the toggle
/* Paragraph mark (). Reserved in the layout at all times, so the toggle
only recolors it and text never reflows. Zero-size inline-block, glyph overflows
visibly: width/height/line-height 0 drop both footprint and line-box strut. */
.paper .tiptap p::after,