From 1fb4f3c0ba3dcb667e8b29384780c5d33c6eb970 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Tue, 11 Feb 2025 12:24:02 +0100 Subject: [PATCH 1/2] fix: chrome zoom bug --- packages/core/src/editor/editor.css | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/core/src/editor/editor.css b/packages/core/src/editor/editor.css index 0fe525849..ccbe283a0 100644 --- a/packages/core/src/editor/editor.css +++ b/packages/core/src/editor/editor.css @@ -92,7 +92,7 @@ The color is actually set by reading the current color from the `.collaboration- There are a number of browser specific quirks with these hacks: - Firefox differs from Chrome & Safari in that it will split a word that is wrapping if not displayed as inline-block (whereas the others need display: inline) - - Safari differs from Chrome & Firefox in that it needs the pseudo element to be position: relative to display a pseudo-element element with a negative margin + - Safari differs from Chrome & Firefox in that it needs the pseudo element to be position: absolute to display a pseudo-element element with a negative margin The word-joiner char (\u2060) is used to make sure the caret doesn't wrap around the text. @@ -113,7 +113,10 @@ Therefore if modifying this code, please test in all major browsers to ensure th /* Make the cursor not actually take up the 2px of space within the element */ margin-left: -2px; /* Fixes Safari's rendering of negative margin elements */ - position: relative; + position: absolute; + /* Position the caret's height */ + top: 1px; + bottom: -2px; } /* Firefox will split a word that is wrapping if not displayed as inline-block */ From c96442b9a42684f6c45fa65a24c3a538f1a327d7 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Tue, 11 Feb 2025 12:52:13 +0100 Subject: [PATCH 2/2] fix: use a wrapper element to guarantee elements do not affect layout --- packages/core/src/editor/editor.css | 59 +++---------------- .../createCollaborationExtensions.ts | 17 ++++-- 2 files changed, 19 insertions(+), 57 deletions(-) diff --git a/packages/core/src/editor/editor.css b/packages/core/src/editor/editor.css index ccbe283a0..797ffea0b 100644 --- a/packages/core/src/editor/editor.css +++ b/packages/core/src/editor/editor.css @@ -77,69 +77,26 @@ Tippy popups that are appended to document.body directly opacity: 0.001; } -/** -Here be dragons! - -The collaboration cursor caret needs to: - - exist in the dom as a non-zero width element, so that when hovering over it, the label can display - - yet, effectively not take up space in the dom, so that it doesn't cause wrapping or otherwise effect layout of the page - -To achieve this, it took quite a bit of fiddling to figure out how to do this. - -The caret is a span which has a before and after pseudo element. -The before element is what actually takes up space in the dom, and is colored via a border. -The color is actually set by reading the current color from the `.collaboration-cursor__caret` element. Allowing for dynamic coloring from JS. - -There are a number of browser specific quirks with these hacks: - - Firefox differs from Chrome & Safari in that it will split a word that is wrapping if not displayed as inline-block (whereas the others need display: inline) - - Safari differs from Chrome & Firefox in that it needs the pseudo element to be position: absolute to display a pseudo-element element with a negative margin - -The word-joiner char (\u2060) is used to make sure the caret doesn't wrap around the text. - -Therefore if modifying this code, please test in all major browsers to ensure that the caret is rendered correctly in all browsers. -**/ - -/* Give a remote user a caret */ -.collaboration-cursor__caret { +.collaboration-cursor__base { position: relative; - word-break: normal; - white-space: nowrap !important; } -/* Allow the caret to be colored & hovered over */ -.collaboration-cursor__caret::before { - /* Use currentColor to grab the color from the caret in set by JS */ - border-left: 2px solid currentColor; - /* Make the cursor not actually take up the 2px of space within the element */ - margin-left: -2px; - /* Fixes Safari's rendering of negative margin elements */ +.collaboration-cursor__caret { position: absolute; - /* Position the caret's height */ + width: 2px; top: 1px; bottom: -2px; + left: -1px; } -/* Firefox will split a word that is wrapping if not displayed as inline-block */ -@-moz-document url-prefix() { - .collaboration-cursor__caret::before { - display: inline-block; - } -} - -/* Add a word-joiner (\u2060) char to each side of the caret */ -.collaboration-cursor__caret::after, -.collaboration-cursor__caret::before { - content: "⁠"; -} - -/* Render the username above the caret */ .collaboration-cursor__label { + pointer-events: none; border-radius: 0 1.5px 1.5px 0; font-size: 12px; font-style: normal; font-weight: 600; line-height: normal; - left: -2px; + left: 0; overflow: hidden; position: absolute; white-space: nowrap; @@ -153,13 +110,13 @@ Therefore if modifying this code, please test in all major browsers to ensure th transition: all 0.2s; } -.collaboration-cursor__caret[data-active] > .collaboration-cursor__label { +.collaboration-cursor__base[data-active] .collaboration-cursor__label { color: #0d0d0d; max-height: 1.1rem; max-width: 20rem; padding: 0.1rem 0.3rem; top: -17px; - left: -2px; + left: 0; border-radius: 3px 3px 3px 0; transition: all 0.2s; diff --git a/packages/core/src/extensions/Collaboration/createCollaborationExtensions.ts b/packages/core/src/extensions/Collaboration/createCollaborationExtensions.ts index 4221eed94..aea2b6bf3 100644 --- a/packages/core/src/extensions/Collaboration/createCollaborationExtensions.ts +++ b/packages/core/src/extensions/Collaboration/createCollaborationExtensions.ts @@ -65,11 +65,12 @@ export const createCollaborationExtensions = (collaboration: { const renderCursor = (user: { name: string; color: string }) => { const cursorElement = document.createElement("span"); - cursorElement.classList.add("collaboration-cursor__caret"); - cursorElement.setAttribute("style", `color: ${user.color}`); - if (collaboration?.showCursorLabels === "always") { - cursorElement.setAttribute("data-active", ""); - } + cursorElement.classList.add("collaboration-cursor__base"); + + const caretElement = document.createElement("span"); + caretElement.setAttribute("contentedEditable", "false"); + caretElement.classList.add("collaboration-cursor__caret"); + caretElement.setAttribute("style", `background-color: ${user.color}`); const labelElement = document.createElement("span"); @@ -77,7 +78,11 @@ export const createCollaborationExtensions = (collaboration: { labelElement.setAttribute("style", `background-color: ${user.color}`); labelElement.insertBefore(document.createTextNode(user.name), null); - cursorElement.insertBefore(labelElement, null); + caretElement.insertBefore(labelElement, null); + + cursorElement.insertBefore(document.createTextNode("\u2060"), null); // Non-breaking space + cursorElement.insertBefore(caretElement, null); + cursorElement.insertBefore(document.createTextNode("\u2060"), null); // Non-breaking space return cursorElement; };