diff --git a/packages/layout-engine/painters/dom/src/ruler/ruler-renderer.test.ts b/packages/layout-engine/painters/dom/src/ruler/ruler-renderer.test.ts index 0188f1ecf0..182757f279 100644 --- a/packages/layout-engine/painters/dom/src/ruler/ruler-renderer.test.ts +++ b/packages/layout-engine/painters/dom/src/ruler/ruler-renderer.test.ts @@ -88,14 +88,13 @@ describe('createRulerElement', () => { expect(allTicks[4].style.left).toBe('48px'); // Half tick }); - it('adds labels to main ticks', () => { + it('adds labels to main ticks but skips the leading zero', () => { const ruler = createRulerElement({ definition, doc }); const labels = ruler.querySelectorAll(`.${RULER_CLASS_NAMES.label}`); - expect(labels.length).toBe(2); // Two main ticks with labels + expect(labels.length).toBe(1); // Label 0 is hidden to prevent overflow clipping - expect(labels[0].textContent).toBe('0'); - expect(labels[1].textContent).toBe('1'); + expect(labels[0].textContent).toBe('1'); }); it('does not add labels to non-main ticks', () => { @@ -264,7 +263,7 @@ describe('createRulerElement', () => { expect(labels.length).toBe(0); }); - it('handles tick with label value of 0', () => { + it('does not render label for tick with label value of 0', () => { const singleTickDefinition: RulerDefinition = { ...definition, ticks: [{ size: 'main', height: '20%', label: 0, x: 0 }], @@ -272,8 +271,8 @@ describe('createRulerElement', () => { const ruler = createRulerElement({ definition: singleTickDefinition, doc }); - const label = ruler.querySelector(`.${RULER_CLASS_NAMES.label}`); - expect(label?.textContent).toBe('0'); + const labels = ruler.querySelectorAll(`.${RULER_CLASS_NAMES.label}`); + expect(labels.length).toBe(0); }); }); diff --git a/packages/layout-engine/painters/dom/src/ruler/ruler-renderer.ts b/packages/layout-engine/painters/dom/src/ruler/ruler-renderer.ts index 7fa9286e98..5a3532f730 100644 --- a/packages/layout-engine/painters/dom/src/ruler/ruler-renderer.ts +++ b/packages/layout-engine/painters/dom/src/ruler/ruler-renderer.ts @@ -155,7 +155,7 @@ function createTickElement(tick: RulerTick, doc: Document): HTMLElement { `; // Add label for main ticks - if (tick.label !== undefined) { + if (tick.label !== undefined && tick.label !== 0) { const label = doc.createElement('span'); label.className = RULER_CLASS_NAMES.label; label.textContent = String(tick.label); diff --git a/packages/super-editor/src/components/rulers/Ruler.test.ts b/packages/super-editor/src/components/rulers/Ruler.test.ts index 01b3a9daba..69ecbc08af 100644 --- a/packages/super-editor/src/components/rulers/Ruler.test.ts +++ b/packages/super-editor/src/components/rulers/Ruler.test.ts @@ -1,22 +1,18 @@ -/** - * Test suite for Ruler.vue section-awareness - * - * NOTE: The Ruler.vue component currently has a TypeScript syntax error in its - * emit definition (line 6). The correct syntax should be: - * - * const emit = defineEmits(['margin-change']); - * - * instead of: - * - * const emit = defineEmits<{ - * 'margin-change': [payload: { side: 'left' | 'right'; value: number; sectionIndex: number }] - * }>(); - * - * Once the Ruler.vue file is fixed, these tests can be uncommented and run. - * For now, we document the expected behaviors that should be tested: - */ - import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import { mount } from '@vue/test-utils'; +import { nextTick } from 'vue'; +import Ruler from './Ruler.vue'; + +const createMockEditor = (overrides = {}) => ({ + options: { mode: 'docx' }, + getPageStyles: vi.fn(() => ({ + pageSize: { width: 8.5, height: 11 }, + pageMargins: { left: 1, right: 1, top: 1, bottom: 1 }, + })), + on: vi.fn(), + off: vi.fn(), + ...overrides, +}); /** * Helper to create a mock emitter for testing event handling @@ -38,9 +34,30 @@ const createEmitter = () => { }; }; -describe('Ruler.vue section-awareness (blocked by syntax error in Ruler.vue)', () => { +describe('Ruler.vue rendering', () => { + it('renders the leading zero label and keeps it inside the ruler bounds', async () => { + const wrapper = mount(Ruler, { + props: { + editor: createMockEditor(), + }, + }); + + await nextTick(); + + const labels = wrapper.findAll('.numbering'); + expect(labels.length).toBeGreaterThan(1); + expect(labels[0].text()).toBe('0'); + expect(labels[0].classes()).toContain('numbering--edge-start'); + expect(labels[1].text()).toBe('1'); + expect(labels[1].classes()).not.toContain('numbering--edge-start'); + + wrapper.unmount(); + }); +}); + +describe('Ruler.vue section-awareness coverage gaps', () => { /** - * Required test cases once Ruler.vue syntax is fixed: + * Remaining component test cases to add: * * 1. Updates ruler when section changes * - On 'selectionUpdate' event, should call getCurrentSectionPageStyles() diff --git a/packages/super-editor/src/components/rulers/Ruler.vue b/packages/super-editor/src/components/rulers/Ruler.vue index 8d14098607..5abe9a6b5f 100644 --- a/packages/super-editor/src/components/rulers/Ruler.vue +++ b/packages/super-editor/src/components/rulers/Ruler.vue @@ -459,7 +459,9 @@ onUnmounted(() => { :class="['ruler-tick', `ruler-tick--${tick.size}`]" :style="getTickStyle(tick)" > - {{ tick.label }} + + {{ tick.label }} + @@ -531,4 +533,8 @@ onUnmounted(() => { pointer-events: none; user-select: none; } + +.numbering--edge-start { + left: 0; +}