feat(writekit): rename @robonen/editor to @robonen/writekit
Rename the rich-text editor package and all Editor* exports to Writekit*; remove the old vue/editor tree.
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { isInteractiveTarget } from '../view/interactive';
|
||||
|
||||
describe('isInteractiveTarget', () => {
|
||||
it('matches atom controls and contenteditable=false islands, not writekit text', () => {
|
||||
const root = document.createElement('div');
|
||||
root.setAttribute('contenteditable', 'true');
|
||||
root.innerHTML = '<p class="text">hi</p><figure contenteditable="false"><input class="cap"></figure>';
|
||||
document.body.append(root);
|
||||
|
||||
expect(isInteractiveTarget(root.querySelector('input.cap'))).toBe(true);
|
||||
expect(isInteractiveTarget(root.querySelector('figure'))).toBe(true);
|
||||
expect(isInteractiveTarget(root.querySelector('p.text'))).toBe(false);
|
||||
expect(isInteractiveTarget(root)).toBe(false);
|
||||
expect(isInteractiveTarget(null)).toBe(false);
|
||||
|
||||
root.remove();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { createBlockElementRegistry, createSelectionBridge } from '../view/selection';
|
||||
|
||||
/**
|
||||
* Builds the single-contenteditable DOM shape the view produces: one
|
||||
* `[data-writekit-content]` root containing plain `[data-block-content]` block
|
||||
* elements. Runs in jsdom (logic project) to prove the cross-block selection
|
||||
* mapping without a real browser.
|
||||
*/
|
||||
function buildDoc() {
|
||||
const root = document.createElement('div');
|
||||
root.setAttribute('data-writekit-content', '');
|
||||
|
||||
const a = document.createElement('p');
|
||||
a.setAttribute('data-block-content', '');
|
||||
a.setAttribute('data-block-id', 'a');
|
||||
a.textContent = 'hello';
|
||||
|
||||
const b = document.createElement('p');
|
||||
b.setAttribute('data-block-content', '');
|
||||
b.setAttribute('data-block-id', 'b');
|
||||
b.textContent = 'world';
|
||||
|
||||
root.append(a, b);
|
||||
document.body.replaceChildren(root);
|
||||
|
||||
const registry = createBlockElementRegistry();
|
||||
registry.set('a', a);
|
||||
registry.set('b', b);
|
||||
|
||||
return { root, a, b, registry };
|
||||
}
|
||||
|
||||
describe('selection bridge (jsdom)', () => {
|
||||
it('round-trips offset ↔ DOM point within a block', () => {
|
||||
const { root, a, registry } = buildDoc();
|
||||
const bridge = createSelectionBridge(() => root, registry);
|
||||
|
||||
const point = bridge.offsetToDomPoint(a, 3);
|
||||
expect(bridge.domPointToOffset(a, point.node, point.offset)).toBe(3);
|
||||
});
|
||||
|
||||
it('reads a cross-block native selection as a cross-block model range', () => {
|
||||
const { root, a, b, registry } = buildDoc();
|
||||
const bridge = createSelectionBridge(() => root, registry);
|
||||
|
||||
const sel = globalThis.getSelection!()!;
|
||||
sel.removeAllRanges();
|
||||
const range = document.createRange();
|
||||
range.setStart(a.firstChild!, 1);
|
||||
range.setEnd(b.firstChild!, 3);
|
||||
sel.addRange(range);
|
||||
|
||||
const model = bridge.read();
|
||||
expect(model?.kind).toBe('text');
|
||||
if (model?.kind === 'text') {
|
||||
expect(model.anchor).toEqual({ blockId: 'a', offset: 1 });
|
||||
expect(model.focus).toEqual({ blockId: 'b', offset: 3 });
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { createDefaultRegistry } from '../preset';
|
||||
import { getSlashItems } from '../view/ui';
|
||||
|
||||
describe('getSlashItems', () => {
|
||||
it('returns every block with meta when the query is empty', () => {
|
||||
const items = getSlashItems(createDefaultRegistry());
|
||||
const types = items.map(item => item.type);
|
||||
expect(types).toContain('heading');
|
||||
expect(types).toContain('image');
|
||||
expect(items.length).toBeGreaterThan(5);
|
||||
});
|
||||
|
||||
it('filters by title and keywords', () => {
|
||||
const registry = createDefaultRegistry();
|
||||
expect(getSlashItems(registry, 'quote').some(item => item.type === 'blockquote')).toBe(true);
|
||||
expect(getSlashItems(registry, 'h1').some(item => item.type === 'heading')).toBe(true);
|
||||
expect(getSlashItems(registry, 'zzzz')).toEqual([]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user