docs: remove word as placeholder for general text editor
This commit is contained in:
1 parent
ad38994c65
commit
7c09727cda
18 files changed
+33
-33
No files matched your search
@@ -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;
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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');
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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'));
|
||||
|
||||
@@ -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' }
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user