diff --git a/src/visualBuilder/utils/__test__/enableInlineEditing.test.ts b/src/visualBuilder/utils/__test__/enableInlineEditing.test.ts index c8565a53..2bee0a0e 100644 --- a/src/visualBuilder/utils/__test__/enableInlineEditing.test.ts +++ b/src/visualBuilder/utils/__test__/enableInlineEditing.test.ts @@ -127,6 +127,39 @@ describe("enableInlineEditing", () => { expect(editableElement.focus).toHaveBeenCalled(); }); + it("should set dir=auto so the caret follows the text direction", () => { + enableInlineEditing({ + expectedFieldData: "Test content", + editableElement, + fieldType: FieldDataType.SINGLELINE, + elements: { + visualBuilderContainer, + resizeObserver, + lastEditedField: null, + }, + }); + + expect(editableElement.getAttribute("dir")).toBe("auto"); + }); + + it("should set dir=auto on the pseudo element when one is created", () => { + // Content differs from expected, so a pseudo editable element is used. + enableInlineEditing({ + expectedFieldData: "Different content", + editableElement, + fieldType: FieldDataType.SINGLELINE, + elements: { + visualBuilderContainer, + resizeObserver, + lastEditedField: null, + }, + }); + + const pseudoElement = + generatePseudoEditableElement.mock.results[0].value; + expect(pseudoElement.getAttribute("dir")).toBe("auto"); + }); + it("should handle multiline fields correctly", () => { enableInlineEditing({ expectedFieldData: "Test content", diff --git a/src/visualBuilder/utils/__test__/getStyleOfAnElement.test.ts b/src/visualBuilder/utils/__test__/getStyleOfAnElement.test.ts index bc449ba8..22decf8f 100644 --- a/src/visualBuilder/utils/__test__/getStyleOfAnElement.test.ts +++ b/src/visualBuilder/utils/__test__/getStyleOfAnElement.test.ts @@ -42,4 +42,14 @@ describe("getStyleOfAnElement", () => { width: "100px", }); }); + + test("it should not copy direction/unicode-bidi so dir=auto can govern", () => { + const elem = document.createElement("div"); + elem.style.direction = "rtl"; + elem.style.unicodeBidi = "isolate"; + + const style = getStyleOfAnElement(elem); + expect(style).not.toHaveProperty("direction"); + expect(style).not.toHaveProperty("unicode-bidi"); + }); }); diff --git a/src/visualBuilder/utils/enableInlineEditing.ts b/src/visualBuilder/utils/enableInlineEditing.ts index ea020a92..92563775 100644 --- a/src/visualBuilder/utils/enableInlineEditing.ts +++ b/src/visualBuilder/utils/enableInlineEditing.ts @@ -92,6 +92,8 @@ export function enableInlineEditing({ } actualEditableField.setAttribute("contenteditable", "true"); + // caret follows the text direction (fixes LTR caret on RTL content) + actualEditableField.setAttribute("dir", "auto"); actualEditableField.addEventListener("input", handleFieldInput); actualEditableField.addEventListener("keydown", handleFieldKeyDown); diff --git a/src/visualBuilder/utils/getStyleOfAnElement.ts b/src/visualBuilder/utils/getStyleOfAnElement.ts index d70a78b0..4451e249 100644 --- a/src/visualBuilder/utils/getStyleOfAnElement.ts +++ b/src/visualBuilder/utils/getStyleOfAnElement.ts @@ -30,6 +30,9 @@ export default function getStyleOfAnElement(element: HTMLElement): { "margin-bottom", "-webkit-user-modify", "cursor", + // let the pseudo element's dir="auto" decide direction, not inline copies + "direction", + "unicode-bidi", ]; const styles: { [key: string]: string } = {}; diff --git a/src/visualBuilder/utils/handleIndividualFields.ts b/src/visualBuilder/utils/handleIndividualFields.ts index 3ddb6763..52f27869 100644 --- a/src/visualBuilder/utils/handleIndividualFields.ts +++ b/src/visualBuilder/utils/handleIndividualFields.ts @@ -133,6 +133,7 @@ export function cleanIndividualFieldResidual(elements: { VISUAL_BUILDER_FIELD_TYPE_ATTRIBUTE_KEY ); previousSelectedEditableDOM.removeAttribute("contenteditable"); + previousSelectedEditableDOM.removeAttribute("dir"); previousSelectedEditableDOM.removeEventListener( "input", handleFieldInput