mirror of
https://github.com/penpot/penpot.git
synced 2026-10-24 06:38:38 -04:00
📎 Fix some missing changes
This commit is contained in:
1 parent
b80ccbec0f
commit
c8c83c1e1d
58 files changed
+551
-504
No files matched your search
@@ -1,29 +0,0 @@
|
||||
import { describe, test, expect, vi } from 'vitest';
|
||||
import { addEventListeners, removeEventListeners } from './Event';
|
||||
|
||||
/* @vitest-environment jsdom */
|
||||
describe('Event', () => {
|
||||
test('addEventListeners should add event listeners to an element using an object', () => {
|
||||
const clickSpy = vi.fn();
|
||||
const events = {
|
||||
click: clickSpy
|
||||
}
|
||||
const element = document.createElement('div');
|
||||
addEventListeners(element, events);
|
||||
element.dispatchEvent(new Event('click'));
|
||||
expect(clickSpy).toBeCalled();
|
||||
});
|
||||
|
||||
test('removeEventListeners should remove event listeners to an element using an object', () => {
|
||||
const clickSpy = vi.fn();
|
||||
const events = {
|
||||
click: clickSpy,
|
||||
};
|
||||
const element = document.createElement("div");
|
||||
addEventListeners(element, events);
|
||||
element.dispatchEvent(new Event("click"));
|
||||
removeEventListeners(element, events);
|
||||
element.dispatchEvent(new Event('click'))
|
||||
expect(clickSpy).toBeCalledTimes(1);
|
||||
})
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"~/*": ["./*"]
|
||||
"~/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,9 @@
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"main": "editor/TextEditor.js",
|
||||
"main": "src/editor/TextEditor.js",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "./scripts/build.sh",
|
||||
"preview": "vite preview",
|
||||
"coverage": "vitest run --coverage",
|
||||
"test": "vitest --run",
|
||||
"test:watch": "vitest",
|
||||
@@ -23,6 +21,7 @@
|
||||
"esbuild": "^0.24.0",
|
||||
"jsdom": "^25.0.0",
|
||||
"playwright": "^1.45.1",
|
||||
"prettier": "^3.3.3",
|
||||
"vite": "^5.3.1",
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
esbuild --bundle --minify --sourcemap --target=es2021 --format=esm --platform=browser editor/TextEditor.js --outfile=dist/TextEditor.mjs
|
||||
File renamed without changes.
@@ -0,0 +1,29 @@
|
||||
import { describe, test, expect, vi } from "vitest";
|
||||
import { addEventListeners, removeEventListeners } from "./Event.js";
|
||||
|
||||
/* @vitest-environment jsdom */
|
||||
describe("Event", () => {
|
||||
test("addEventListeners should add event listeners to an element using an object", () => {
|
||||
const clickSpy = vi.fn();
|
||||
const events = {
|
||||
click: clickSpy,
|
||||
};
|
||||
const element = document.createElement("div");
|
||||
addEventListeners(element, events);
|
||||
element.dispatchEvent(new Event("click"));
|
||||
expect(clickSpy).toBeCalled();
|
||||
});
|
||||
|
||||
test("removeEventListeners should remove event listeners to an element using an object", () => {
|
||||
const clickSpy = vi.fn();
|
||||
const events = {
|
||||
click: clickSpy,
|
||||
};
|
||||
const element = document.createElement("div");
|
||||
addEventListeners(element, events);
|
||||
element.dispatchEvent(new Event("click"));
|
||||
removeEventListeners(element, events);
|
||||
element.dispatchEvent(new Event("click"));
|
||||
expect(clickSpy).toBeCalledTimes(1);
|
||||
});
|
||||
});
|
||||
File renamed without changes.
+8
-8
@@ -8,15 +8,15 @@
|
||||
|
||||
import clipboard from "./clipboard/index.js";
|
||||
import commands from "./commands/index.js";
|
||||
import ChangeController from './controllers/ChangeController.js';
|
||||
import SelectionController from './controllers/SelectionController.js';
|
||||
import { createSelectionImposterFromClientRects } from './selection/Imposter.js';
|
||||
import ChangeController from "./controllers/ChangeController.js";
|
||||
import SelectionController from "./controllers/SelectionController.js";
|
||||
import { createSelectionImposterFromClientRects } from "./selection/Imposter.js";
|
||||
import { addEventListeners, removeEventListeners } from "./Event.js";
|
||||
import { createRoot, createEmptyRoot } from './content/dom/Root.js';
|
||||
import { createParagraph, fixParagraph, getParagraph } from './content/dom/Paragraph.js';
|
||||
import { createEmptyInline, createInline } from './content/dom/Inline.js';
|
||||
import { isLineBreak } from './content/dom/LineBreak.js';
|
||||
import LayoutType from './layout/LayoutType.js';
|
||||
import { createRoot, createEmptyRoot } from "./content/dom/Root.js";
|
||||
import { createParagraph } from "./content/dom/Paragraph.js";
|
||||
import { createEmptyInline, createInline } from "./content/dom/Inline.js";
|
||||
import { isLineBreak } from "./content/dom/LineBreak.js";
|
||||
import LayoutType from "./layout/LayoutType.js";
|
||||
|
||||
/**
|
||||
* Text Editor.
|
||||
+22
-22
@@ -1,49 +1,49 @@
|
||||
import { describe, test, expect } from 'vitest'
|
||||
import { TextEditor } from './TextEditor'
|
||||
import { describe, test, expect } from "vitest";
|
||||
import { TextEditor } from "./TextEditor.js";
|
||||
|
||||
/* @vitest-environment jsdom */
|
||||
describe('TextEditor', () => {
|
||||
test('Creating TextEditor without element should throw', () => {
|
||||
expect(() => new TextEditor()).toThrowError('Invalid text editor element');
|
||||
describe("TextEditor", () => {
|
||||
test("Creating TextEditor without element should throw", () => {
|
||||
expect(() => new TextEditor()).toThrowError("Invalid text editor element");
|
||||
});
|
||||
|
||||
test('Creating TextEditor with element should success', () => {
|
||||
expect(new TextEditor(document.createElement('div'))).toBeInstanceOf(TextEditor);
|
||||
test("Creating TextEditor with element should success", () => {
|
||||
expect(new TextEditor(document.createElement("div"))).toBeInstanceOf(
|
||||
TextEditor,
|
||||
);
|
||||
});
|
||||
|
||||
test('isEmpty should return true when editor is empty', () => {
|
||||
test("isEmpty should return true when editor is empty", () => {
|
||||
const textEditor = new TextEditor(document.createElement("div"));
|
||||
expect(textEditor).toBeInstanceOf(TextEditor);
|
||||
expect(textEditor.isEmpty).toBe(true);
|
||||
});
|
||||
|
||||
test('Num paragraphs should return 1 when empty', () => {
|
||||
test("Num paragraphs should return 1 when empty", () => {
|
||||
const textEditor = new TextEditor(document.createElement("div"));
|
||||
expect(textEditor).toBeInstanceOf(TextEditor);
|
||||
expect(textEditor.numParagraphs).toBe(1);
|
||||
});
|
||||
|
||||
test('Num paragraphs should return the number of paragraphs', () => {
|
||||
test("Num paragraphs should return the number of paragraphs", () => {
|
||||
const textEditor = new TextEditor(document.createElement("div"));
|
||||
textEditor.root = textEditor.createRoot([
|
||||
textEditor.createParagraph([
|
||||
textEditor.createInlineFromString('Hello, World!')
|
||||
textEditor.createInlineFromString("Hello, World!"),
|
||||
]),
|
||||
textEditor.createParagraph([textEditor.createInlineFromString("")]),
|
||||
textEditor.createParagraph([
|
||||
textEditor.createInlineFromString("¡Hola, Mundo!"),
|
||||
]),
|
||||
textEditor.createParagraph([
|
||||
textEditor.createInlineFromString('')
|
||||
textEditor.createInlineFromString("Hallo, Welt!"),
|
||||
]),
|
||||
textEditor.createParagraph([
|
||||
textEditor.createInlineFromString('¡Hola, Mundo!')
|
||||
]),
|
||||
textEditor.createParagraph([
|
||||
textEditor.createInlineFromString('Hallo, Welt!')
|
||||
])
|
||||
]);
|
||||
expect(textEditor).toBeInstanceOf(TextEditor);
|
||||
expect(textEditor.numParagraphs).toBe(4);
|
||||
});
|
||||
|
||||
test('Disposing a TextEditor nullifies everything', () => {
|
||||
test("Disposing a TextEditor nullifies everything", () => {
|
||||
const textEditor = new TextEditor(document.createElement("div"));
|
||||
expect(textEditor).toBeInstanceOf(TextEditor);
|
||||
textEditor.dispose();
|
||||
@@ -51,7 +51,7 @@ describe('TextEditor', () => {
|
||||
expect(textEditor.element).toBe(null);
|
||||
});
|
||||
|
||||
test('TextEditor focus should focus the contenteditable element', () => {
|
||||
test("TextEditor focus should focus the contenteditable element", () => {
|
||||
const textEditorElement = document.createElement("div");
|
||||
document.body.appendChild(textEditorElement);
|
||||
const textEditor = new TextEditor(textEditorElement);
|
||||
@@ -76,8 +76,8 @@ describe('TextEditor', () => {
|
||||
const textEditor = new TextEditor(textEditorElement);
|
||||
textEditor.root = textEditor.createRoot([
|
||||
textEditor.createParagraph([
|
||||
textEditor.createInlineFromString("Hello, World!")
|
||||
])
|
||||
textEditor.createInlineFromString("Hello, World!"),
|
||||
]),
|
||||
]);
|
||||
expect(textEditor).toBeInstanceOf(TextEditor);
|
||||
textEditor.focus();
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -6,7 +6,7 @@
|
||||
* Copyright (c) KALEIDOS INC
|
||||
*/
|
||||
|
||||
import { mapContentFragmentFromHTML, mapContentFragmentFromString } from '../content/dom/Content.js';
|
||||
import { mapContentFragmentFromHTML, mapContentFragmentFromString } from "../content/dom/Content.js";
|
||||
|
||||
/**
|
||||
* When the user pastes some HTML, what we do is generate
|
||||
File renamed without changes.
+3
-3
@@ -1,5 +1,5 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import CommandMutations from './CommandMutations';
|
||||
import { describe, test, expect } from "vitest";
|
||||
import CommandMutations from "./CommandMutations.js";
|
||||
|
||||
describe("CommandMutations", () => {
|
||||
test("should create a new CommandMutations", () => {
|
||||
@@ -67,5 +67,5 @@ describe("CommandMutations", () => {
|
||||
expect(mutations.added).toBe(null);
|
||||
expect(mutations.updated).toBe(null);
|
||||
expect(mutations.removed).toBe(null);
|
||||
})
|
||||
});
|
||||
});
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+38
-31
@@ -1,23 +1,26 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { mapContentFragmentFromHTML, mapContentFragmentFromString } from './Content.js';
|
||||
import { describe, test, expect } from "vitest";
|
||||
import {
|
||||
mapContentFragmentFromHTML,
|
||||
mapContentFragmentFromString,
|
||||
} from "./Content.js";
|
||||
|
||||
/* @vitest-environment jsdom */
|
||||
describe('Content', () => {
|
||||
describe("Content", () => {
|
||||
test("mapContentFragmentFromHTML should return a valid content for the editor", () => {
|
||||
const inertElement = document.createElement("div");
|
||||
const contentFragment = mapContentFragmentFromHTML(
|
||||
"<div>Hello, World!</div>",
|
||||
inertElement.style
|
||||
inertElement.style,
|
||||
);
|
||||
expect(contentFragment).toBeInstanceOf(DocumentFragment);
|
||||
expect(contentFragment.children).toHaveLength(1);
|
||||
expect(contentFragment.firstElementChild).toBeInstanceOf(HTMLDivElement);
|
||||
expect(contentFragment.firstElementChild.firstElementChild).toBeInstanceOf(
|
||||
HTMLSpanElement
|
||||
);
|
||||
expect(contentFragment.firstElementChild.firstElementChild.firstChild).toBeInstanceOf(
|
||||
Text
|
||||
HTMLSpanElement,
|
||||
);
|
||||
expect(
|
||||
contentFragment.firstElementChild.firstElementChild.firstChild,
|
||||
).toBeInstanceOf(Text);
|
||||
expect(contentFragment.textContent).toBe("Hello, World!");
|
||||
});
|
||||
|
||||
@@ -25,18 +28,18 @@ describe('Content', () => {
|
||||
const inertElement = document.createElement("div");
|
||||
const contentFragment = mapContentFragmentFromHTML(
|
||||
"<div>Hello,<br/><span> World!</span><br/></div>",
|
||||
inertElement.style
|
||||
inertElement.style,
|
||||
);
|
||||
expect(contentFragment).toBeInstanceOf(DocumentFragment);
|
||||
expect(contentFragment.children).toHaveLength(1);
|
||||
expect(contentFragment.firstElementChild).toBeInstanceOf(HTMLDivElement);
|
||||
expect(contentFragment.firstElementChild.children).toHaveLength(2);
|
||||
expect(contentFragment.firstElementChild.firstElementChild).toBeInstanceOf(
|
||||
HTMLSpanElement
|
||||
);
|
||||
expect(contentFragment.firstElementChild.firstElementChild.firstChild).toBeInstanceOf(
|
||||
Text
|
||||
HTMLSpanElement,
|
||||
);
|
||||
expect(
|
||||
contentFragment.firstElementChild.firstElementChild.firstChild,
|
||||
).toBeInstanceOf(Text);
|
||||
expect(contentFragment.textContent).toBe("Hello, World!");
|
||||
});
|
||||
|
||||
@@ -49,42 +52,46 @@ describe('Content', () => {
|
||||
const inertElement = document.createElement("div");
|
||||
const contentFragment = mapContentFragmentFromHTML(
|
||||
"<div>Lorem ipsum</div><div>Dolor sit amet</div><div><br/></div><div>Sed iaculis blandit odio ornare sagittis.</div>",
|
||||
inertElement.style
|
||||
inertElement.style,
|
||||
);
|
||||
expect(contentFragment).toBeInstanceOf(DocumentFragment);
|
||||
expect(contentFragment.children).toHaveLength(3);
|
||||
for (let index = 0; index < contentFragment.children.length; index++) {
|
||||
expect(contentFragment.children.item(index)).toBeInstanceOf(HTMLDivElement);
|
||||
expect(contentFragment.children.item(index).firstElementChild).toBeInstanceOf(
|
||||
HTMLSpanElement
|
||||
expect(contentFragment.children.item(index)).toBeInstanceOf(
|
||||
HTMLDivElement,
|
||||
);
|
||||
expect(
|
||||
contentFragment.children.item(index).firstElementChild.firstChild
|
||||
contentFragment.children.item(index).firstElementChild,
|
||||
).toBeInstanceOf(HTMLSpanElement);
|
||||
expect(
|
||||
contentFragment.children.item(index).firstElementChild.firstChild,
|
||||
).toBeInstanceOf(Text);
|
||||
expect(contentFragment.children.item(index).textContent).toBe(paragraphs[index]);
|
||||
expect(contentFragment.children.item(index).textContent).toBe(
|
||||
paragraphs[index],
|
||||
);
|
||||
}
|
||||
expect(contentFragment.textContent).toBe("Lorem ipsumDolor sit ametSed iaculis blandit odio ornare sagittis.");
|
||||
expect(contentFragment.textContent).toBe(
|
||||
"Lorem ipsumDolor sit ametSed iaculis blandit odio ornare sagittis.",
|
||||
);
|
||||
});
|
||||
|
||||
test("mapContentFragmentFromString should return a valid content for the editor", () => {
|
||||
const contentFragment = mapContentFragmentFromString(
|
||||
"Hello, \nWorld!"
|
||||
);
|
||||
const contentFragment = mapContentFragmentFromString("Hello, \nWorld!");
|
||||
expect(contentFragment).toBeInstanceOf(DocumentFragment);
|
||||
expect(contentFragment.children).toHaveLength(2);
|
||||
expect(contentFragment.children.item(0)).toBeInstanceOf(HTMLDivElement);
|
||||
expect(contentFragment.children.item(1)).toBeInstanceOf(HTMLDivElement);
|
||||
expect(contentFragment.children.item(0).firstElementChild).toBeInstanceOf(
|
||||
HTMLSpanElement
|
||||
);
|
||||
expect(contentFragment.children.item(0).firstElementChild.firstChild).toBeInstanceOf(
|
||||
Text
|
||||
);
|
||||
expect(contentFragment.children.item(1).firstElementChild).toBeInstanceOf(
|
||||
HTMLSpanElement
|
||||
HTMLSpanElement,
|
||||
);
|
||||
expect(
|
||||
contentFragment.children.item(1).firstElementChild.firstChild
|
||||
contentFragment.children.item(0).firstElementChild.firstChild,
|
||||
).toBeInstanceOf(Text);
|
||||
expect(contentFragment.children.item(1).firstElementChild).toBeInstanceOf(
|
||||
HTMLSpanElement,
|
||||
);
|
||||
expect(
|
||||
contentFragment.children.item(1).firstElementChild.firstChild,
|
||||
).toBeInstanceOf(Text);
|
||||
expect(contentFragment.textContent).toBe("Hello, World!");
|
||||
});
|
||||
File renamed without changes.
+24
-16
@@ -1,11 +1,17 @@
|
||||
import { describe, test, expect } from "vitest";
|
||||
import { createElement, isElement, createRandomId, isOffsetAtStart, isOffsetAtEnd } from "./Element.js";
|
||||
import {
|
||||
createElement,
|
||||
isElement,
|
||||
createRandomId,
|
||||
isOffsetAtStart,
|
||||
isOffsetAtEnd,
|
||||
} from "./Element.js";
|
||||
|
||||
/* @vitest-environment jsdom */
|
||||
describe("Element", () => {
|
||||
test("createRandomId should create a new random id", () => {
|
||||
const randomId = createRandomId();
|
||||
expect(typeof randomId).toBe('string');
|
||||
expect(typeof randomId).toBe("string");
|
||||
expect(randomId.length).toBeGreaterThan(0);
|
||||
expect(randomId.length).toBeLessThan(12);
|
||||
});
|
||||
@@ -20,8 +26,8 @@ describe("Element", () => {
|
||||
const element = createElement("div", {
|
||||
attributes: {
|
||||
"aria-multiline": true,
|
||||
"role": "textbox"
|
||||
}
|
||||
role: "textbox",
|
||||
},
|
||||
});
|
||||
expect(element.ariaMultiLine).toBe("true");
|
||||
expect(element.role).toBe("textbox");
|
||||
@@ -30,8 +36,8 @@ describe("Element", () => {
|
||||
test("createElement should create a new element with data- properties", () => {
|
||||
const element = createElement("div", {
|
||||
data: {
|
||||
itype: "root"
|
||||
}
|
||||
itype: "root",
|
||||
},
|
||||
});
|
||||
expect(element.dataset.itype).toBe("root");
|
||||
});
|
||||
@@ -41,14 +47,14 @@ describe("Element", () => {
|
||||
styles: {
|
||||
"text-decoration": "underline",
|
||||
},
|
||||
allowedStyles: [["text-decoration"]]
|
||||
allowedStyles: [["text-decoration"]],
|
||||
});
|
||||
expect(element.style.textDecoration).toBe("underline");
|
||||
});
|
||||
|
||||
test("createElement should create a new element with a child", () => {
|
||||
const element = createElement("div", {
|
||||
children: new Text("Hello, World!")
|
||||
children: new Text("Hello, World!"),
|
||||
});
|
||||
expect(element.textContent).toBe("Hello, World!");
|
||||
});
|
||||
@@ -59,16 +65,18 @@ describe("Element", () => {
|
||||
createElement("div", {
|
||||
children: [
|
||||
createElement("div", {
|
||||
children: new Text("Hello, World!")
|
||||
})
|
||||
]
|
||||
})
|
||||
children: new Text("Hello, World!"),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
});
|
||||
expect(element.textContent).toBe("Hello, World!");
|
||||
expect(element.firstChild.nodeType).toBe(Node.ELEMENT_NODE);
|
||||
expect(element.firstChild.firstChild.nodeType).toBe(Node.ELEMENT_NODE);
|
||||
expect(element.firstChild.firstChild.firstChild.nodeType).toBe(Node.TEXT_NODE);
|
||||
expect(element.firstChild.firstChild.firstChild.nodeType).toBe(
|
||||
Node.TEXT_NODE,
|
||||
);
|
||||
});
|
||||
|
||||
test("isElement returns true if the passed element is the expected element", () => {
|
||||
@@ -81,9 +89,9 @@ describe("Element", () => {
|
||||
});
|
||||
|
||||
test("isOffsetAtStart should return true when offset is 0", () => {
|
||||
const element = createElement('span', {
|
||||
children: new Text("Hello")
|
||||
})
|
||||
const element = createElement("span", {
|
||||
children: new Text("Hello"),
|
||||
});
|
||||
expect(isOffsetAtStart(element, 0)).toBe(true);
|
||||
});
|
||||
|
||||
File renamed without changes.
+18
-6
@@ -1,12 +1,24 @@
|
||||
import { describe, test, expect } from "vitest";
|
||||
import { createEmptyInline, createInline, getInline, getInlineLength, isInline, isInlineEnd, isInlineStart, isLikeInline, splitInline, TAG, TYPE } from "./Inline.js";
|
||||
import {
|
||||
createEmptyInline,
|
||||
createInline,
|
||||
getInline,
|
||||
getInlineLength,
|
||||
isInline,
|
||||
isInlineEnd,
|
||||
isInlineStart,
|
||||
isLikeInline,
|
||||
splitInline,
|
||||
TAG,
|
||||
TYPE,
|
||||
} from "./Inline.js";
|
||||
import { createLineBreak } from "./LineBreak.js";
|
||||
|
||||
/* @vitest-environment jsdom */
|
||||
describe("Inline", () => {
|
||||
test("createInline should throw when passed an invalid child", () => {
|
||||
expect(() => createInline("Hello, World!")).toThrowError(
|
||||
"Invalid inline child"
|
||||
"Invalid inline child",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -44,7 +56,7 @@ describe("Inline", () => {
|
||||
expect(isInline(a)).toBe(false);
|
||||
const b = null;
|
||||
expect(isInline(b)).toBe(false);
|
||||
const c = document.createElement('span');
|
||||
const c = document.createElement("span");
|
||||
expect(isInline(c)).toBe(false);
|
||||
});
|
||||
|
||||
@@ -82,11 +94,11 @@ describe("Inline", () => {
|
||||
|
||||
test("getInline ", () => {
|
||||
expect(getInline(null)).toBe(null);
|
||||
})
|
||||
});
|
||||
|
||||
test("getInlineLength throws when the passed node is not an inline", () => {
|
||||
const inline = document.createElement('div');
|
||||
expect(() => getInlineLength(inline)).toThrowError('Invalid inline');
|
||||
const inline = document.createElement("div");
|
||||
expect(() => getInlineLength(inline)).toThrowError("Invalid inline");
|
||||
});
|
||||
|
||||
test("getInlineLength returns the length of the inline content", () => {
|
||||
File renamed without changes.
+5
-5
@@ -1,11 +1,11 @@
|
||||
import { describe, expect, test } from 'vitest';
|
||||
import { createLineBreak } from './LineBreak.js';
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { createLineBreak } from "./LineBreak.js";
|
||||
|
||||
/* @vitest-environment jsdom */
|
||||
describe('LineBreak', () => {
|
||||
describe("LineBreak", () => {
|
||||
test("createLineBreak should return a <br> element", () => {
|
||||
const br = createLineBreak();
|
||||
expect(br.nodeType).toBe(Node.ELEMENT_NODE);
|
||||
expect(br.nodeName).toBe('BR');
|
||||
})
|
||||
expect(br.nodeName).toBe("BR");
|
||||
});
|
||||
});
|
||||
+1
-2
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
createRandomId,
|
||||
createElement,
|
||||
isElement,
|
||||
isOffsetAtStart,
|
||||
@@ -24,8 +25,6 @@ import {
|
||||
} from "./Inline.js";
|
||||
import { createLineBreak, isLineBreak } from "./LineBreak.js";
|
||||
import { setStyles } from "./Style.js";
|
||||
import { createRandomId } from "./Element.js";
|
||||
import { isEmptyTextNode, isTextNode } from './TextNode.js';
|
||||
|
||||
export const TAG = "DIV";
|
||||
export const TYPE = "paragraph";
|
||||
+19
-20
@@ -18,9 +18,9 @@ import { createInline, isInline } from "./Inline.js";
|
||||
/* @vitest-environment jsdom */
|
||||
describe("Paragraph", () => {
|
||||
test("createParagraph should throw when passed invalid children", () => {
|
||||
expect(() => createParagraph([
|
||||
"Whatever"
|
||||
])).toThrowError("Invalid paragraph children");
|
||||
expect(() => createParagraph(["Whatever"])).toThrowError(
|
||||
"Invalid paragraph children",
|
||||
);
|
||||
});
|
||||
|
||||
test("createEmptyParagraph should create a new empty paragraph", () => {
|
||||
@@ -33,30 +33,30 @@ describe("Paragraph", () => {
|
||||
|
||||
test("isParagraph should return true when the passed node is a paragraph", () => {
|
||||
expect(isParagraph(null)).toBe(false);
|
||||
expect(isParagraph(document.createElement('div'))).toBe(false);
|
||||
expect(isParagraph(document.createElement('h1'))).toBe(false);
|
||||
expect(isParagraph(document.createElement("div"))).toBe(false);
|
||||
expect(isParagraph(document.createElement("h1"))).toBe(false);
|
||||
expect(isParagraph(createEmptyParagraph())).toBe(true);
|
||||
expect(isParagraph(createParagraph([
|
||||
createInline(new Text('Hello, World!'))
|
||||
]))).toBe(true);
|
||||
expect(
|
||||
isParagraph(createParagraph([createInline(new Text("Hello, World!"))])),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
test("isLikeParagraph should return true when node looks like a paragraph", () => {
|
||||
const p = document.createElement('p');
|
||||
const p = document.createElement("p");
|
||||
expect(isLikeParagraph(p)).toBe(true);
|
||||
const div = document.createElement('div');
|
||||
const div = document.createElement("div");
|
||||
expect(isLikeParagraph(div)).toBe(true);
|
||||
const h1 = document.createElement('h1');
|
||||
const h1 = document.createElement("h1");
|
||||
expect(isLikeParagraph(h1)).toBe(true);
|
||||
const h2 = document.createElement('h2');
|
||||
const h2 = document.createElement("h2");
|
||||
expect(isLikeParagraph(h2)).toBe(true);
|
||||
const h3 = document.createElement('h3');
|
||||
const h3 = document.createElement("h3");
|
||||
expect(isLikeParagraph(h3)).toBe(true);
|
||||
const h4 = document.createElement('h4');
|
||||
const h4 = document.createElement("h4");
|
||||
expect(isLikeParagraph(h4)).toBe(true);
|
||||
const h5 = document.createElement('h5');
|
||||
const h5 = document.createElement("h5");
|
||||
expect(isLikeParagraph(h5)).toBe(true);
|
||||
const h6 = document.createElement('h6');
|
||||
const h6 = document.createElement("h6");
|
||||
expect(isLikeParagraph(h6)).toBe(true);
|
||||
});
|
||||
|
||||
@@ -69,7 +69,7 @@ describe("Paragraph", () => {
|
||||
|
||||
test("getParagraph should return null if there aren't closer paragraph nodes", () => {
|
||||
const text = new Text("Hello, World!");
|
||||
const whatever = document.createElement('div');
|
||||
const whatever = document.createElement("div");
|
||||
whatever.appendChild(text);
|
||||
expect(getParagraph(text)).toBe(null);
|
||||
});
|
||||
@@ -81,7 +81,7 @@ describe("Paragraph", () => {
|
||||
|
||||
test("isParagraphStart should return true on a paragraph", () => {
|
||||
const paragraph = createParagraph([
|
||||
createInline(new Text("Hello, World!"))
|
||||
createInline(new Text("Hello, World!")),
|
||||
]);
|
||||
expect(isParagraphStart(paragraph.firstChild.firstChild, 0)).toBe(true);
|
||||
});
|
||||
@@ -162,11 +162,10 @@ describe("Paragraph", () => {
|
||||
|
||||
const nonEmptyInline = document.createElement("span");
|
||||
nonEmptyInline.dataset.itype = "inline";
|
||||
nonEmptyInline.appendChild(new Text('Not empty!'));
|
||||
nonEmptyInline.appendChild(new Text("Not empty!"));
|
||||
const nonEmptyParagraph = document.createElement("div");
|
||||
nonEmptyParagraph.dataset.itype = "paragraph";
|
||||
nonEmptyParagraph.appendChild(nonEmptyInline);
|
||||
expect(isEmptyParagraph(nonEmptyParagraph)).toBe(false);
|
||||
|
||||
});
|
||||
});
|
||||
+1
-2
@@ -6,10 +6,9 @@
|
||||
* Copyright (c) KALEIDOS INC
|
||||
*/
|
||||
|
||||
import { createElement, isElement } from "./Element.js";
|
||||
import { createRandomId, createElement, isElement } from "./Element.js";
|
||||
import { createEmptyParagraph, isParagraph } from "./Paragraph.js";
|
||||
import { setStyles } from "./Style.js";
|
||||
import { createRandomId } from "./Element.js";
|
||||
|
||||
export const TAG = "DIV";
|
||||
export const TYPE = "root";
|
||||
+7
-5
@@ -1,11 +1,11 @@
|
||||
import { describe, test, expect } from "vitest";
|
||||
import { createEmptyRoot, createRoot, setRootStyles, TAG, TYPE } from './Root.js'
|
||||
import { createEmptyRoot, createRoot, setRootStyles, TAG, TYPE } from "./Root.js";
|
||||
|
||||
/* @vitest-environment jsdom */
|
||||
describe("Root", () => {
|
||||
test("createRoot should throw when passed invalid children", () => {
|
||||
expect(() => createRoot(["Whatever"])).toThrowError(
|
||||
"Invalid root children"
|
||||
"Invalid root children",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -16,18 +16,20 @@ describe("Root", () => {
|
||||
expect(emptyRoot.dataset.itype).toBe(TYPE);
|
||||
expect(emptyRoot.firstChild).toBeInstanceOf(HTMLDivElement);
|
||||
expect(emptyRoot.firstChild.firstChild).toBeInstanceOf(HTMLSpanElement);
|
||||
expect(emptyRoot.firstChild.firstChild.firstChild).toBeInstanceOf(HTMLBRElement);
|
||||
expect(emptyRoot.firstChild.firstChild.firstChild).toBeInstanceOf(
|
||||
HTMLBRElement,
|
||||
);
|
||||
});
|
||||
|
||||
test("setRootStyles should apply only the styles of root to the root", () => {
|
||||
const emptyRoot = createEmptyRoot();
|
||||
setRootStyles(emptyRoot, {
|
||||
["--vertical-align"]: "top",
|
||||
["font-size"]: "25px"
|
||||
["font-size"]: "25px",
|
||||
});
|
||||
expect(emptyRoot.style.getPropertyValue("--vertical-align")).toBe("top");
|
||||
// We expect this style to be empty because we don't apply it
|
||||
// to the root.
|
||||
expect(emptyRoot.style.getPropertyValue("font-size")).toBe("");
|
||||
})
|
||||
});
|
||||
});
|
||||
File renamed without changes.
+12
-6
@@ -1,5 +1,11 @@
|
||||
import { describe, test, expect, vi } from "vitest";
|
||||
import { getStyles, isDisplayBlock, isDisplayInline, setStyle, setStyles } from "./Style.js";
|
||||
import {
|
||||
getStyles,
|
||||
isDisplayBlock,
|
||||
isDisplayInline,
|
||||
setStyle,
|
||||
setStyles,
|
||||
} from "./Style.js";
|
||||
|
||||
/* @vitest-environment jsdom */
|
||||
describe("Style", () => {
|
||||
@@ -39,16 +45,16 @@ describe("Style", () => {
|
||||
|
||||
test("getStyles should retrieve a list of allowed styles", () => {
|
||||
const element = document.createElement("div");
|
||||
element.style.display = 'block';
|
||||
element.style.textDecoration = 'underline';
|
||||
element.style.fontSize = '32px';
|
||||
element.style.display = "block";
|
||||
element.style.textDecoration = "underline";
|
||||
element.style.fontSize = "32px";
|
||||
const textDecorationStyles = getStyles(element, [["text-decoration"]]);
|
||||
expect(textDecorationStyles).toStrictEqual({
|
||||
"text-decoration": "underline"
|
||||
"text-decoration": "underline",
|
||||
});
|
||||
const displayStyles = getStyles(element, [["display"]]);
|
||||
expect(displayStyles).toStrictEqual({
|
||||
"display": "block",
|
||||
display: "block",
|
||||
});
|
||||
const fontSizeStyles = getStyles(element, [["font-size", "px"]]);
|
||||
expect(fontSizeStyles).toStrictEqual({
|
||||
File renamed without changes.
+11
-9
@@ -1,6 +1,6 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { isTextNode, getTextNodeLength } from './TextNode.js';
|
||||
import { createLineBreak } from './LineBreak.js';
|
||||
import { describe, test, expect } from "vitest";
|
||||
import { isTextNode, getTextNodeLength } from "./TextNode.js";
|
||||
import { createLineBreak } from "./LineBreak.js";
|
||||
|
||||
/* @vitest-environment jsdom */
|
||||
describe("TextNode", () => {
|
||||
@@ -11,16 +11,18 @@ describe("TextNode", () => {
|
||||
expect(isTextNode("hola")).toBe(false);
|
||||
expect(isTextNode({})).toBe(false);
|
||||
expect(isTextNode([])).toBe(false);
|
||||
expect(() => isTextNode(undefined)).toThrowError('Invalid text node');
|
||||
expect(() => isTextNode(null)).toThrowError('Invalid text node');
|
||||
expect(() => isTextNode(0)).toThrowError('Invalid text node');
|
||||
expect(() => isTextNode(undefined)).toThrowError("Invalid text node");
|
||||
expect(() => isTextNode(null)).toThrowError("Invalid text node");
|
||||
expect(() => isTextNode(0)).toThrowError("Invalid text node");
|
||||
});
|
||||
|
||||
test("getTextNodeLength should return the length of the text node or 0 if it is a <br>", () => {
|
||||
expect(getTextNodeLength(new Text("Hello, World!"))).toBe(13);
|
||||
expect(getTextNodeLength(createLineBreak())).toBe(0);
|
||||
expect(() => getTextNodeLength(undefined)).toThrowError('Invalid text node');
|
||||
expect(() => getTextNodeLength(null)).toThrowError('Invalid text node');
|
||||
expect(() => getTextNodeLength(0)).toThrowError('Invalid text node');
|
||||
expect(() => getTextNodeLength(undefined)).toThrowError(
|
||||
"Invalid text node",
|
||||
);
|
||||
expect(() => getTextNodeLength(null)).toThrowError("Invalid text node");
|
||||
expect(() => getTextNodeLength(0)).toThrowError("Invalid text node");
|
||||
});
|
||||
});
|
||||
File renamed without changes.
+6
-3
@@ -10,11 +10,11 @@ describe("TextNodeIterator", () => {
|
||||
test("Create a new TextNodeIterator with an invalid root should throw", () => {
|
||||
expect(() => new TextNodeIterator(null)).toThrowError("Invalid root node");
|
||||
expect(() => new TextNodeIterator(Infinity)).toThrowError(
|
||||
"Invalid root node"
|
||||
"Invalid root node",
|
||||
);
|
||||
expect(() => new TextNodeIterator(1)).toThrowError("Invalid root node");
|
||||
expect(() => new TextNodeIterator("hola")).toThrowError(
|
||||
"Invalid root node"
|
||||
"Invalid root node",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -26,7 +26,10 @@ describe("TextNodeIterator", () => {
|
||||
createInline(new Text("Whatever")),
|
||||
]),
|
||||
createParagraph([createInline(createLineBreak())]),
|
||||
createParagraph([createInline(new Text("This is a ")), createInline(new Text("test"))]),
|
||||
createParagraph([
|
||||
createInline(new Text("This is a ")),
|
||||
createInline(new Text("test")),
|
||||
]),
|
||||
createParagraph([createInline(new Text("Hi!"))]),
|
||||
]);
|
||||
|
||||
File renamed without changes.
+4
-4
@@ -1,15 +1,15 @@
|
||||
import { expect, describe, test, vi } from 'vitest'
|
||||
import ChangeController from './ChangeController'
|
||||
import { expect, describe, test, vi } from "vitest";
|
||||
import ChangeController from "./ChangeController.js";
|
||||
|
||||
describe("ChangeController", () => {
|
||||
test("Creating a ChangeController without a valid time should throw", () => {
|
||||
expect(() => new ChangeController(Infinity)).toThrowError('Invalid time')
|
||||
expect(() => new ChangeController(Infinity)).toThrowError("Invalid time");
|
||||
});
|
||||
|
||||
test("A ChangeController should dispatch an event when `notifyImmediately` is called", () => {
|
||||
const changeListener = vi.fn();
|
||||
const changeController = new ChangeController(10);
|
||||
changeController.addEventListener("change", changeListener)
|
||||
changeController.addEventListener("change", changeListener);
|
||||
changeController.notifyImmediately();
|
||||
expect(changeController.hasPendingChanges).toBe(false);
|
||||
expect(changeListener).toBeCalled(1);
|
||||
File renamed without changes.
-5
@@ -16,7 +16,6 @@ import {
|
||||
isInlineStart,
|
||||
isInlineEnd,
|
||||
setInlineStyles,
|
||||
mergeInlines,
|
||||
splitInline,
|
||||
createEmptyInline,
|
||||
} from "../content/dom/Inline.js";
|
||||
@@ -29,7 +28,6 @@ import {
|
||||
isParagraphEnd,
|
||||
setParagraphStyles,
|
||||
splitParagraph,
|
||||
splitParagraphAtNode,
|
||||
mergeParagraphs,
|
||||
fixParagraph,
|
||||
} from "../content/dom/Paragraph.js";
|
||||
@@ -48,9 +46,6 @@ import { setRootStyles } from "../content/dom/Root.js";
|
||||
import { SelectionDirection } from "./SelectionDirection.js";
|
||||
import SafeGuard from "./SafeGuard.js";
|
||||
|
||||
const SAFE_GUARD = true;
|
||||
const SAFE_GUARD_TIME = true;
|
||||
|
||||
/**
|
||||
* Supported options for the SelectionController.
|
||||
*
|
||||
+319
-307
File diff suppressed because it is too large.
Load diff
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -6,7 +6,7 @@ test("Create selection DOM rects from client rects", () => {
|
||||
const rect = new DOMRect(20, 20, 100, 50);
|
||||
const clientRects = [
|
||||
new DOMRect(20, 20, 100, 20),
|
||||
new DOMRect(20, 50, 50, 20)
|
||||
new DOMRect(20, 50, 50, 20),
|
||||
];
|
||||
const fragment = createSelectionImposterFromClientRects(rect, clientRects);
|
||||
expect(fragment).toBeInstanceOf(DocumentFragment);
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+4
-4
@@ -1,7 +1,7 @@
|
||||
import { createRoot } from "~/editor/content/dom/Root";
|
||||
import { createParagraph } from "~/editor/content/dom/Paragraph";
|
||||
import { createEmptyInline, createInline } from "~/editor/content/dom/Inline";
|
||||
import { createLineBreak } from "~/editor/content/dom/LineBreak";
|
||||
import { createRoot } from "../editor/content/dom/Root.js";
|
||||
import { createParagraph } from "../editor/content/dom/Paragraph.js";
|
||||
import { createEmptyInline, createInline } from "../editor/content/dom/Inline.js";
|
||||
import { createLineBreak } from "../editor/content/dom/LineBreak.js";
|
||||
|
||||
export class TextEditorMock extends EventTarget {
|
||||
/**
|
||||
@@ -1,26 +1,23 @@
|
||||
import { resolve } from "node:path";
|
||||
import { defineConfig } from "vite";
|
||||
import { coverageConfigDefaults } from 'vitest/config'
|
||||
import { coverageConfigDefaults } from "vitest/config"
|
||||
|
||||
export default defineConfig({
|
||||
root: "./src",
|
||||
resolve: {
|
||||
alias: {
|
||||
"~": resolve("."),
|
||||
"~": resolve("./src"),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
minify: false,
|
||||
minify: true,
|
||||
sourcemap: true,
|
||||
lib: {
|
||||
entry: "editor/TextEditor.js",
|
||||
entry: "src/editor/TextEditor.js",
|
||||
name: "TextEditor",
|
||||
fileName: "TextEditor",
|
||||
formats: ["es"],
|
||||
},
|
||||
terserOptions: {
|
||||
compress: true,
|
||||
mangle: true,
|
||||
},
|
||||
},
|
||||
test: {
|
||||
coverage: {
|
||||
|
||||
@@ -518,6 +518,7 @@ __metadata:
|
||||
esbuild: "npm:^0.24.0"
|
||||
jsdom: "npm:^25.0.0"
|
||||
playwright: "npm:^1.45.1"
|
||||
prettier: "npm:^3.3.3"
|
||||
vite: "npm:^5.3.1"
|
||||
vitest: "npm:^1.6.0"
|
||||
languageName: unknown
|
||||
@@ -2292,6 +2293,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"prettier@npm:^3.3.3":
|
||||
version: 3.3.3
|
||||
resolution: "prettier@npm:3.3.3"
|
||||
bin:
|
||||
prettier: bin/prettier.cjs
|
||||
checksum: 10c0/b85828b08e7505716324e4245549b9205c0cacb25342a030ba8885aba2039a115dbcf75a0b7ca3b37bc9d101ee61fab8113fc69ca3359f2a226f1ecc07ad2e26
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pretty-format@npm:^29.7.0":
|
||||
version: 29.7.0
|
||||
resolution: "pretty-format@npm:29.7.0"
|
||||
|
||||
Reference in new issue
Block a user