diff --git a/lib/dist/editors/ColoredGraphEditorElement.js b/lib/dist/editors/ColoredGraphEditorElement.js index ed4fc4a..2d10df9 100644 --- a/lib/dist/editors/ColoredGraphEditorElement.js +++ b/lib/dist/editors/ColoredGraphEditorElement.js @@ -114,7 +114,7 @@ export class ColoredGraphEditorElement extends EditorElement { this.shadowRoot.append(editor); this.blur(); setTimeout(() => editor.focusEditor()); - this.fromNode = node; + //this.fromNode = node; this.render(); this.parentEditor?.dispatchEvent(new CustomEvent("childEditorUpdate", { detail: { @@ -124,7 +124,7 @@ export class ColoredGraphEditorElement extends EditorElement { })); }); this.addEventListener("mouseup", (e) => { - const targetEl = e.path[0]; + const targetEl = e.composedPath()[0]; const targetNode = this.nodes.find(({ editor }) => editor.contains(targetEl) || editor.shadowRoot.contains(targetEl)); if (targetNode) { if (this.fromNode && diff --git a/lib/dist/editors/ForceColoredGraphEditorElement.js b/lib/dist/editors/ForceColoredGraphEditorElement.js index f8fbc95..b5115d8 100644 --- a/lib/dist/editors/ForceColoredGraphEditorElement.js +++ b/lib/dist/editors/ForceColoredGraphEditorElement.js @@ -115,7 +115,7 @@ export class ForceColoredGraphEditorElement extends EditorElement { this.shadowRoot.append(editor); this.blur(); setTimeout(() => editor.focusEditor()); - this.fromNode = node; + //this.fromNode = node; this.render(); this.parentEditor?.dispatchEvent(new CustomEvent("childEditorUpdate", { detail: { @@ -125,7 +125,7 @@ export class ForceColoredGraphEditorElement extends EditorElement { })); }); this.addEventListener("mouseup", (e) => { - const targetEl = e.path[0]; + const targetEl = e.composedPath()[0]; const targetNode = this.nodes.find(({ editor }) => editor.contains(targetEl) || editor.shadowRoot.contains(targetEl)); if (targetNode) { if (this.fromNode && diff --git a/lib/dist/editors/ForceGraphEditorElement.js b/lib/dist/editors/ForceGraphEditorElement.js index d9af2fa..8b674b5 100644 --- a/lib/dist/editors/ForceGraphEditorElement.js +++ b/lib/dist/editors/ForceGraphEditorElement.js @@ -97,7 +97,7 @@ export class ForceGraphEditorElement extends EditorElement { this.shadowRoot.append(editor); this.blur(); setTimeout(() => editor.focusEditor()); - this.fromNode = node; + //this.fromNode = node; this.render(); new CustomEvent("childEditorUpdate", { detail: { @@ -107,8 +107,10 @@ export class ForceGraphEditorElement extends EditorElement { }); }); this.addEventListener("mouseup", (e) => { - const targetEl = e.path[0]; - const targetNode = this.nodes.find(({ editor }) => editor.contains(targetEl) || editor.shadowRoot.contains(targetEl)); + const targetEl = e.composedPath()[0]; + const targetNode = this.nodes.find(({ editor }) => editor === targetEl || + editor.contains(targetEl) || + editor.shadowRoot.contains(targetEl)); if (targetNode) { if (this.fromNode && this.fromNode !== targetNode && diff --git a/lib/dist/editors/MakeGraphEditorElement.js b/lib/dist/editors/MakeGraphEditorElement.js index 1711c12..c2d9f47 100644 --- a/lib/dist/editors/MakeGraphEditorElement.js +++ b/lib/dist/editors/MakeGraphEditorElement.js @@ -103,7 +103,7 @@ export const MakeGraphEditorElement = (NestedEditorConstructor = TextEditorEleme this.shadowRoot.append(editor); this.blur(); setTimeout(() => editor.focusEditor()); - this.fromNode = node; + //this.fromNode = node; this.render(); this.parentEditor?.dispatchEvent(new CustomEvent("childEditorUpdate", { detail: { @@ -113,7 +113,7 @@ export const MakeGraphEditorElement = (NestedEditorConstructor = TextEditorEleme })); }); this.addEventListener("mouseup", (e) => { - const targetEl = e.path[0]; + const targetEl = e.composedPath()[0]; const targetNode = this.nodes.find(({ editor }) => editor.contains(targetEl) || editor.shadowRoot.contains(targetEl)); if (targetNode) { if (this.fromNode && diff --git a/lib/dist/editors/TextEditorElement.js b/lib/dist/editors/TextEditorElement.js index c958efa..5502835 100644 --- a/lib/dist/editors/TextEditorElement.js +++ b/lib/dist/editors/TextEditorElement.js @@ -84,18 +84,23 @@ export class TextEditorElement extends EditorElement { this.addEventListener("mousedown", (e) => { if (e.buttons === 1) { const pos = this.cursorPosFromMouseEvent(e); - this.caret = pos; - this.minorCaret = pos; - this.render(); - setTimeout(() => this.focusEditor()); + if (pos !== -1) { + this.caret = pos; + this.minorCaret = pos; + this.render(); + setTimeout(() => this.focusEditor()); + } + // } }); this.addEventListener("mousemove", (e) => { if (this.isFocused) { if (e.buttons === 1) { const pos = this.cursorPosFromMouseEvent(e); - this.caret = pos; - this.render(); + if (pos !== -1) { + this.caret = pos; + this.render(); + } } } }); diff --git a/lib/dist/editors/TextLikeEditor.js b/lib/dist/editors/TextLikeEditor.js deleted file mode 100644 index e69de29..0000000 diff --git a/lib/dist/editors/TextLikeEditorElement.js b/lib/dist/editors/TextLikeEditorElement.js deleted file mode 100644 index 78bc04e..0000000 --- a/lib/dist/editors/TextLikeEditorElement.js +++ /dev/null @@ -1,324 +0,0 @@ -import { withIndex } from "../Iterable.js"; -import { EditorElement } from "../editor.js"; -export class ArrayEditorElement extends EditorElement { - meta = { - editorName: "Text", - }; - contents; - caret = 0; - minorCaret = 0; - styleEl; - contentsEl; - keyHandler(e) { - return false; // override me! - } - processClipboardText(clipboardText) { - return []; // override me! - } - constructor({ contents } = {}) { - super(...arguments); - this.style.setProperty("--editor-name", `'text'`); - this.style.setProperty("--editor-color", "#017BFF"); - this.style.setProperty("--editor-name-color", "white"); - this.style.setProperty("--editor-background-color", "#E6F2FF"); - this.style.setProperty("--editor-outline-color", "#d4e9ff"); - this.styleEl = document.createElement("style"); - this.styleEl.textContent = ` - contents { - white-space: pre; - width: inherit; - height: inherit; - display: inline-block; - } - :host(:not(:focus-visible)) code caret { - display: none; - } - caret { - position: relative; - display: inline-block; - height: 1rem; - width: 0px; - } - caret::after { - content: ""; - height: 1.2rem; - left: -1px; - width: 2px; - position: absolute; - background: black; - animation: blinker 1s linear infinite; - } - @keyframes blinker { - 0% { opacity: 1; } - 49% { opacity: 1; } - 50% { opacity: 0; } - 100% { opacity: 0; } - } - `; - this.contentsEl = document.createElement("contents"); - this.shadowRoot.append(this.styleEl, this.contentsEl); - this.addEventListener("blur", (e) => { - this.minorCaret = this.caret; - this.render(); - }); - this.addEventListener("mousedown", (e) => { - if (e.buttons === 1) { - const pos = this.cursorPosFromMouseEvent(e); - this.caret = pos; - this.minorCaret = pos; - this.render(); - setTimeout(() => this.focusEditor()); - } - }); - this.addEventListener("mousemove", (e) => { - if (this.isFocused) { - if (e.buttons === 1) { - const pos = this.cursorPosFromMouseEvent(e); - this.caret = pos; - this.render(); - } - } - }); - const copy = (e) => { - if (this.isFocused && this.minorCaret !== this.caret) { - const output = this.getHighlightedOutput(); - e.clipboardData.setData("text/plain", output); - e.preventDefault(); - console.log("copied!", output); - if (e.type === "cut") { - this.backspace(); - this.render(); - } - } - }; - document.addEventListener("copy", copy); - document.addEventListener("cut", copy); - document.addEventListener("paste", (e) => { - let pasteText = e.clipboardData.getData("text"); - if (pasteText && this.isFocused) { - const processed = this.processClipboardText(pasteText); - this.insert(processed); - this.moveCaret(processed.length); - this.render(); - } - }); - this.addEventListener("childEditorUpdate", (e) => { - this.parentEditor?.dispatchEvent(new CustomEvent("childEditorUpdate", { - detail: { - out: this.getOutput(), - editor: this, - }, - })); - }); - this.render(); - this.addEventListener("keydown", (e) => { - if (e.key === "Control") { - // TODO: modifier is down - return; - } - if (e.composedPath().includes(this)) { - if (this.keyHandler) { - this.keyHandler(e); - } - } - if (!e.composedPath().includes(this)) { - } - else if (e.key === "Backspace") { - if (this.parentEditor && this.contents.length === 0) { - this.parentEditor.dispatchEvent(new CustomEvent("subEditorDeleted", { detail: this })); - } - this.backspace(); - this.render(); - } - else if (e.key === "Alt") { - } - else if (e.key === "Meta") { - } - else if (e.key === "CapsLock") { - } - else if (e.key === "Shift") { - } - else if (e.key === "Control") { - } - else if (e.key === "ArrowLeft") { - this.moveCaret(-1, e.shiftKey); - this.render(); - } - else if (e.key === "ArrowRight") { - this.moveCaret(1, e.shiftKey); - this.render(); - } - }); - } - cursorPosFromMouseEvent(e) { - const cand = Array.from(this.contentsEl.children) - .map((childEl) => ({ - el: childEl, - rect: childEl.getBoundingClientRect(), - })) - .filter(({ el, rect }) => { - return e.pageY > rect.top && e.pageY < rect.bottom; - }) - .sort((childA, childB) => Math.abs(e.screenX - childA.rect.right) - - Math.abs(Math.abs(e.screenX - childB.rect.right)))[0]; - const tryAttribute = cand?.el.getAttribute("i") ?? - cand?.el.parentElement.getAttribute("i") ?? - cand?.el.parentElement.parentElement.getAttribute("i"); - if (tryAttribute) { - let chari = parseInt(tryAttribute); - const x = e.pageX - cand.rect.left; //x position within the element. - if (x >= cand.rect.width / 2) { - chari = chari + 1; - } - return chari; - } - return this.contents.length - 1; - } - caretsOrdered() { - let start; - let end; - if (this.minorCaret > this.caret) { - start = this.caret; - end = this.minorCaret; - } - else { - end = this.caret; - start = this.minorCaret; - } - return [start, end]; - } - insert(arr) { - const [start, end] = this.caretsOrdered(); - if (start === end) { - this.contents.splice(this.caret, 0, ...arr); - this.moveCaret(arr.length); - } - else { - this.contents.splice(start, end, ...arr); - } - this.parentEditor?.dispatchEvent(new CustomEvent("childEditorUpdate", { - detail: { - out: this.getOutput(), - editor: this, - }, - })); - } - backspace() { - let start; - let length; - let move; - if (this.minorCaret === this.caret) { - start = this.caret - 1; - length = 1; - move = -1; - } - else if (this.minorCaret > this.caret) { - start = this.caret; - length = this.minorCaret - this.caret; - move = 0; - } - else if (this.minorCaret < this.caret) { - start = this.minorCaret; - length = this.caret - this.minorCaret; - move = -length; - } - this.contents.splice(start, length); - this.moveCaret(move); - this.parentEditor?.dispatchEvent(new CustomEvent("childEditorUpdate", { - detail: { - out: this.getOutput(), - editor: this, - }, - })); - } - moveCaret(change, isSelecting) { - if (this.caret + change > this.contents.length || this.caret + change < 0) { - if (this.parentEditor) { - if (!isSelecting) { - return this.parentEditor; - } - } - return; - } - const newCaret = this.caret + change; - if (isSelecting) { - this.caret = newCaret; - } - else { - this.onCaretMoveOverContentItem(this.contents.slice(this.caret, newCaret)); - this.caret = newCaret; - this.minorCaret = newCaret; - } - } - isIndexInSelection(i) { - return ((i < this.caret && i >= this.minorCaret) || - (i >= this.caret && i < this.minorCaret)); - } - onCaretMoveOverContentItem(contentItems) { - // can be implemented by child class - } - render() { - this.contentsEl.innerHTML = ""; - let results = []; - for (const [contentItem, i] of withIndex(this.contents)) { - if (i === this.caret) { - results.push(document.createElement("caret")); - } - const contentEl = document.createElement("span"); - contentEl.textContent = contentItem.toString(); - contentEl.setAttribute("i", i); - if ((i < this.caret && i >= this.minorCaret) || - (i >= this.caret && i < this.minorCaret)) { - contentEl.style.background = "black"; - contentEl.style.color = "white"; - } - results.push(contentEl); - } - if (this.caret === this.contents.length) { - results.push(document.createElement("caret")); - } - this.contentsEl.append(...results); - } - focusEditor(fromEl, position, isSelecting) { - super.focusEditor(); - if (fromEl !== undefined && position !== undefined) { - if (position === 1) { - // case: entering from a parent on the left - this.caret = 0; - this.minorCaret = this.caret; - } - if (position === 0) { - // case: entering from a parent on the right - this.caret = this.contents.length; - this.minorCaret = this.caret; - } - this.render(); - } - } - blur() { - super.blur(); - this.minorCaret = this.caret; - this.render(); - } - getContentItemOutput(element) { - return element.toString(); - } - getHighlightedOutput() { - if (!this.isFocused || this.minorCaret === this.caret) - return ""; - const [start, end] = this.caretsOrdered(); - let output = ""; - for (let i = start; i < end; i++) { - output += this.getContentItemOutput(this.contents[i]); - } - return output; - } - getOutput() { - let output = ""; - for (const contentItem of this.contents) { - output += this.getContentItemOutput(contentItem); - } - return output; - } -} -customElements.define("textlike-editor", LinearEditorElement); diff --git a/lib/dist/js/bundle.js b/lib/dist/js/bundle.js deleted file mode 100644 index 10ad291..0000000 --- a/lib/dist/js/bundle.js +++ /dev/null @@ -1,145 +0,0 @@ -/******/ (() => { // webpackBootstrap -/******/ "use strict"; -/******/ // The require scope -/******/ var __webpack_require__ = {}; -/******/ -/************************************************************************/ -/******/ /* webpack/runtime/define property getters */ -/******/ (() => { -/******/ // define getter functions for harmony exports -/******/ __webpack_require__.d = (exports, definition) => { -/******/ for(var key in definition) { -/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { -/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); -/******/ } -/******/ } -/******/ }; -/******/ })(); -/******/ -/******/ /* webpack/runtime/hasOwnProperty shorthand */ -/******/ (() => { -/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) -/******/ })(); -/******/ -/******/ /* webpack/runtime/make namespace object */ -/******/ (() => { -/******/ // define __esModule on exports -/******/ __webpack_require__.r = (exports) => { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ })(); -/******/ -/************************************************************************/ -var __webpack_exports__ = {}; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "EditorElement": () => (/* binding */ EditorElement) -/* harmony export */ }); -class EditorElement extends HTMLElement { - constructor({ parentEditor } = { - parentEditor: undefined, - }) { - super(); - this.parentEditor = undefined; - this.isFocused = false; - this.parentEditor = parentEditor; - this.attachShadow({ mode: "open" }); - const styleEl = document.createElement("style"); - styleEl.textContent = ` - :host { - --editor-name: 'editor'; - --editor-color: #017BFF; - --editor-name-color: white; - --editor-background-color: #E6F2FF; - --editor-outline-color: #d4e9ff; - - // unused: - --highlight-text-color: black; - --highlight-editor-color: yellow; - --highlight-editor-name-color: black; - --highlight-editor-background-color: yellow; - - display: inline-flex; - justify-content: center; - - vertical-align: middle; - - user-select: none; - border-radius: 4px; - background: var(--editor-background-color); - border: 2px solid var(--editor-outline-color); - box-sizing: border-box; - position: relative; - font-family: monospace; - - line-height: 1; - - min-height: 1.6rem; - min-width: 0.5rem; - } - :host(:focus)::before { - content: var(--editor-name); - font-size: 14px; - padding: 1px 8px 2px 8px; - background: var(--editor-color); - color: var(--editor-name-color); - position: absolute; - bottom: -17px; - left: -2px; - border-radius: 0 0 4px 4px; - font-family: monospace; - z-index: 10; - } - :host(:focus) { - border: 2px solid var(--editor-color); - color: black !important; - outline: none; - } - :host(:not(:focus)) { - color: rgba(0,0,0,0.5); - } - `; - this.shadowRoot.append(styleEl); - if (!this.hasAttribute("tabindex")) - this.setAttribute("tabindex", "0"); - this.addEventListener("focus", (e) => { - e.stopPropagation(); - this.isFocused = true; - }); - this.addEventListener("subEditorClicked", (e) => { - var _a; - (_a = this.parentEditor) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new CustomEvent("subEditorClicked", { detail: [this, ...e.detail] })); - }); - this.addEventListener("blur", (e) => { - e.stopPropagation(); - this.isFocused = false; - }); - this.addEventListener("mousedown", (e) => { - var _a; - e.stopPropagation(); - (_a = this.parentEditor) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new CustomEvent("subEditorClicked", { detail: [this] })); - this.focus(); - this.isFocused = true; - }); - this.addEventListener("keydown", (e) => e.stopPropagation()); - } - get javaScriptCode() { - return ""; - } - focusEditor(fromEl, position, isSelecting) { - super.focus(); - } -} -// editorDescription: [{ -// name: string; -// description: string; -// iconPath: string; -// ElementConstructor: HTMLElement; -// }] -customElements.define("polytope-editor", EditorElement); - -/******/ })() -; \ No newline at end of file diff --git a/lib/src/editor.ts b/lib/src/editor.ts index ccaacef..8b5714b 100644 --- a/lib/src/editor.ts +++ b/lib/src/editor.ts @@ -1,6 +1,6 @@ export type EditorArgumentObject = { parentEditor?: EditorElement; - builder?: (input: string) => { output: EditorElement }; + builder?: (input: string) => { output: EditorElement[] }; }; export class EditorElement extends HTMLElement { @@ -9,7 +9,7 @@ export class EditorElement extends HTMLElement { isUnstyled?: boolean; }; parentEditor?: EditorElement = undefined; - builder?: (input: string) => { output: EditorElement }; + builder?: (input: string) => { output: EditorElement[] }; isFocused = false; constructor( diff --git a/lib/src/editors/ColoredGraphEditorElement.ts b/lib/src/editors/ColoredGraphEditorElement.ts index 6e912ce..1136ac4 100644 --- a/lib/src/editors/ColoredGraphEditorElement.ts +++ b/lib/src/editors/ColoredGraphEditorElement.ts @@ -150,7 +150,7 @@ export class ColoredGraphEditorElement extends EditorElement { this.shadowRoot.append(editor); this.blur(); setTimeout(() => editor.focusEditor()); - this.fromNode = node; + //this.fromNode = node; this.render(); this.parentEditor?.dispatchEvent( new CustomEvent("childEditorUpdate", { @@ -162,7 +162,7 @@ export class ColoredGraphEditorElement extends EditorElement { ); }); this.addEventListener("mouseup", (e: MouseEvent) => { - const targetEl = (e as any).path[0]; + const targetEl = (e as MouseEvent).composedPath()[0] as Node; const targetNode = this.nodes.find( ({ editor }) => editor.contains(targetEl) || editor.shadowRoot.contains(targetEl) diff --git a/lib/src/editors/ForceColoredGraphEditorElement.ts b/lib/src/editors/ForceColoredGraphEditorElement.ts index dfd3fe5..b08f6f7 100644 --- a/lib/src/editors/ForceColoredGraphEditorElement.ts +++ b/lib/src/editors/ForceColoredGraphEditorElement.ts @@ -151,7 +151,7 @@ export class ForceColoredGraphEditorElement extends EditorElement { this.shadowRoot.append(editor); this.blur(); setTimeout(() => editor.focusEditor()); - this.fromNode = node; + //this.fromNode = node; this.render(); this.parentEditor?.dispatchEvent( new CustomEvent("childEditorUpdate", { @@ -163,7 +163,7 @@ export class ForceColoredGraphEditorElement extends EditorElement { ); }); this.addEventListener("mouseup", (e) => { - const targetEl = (e as any).path[0]; + const targetEl = (e as MouseEvent).composedPath()[0] as Node; const targetNode = this.nodes.find( ({ editor }) => editor.contains(targetEl) || editor.shadowRoot.contains(targetEl) diff --git a/lib/src/editors/ForceGraphEditorElement.ts b/lib/src/editors/ForceGraphEditorElement.ts index 980cca2..8b7fefb 100644 --- a/lib/src/editors/ForceGraphEditorElement.ts +++ b/lib/src/editors/ForceGraphEditorElement.ts @@ -125,7 +125,7 @@ export class ForceGraphEditorElement extends EditorElement { this.shadowRoot.append(editor); this.blur(); setTimeout(() => editor.focusEditor()); - this.fromNode = node; + //this.fromNode = node; this.render(); new CustomEvent("childEditorUpdate", { detail: { @@ -135,10 +135,12 @@ export class ForceGraphEditorElement extends EditorElement { }); }); this.addEventListener("mouseup", (e) => { - const targetEl = (e as any).path[0]; + const targetEl = (e as MouseEvent).composedPath()[0] as Node; const targetNode = this.nodes.find( ({ editor }) => - editor.contains(targetEl) || editor.shadowRoot.contains(targetEl) + editor === targetEl || + editor.contains(targetEl) || + editor.shadowRoot.contains(targetEl) ); if (targetNode) { if ( diff --git a/lib/src/editors/MakeGraphEditorElement.ts b/lib/src/editors/MakeGraphEditorElement.ts index c45cb40..b51ff14 100644 --- a/lib/src/editors/MakeGraphEditorElement.ts +++ b/lib/src/editors/MakeGraphEditorElement.ts @@ -140,7 +140,7 @@ export const MakeGraphEditorElement = ( this.shadowRoot.append(editor); this.blur(); setTimeout(() => editor.focusEditor()); - this.fromNode = node; + //this.fromNode = node; this.render(); this.parentEditor?.dispatchEvent( new CustomEvent("childEditorUpdate", { @@ -152,7 +152,7 @@ export const MakeGraphEditorElement = ( ); }); this.addEventListener("mouseup", (e) => { - const targetEl = (e as any).path[0]; + const targetEl = (e as MouseEvent).composedPath()[0] as Node; const targetNode = this.nodes.find( ({ editor }) => editor.contains(targetEl) || editor.shadowRoot.contains(targetEl) diff --git a/lib/src/editors/TextEditorElement.ts b/lib/src/editors/TextEditorElement.ts index bb0ed8f..296b6c2 100644 --- a/lib/src/editors/TextEditorElement.ts +++ b/lib/src/editors/TextEditorElement.ts @@ -97,20 +97,25 @@ export class TextEditorElement extends EditorElement { this.addEventListener("mousedown", (e) => { if (e.buttons === 1) { const pos = this.cursorPosFromMouseEvent(e); - this.caret = pos; - this.minorCaret = pos; + if (pos !== -1) { + this.caret = pos; + this.minorCaret = pos; + this.render(); - this.render(); - setTimeout(() => this.focusEditor()); + setTimeout(() => this.focusEditor()); + } + + // } }); this.addEventListener("mousemove", (e) => { if (this.isFocused) { if (e.buttons === 1) { const pos = this.cursorPosFromMouseEvent(e); - this.caret = pos; - - this.render(); + if (pos !== -1) { + this.caret = pos; + this.render(); + } } } });