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;
+}