test: add unit test for display of font size
This commit is contained in:
1 parent
56f884a412
commit
f4973caade
3 files changed
+54
-19
No files matched your search
@@ -18,7 +18,7 @@
|
||||
import type { Orientation } from '../storage/pageOrientation';
|
||||
import { pageDimsCm, PAGE_FORMAT_CM, type PageFormat } from '../storage/pageFormat';
|
||||
import { DEFAULT_HF_DISTANCES, clampHfDistance, type HfDistances } from '../storage/headerFooter';
|
||||
import { HEADING_STYLE_OVERRIDES } from '../export/odt';
|
||||
import { blockFontSize, DEFAULT_FONT_SIZE, type SizedBlock } from '../utils/fontSize';
|
||||
import { listContext } from '../editor/extensions/indent';
|
||||
import { findColumns, DEFAULT_COLUMN_GAP_CM } from '../editor/extensions/columns';
|
||||
import { t } from '../i18n/i18n.svelte';
|
||||
@@ -129,27 +129,11 @@
|
||||
return mixed ? '' : (font ?? DEFAULT_EDITOR_FONT);
|
||||
});
|
||||
|
||||
// Must match the common document default; heading sizes come from the export overrides
|
||||
// (the single source editor.css and both importers agree with).
|
||||
const DEFAULT_FONT_SIZE = '12pt';
|
||||
const HEADING_SIZES: Record<number, string> =
|
||||
Object.fromEntries(HEADING_STYLE_OVERRIDES.map((h, i) => [i + 1, h.fontSize]));
|
||||
const FONT_SIZES = [8, 9, 10, 11, 12, 14, 16, 18, 20, 24, 28, 36, 48, 72];
|
||||
|
||||
type SizedBlock = { type: { name: string }; attrs: Record<string, unknown> } | null;
|
||||
|
||||
// What a block renders its unmarked text at: its paragraph-mark size (blockFontSize,
|
||||
// set by the style gallery and by imported sized lines), else the heading/body default.
|
||||
function blockSize(parent: SizedBlock): string {
|
||||
const block = parent?.attrs?.fontSize;
|
||||
if (typeof block === 'string' && block) return block;
|
||||
if (parent?.type.name === 'heading') return HEADING_SIZES[Number(parent.attrs.level)] ?? DEFAULT_FONT_SIZE;
|
||||
return DEFAULT_FONT_SIZE;
|
||||
}
|
||||
|
||||
function effectiveSize(node: { isText: boolean; marks: readonly { type: { name: string }; attrs: Record<string, string> }[] }, parent: SizedBlock): string {
|
||||
const explicit = node.marks.find(m => m.type.name === 'textStyle')?.attrs.fontSize;
|
||||
return explicit || blockSize(parent);
|
||||
return explicit || blockFontSize(parent);
|
||||
}
|
||||
|
||||
let currentFontSize = $derived.by(() => {
|
||||
@@ -160,7 +144,7 @@
|
||||
const marks = editor.state.storedMarks ?? head.marks();
|
||||
const explicit = marks.find(m => m.type.name === 'textStyle')?.attrs.fontSize;
|
||||
if (explicit) return explicit;
|
||||
return blockSize(head.parent as SizedBlock);
|
||||
return blockFontSize(head.parent as SizedBlock);
|
||||
}
|
||||
let size: string | undefined;
|
||||
let mixed = false;
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { HEADING_STYLE_OVERRIDES } from '../export/odt';
|
||||
|
||||
// The size a block renders its unmarked text at — what the toolbar's size box must show.
|
||||
// Keep in sync with editor.css (tests/unit/font-size-display.test.ts asserts it).
|
||||
|
||||
export const DEFAULT_FONT_SIZE = '12pt';
|
||||
|
||||
export const HEADING_SIZES: Record<number, string> =
|
||||
Object.fromEntries(HEADING_STYLE_OVERRIDES.map((h, i) => [i + 1, h.fontSize]));
|
||||
|
||||
export type SizedBlock = { type: { name: string }; attrs?: Record<string, unknown> } | null;
|
||||
|
||||
// Paragraph-mark size (blockFontSize attr) wins, else the heading/body default.
|
||||
export function blockFontSize(block: SizedBlock): string {
|
||||
const explicit = block?.attrs?.fontSize;
|
||||
if (typeof explicit === 'string' && explicit) return explicit;
|
||||
if (block?.type.name === 'heading') return HEADING_SIZES[Number(block.attrs?.level)] ?? DEFAULT_FONT_SIZE;
|
||||
return DEFAULT_FONT_SIZE;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
import { blockFontSize, DEFAULT_FONT_SIZE, HEADING_SIZES } from '../../src/lib/utils/fontSize';
|
||||
|
||||
// The toolbar's size box shows blockFontSize() for text without its own size mark, while
|
||||
// the page renders what editor.css says — so the two tables must not drift apart.
|
||||
const css = readFileSync(resolve(process.cwd(), 'src/styles/editor.css'), 'utf8');
|
||||
|
||||
function cssFontSize(selector: string): string | null {
|
||||
const re = new RegExp(`${selector.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\s*\\{[^}]*?font-size:\\s*([^;]+);`);
|
||||
return css.match(re)?.[1].trim() ?? null;
|
||||
}
|
||||
|
||||
describe('toolbar font size vs. rendered font size', () => {
|
||||
it('shows the paragraph-mark size, else the block default', () => {
|
||||
const para = { type: { name: 'paragraph' }, attrs: {} };
|
||||
expect(blockFontSize(para)).toBe(DEFAULT_FONT_SIZE);
|
||||
expect(blockFontSize({ ...para, attrs: { fontSize: '22pt' } })).toBe('22pt');
|
||||
expect(blockFontSize({ type: { name: 'heading' }, attrs: { level: 5 } })).toBe(HEADING_SIZES[5]);
|
||||
// An explicit paragraph-mark size beats the heading default (style gallery, imports).
|
||||
expect(blockFontSize({ type: { name: 'heading' }, attrs: { level: 1, fontSize: '9pt' } })).toBe('9pt');
|
||||
expect(blockFontSize(null)).toBe(DEFAULT_FONT_SIZE);
|
||||
});
|
||||
|
||||
it('matches the sizes editor.css renders', () => {
|
||||
expect(cssFontSize('.paper .tiptap')).toBe(DEFAULT_FONT_SIZE);
|
||||
for (const [level, size] of Object.entries(HEADING_SIZES)) {
|
||||
expect(cssFontSize(`.paper .tiptap h${level}`), `h${level}`).toBe(size);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user