From 95f556c02e54b8c3d1eb253ea5eb423bcb861961 Mon Sep 17 00:00:00 2001 From: boyam01 Date: Thu, 3 Sep 2026 00:52:19 +0800 Subject: [PATCH 1/3] fix: replace narrow mode with container queries --- src/components/modules/ui.ts | 12 +------ src/styles/rtl.css | 11 +++---- src/styles/toolbar.css | 11 +++---- src/styles/toolbox.css | 6 ++-- src/styles/ui.css | 40 ++++++++++------------ src/styles/variables.css | 4 +-- test/cypress/tests/modules/Ui.cy.ts | 51 +++++++++++++++++++++++++++++ 7 files changed, 84 insertions(+), 51 deletions(-) diff --git a/src/components/modules/ui.ts b/src/components/modules/ui.ts index d8dc37989..603ca9e7f 100644 --- a/src/components/modules/ui.ts +++ b/src/components/modules/ui.ts @@ -49,12 +49,11 @@ export default class UI extends Module { * @returns {{editorWrapper: string, editorZone: string}} */ public get CSS(): { - editorWrapper: string; editorWrapperNarrow: string; editorZone: string; editorZoneHidden: string; + editorWrapper: string; editorZone: string; editorZoneHidden: string; editorEmpty: string; editorRtlFix: string; } { return { editorWrapper: 'codex-editor', - editorWrapperNarrow: 'codex-editor--narrow', editorZone: 'codex-editor__redactor', editorZoneHidden: 'codex-editor__redactor--hidden', editorEmpty: 'codex-editor--empty', @@ -290,15 +289,6 @@ export default class UI extends Module { ]); this.nodes.redactor = $.make('div', this.CSS.editorZone); - /** - * If Editor has injected into the narrow container, enable Narrow Mode - * - * @todo Forced layout. Get rid of this feature - */ - if (this.nodes.holder.offsetWidth < this.contentRect.width) { - this.nodes.wrapper.classList.add(this.CSS.editorWrapperNarrow); - } - /** * Set customizable bottom zone height */ diff --git a/src/styles/rtl.css b/src/styles/rtl.css index f65cce74a..7aab1211a 100644 --- a/src/styles/rtl.css +++ b/src/styles/rtl.css @@ -64,19 +64,16 @@ } -.codex-editor--narrow.codex-editor--rtl { - .ce-toolbar__plus { - @media (--not-mobile) { +@media (--not-mobile) { + @container editor (width < 650px) { + .codex-editor.codex-editor--rtl .ce-toolbar__plus { left: 0px; right: 5px; } - } - .ce-toolbar__actions { - @media (--not-mobile) { + .codex-editor.codex-editor--rtl .ce-toolbar__actions { left: -5px; } } } - diff --git a/src/styles/toolbar.css b/src/styles/toolbar.css index 0358eab5b..e5a199c5c 100644 --- a/src/styles/toolbar.css +++ b/src/styles/toolbar.css @@ -84,11 +84,10 @@ } } -/** - * Styles for Narrow mode - */ -.codex-editor--narrow .ce-toolbar__plus { - @media (--not-mobile) { - left: 5px; +@media (--not-mobile) { + @container editor (width < 650px) { + .codex-editor .ce-toolbar__plus { + left: 5px; + } } } diff --git a/src/styles/toolbox.css b/src/styles/toolbox.css index e0c548308..87df2125e 100644 --- a/src/styles/toolbox.css +++ b/src/styles/toolbox.css @@ -2,9 +2,9 @@ } -.codex-editor--narrow .ce-toolbox { - @media (--not-mobile){ - .ce-popover { +@media (--not-mobile){ + @container editor (width < 650px) { + .ce-toolbox .ce-popover { right: 0; left: unset; } diff --git a/src/styles/ui.css b/src/styles/ui.css index d84237b5c..22aaa9938 100644 --- a/src/styles/ui.css +++ b/src/styles/ui.css @@ -2,6 +2,7 @@ * Editor wrapper */ .codex-editor { + container: editor / inline-size; position: relative; box-sizing: border-box; z-index: 1; @@ -20,28 +21,6 @@ } } - /** - * Styles for narrow holder - */ - &--narrow &__redactor { - @media (--not-mobile) { - margin-right: var(--narrow-mode-right-padding); - } - } - - &--narrow&--rtl &__redactor { - @media (--not-mobile) { - margin-left: var(--narrow-mode-right-padding); - margin-right: 0; - } - } - - &--narrow .ce-toolbar__actions { - @media (--not-mobile) { - right: -5px; - } - } - &-copyable { position: absolute; height: 1px; @@ -91,6 +70,23 @@ } } +@media (--not-mobile) { + @container editor (width < 650px) { + .codex-editor .codex-editor__redactor { + margin-right: var(--toolbar-actions-space); + } + + .codex-editor.codex-editor--rtl .codex-editor__redactor { + margin-left: var(--toolbar-actions-space); + margin-right: 0; + } + + .codex-editor .ce-toolbar__actions { + right: -5px; + } + } +} + .codex-editor--toolbox-opened [contentEditable=true][data-placeholder]:focus::before { opacity: 0 !important; diff --git a/src/styles/variables.css b/src/styles/variables.css index 61d8ab2b3..272742e17 100644 --- a/src/styles/variables.css +++ b/src/styles/variables.css @@ -45,9 +45,9 @@ --content-width: 650px; /** - * In narrow mode, we increase right zone contained Block Actions button + * Space reserved for Block Actions inside narrow editor containers */ - --narrow-mode-right-padding: 50px; + --toolbar-actions-space: 50px; /** * Toolbar Plus Button and Toolbox buttons height and width diff --git a/test/cypress/tests/modules/Ui.cy.ts b/test/cypress/tests/modules/Ui.cy.ts index eaf2246a8..478ddc7de 100644 --- a/test/cypress/tests/modules/Ui.cy.ts +++ b/test/cypress/tests/modules/Ui.cy.ts @@ -2,6 +2,57 @@ import { createEditorWithTextBlocks } from '../../support/utils/createEditorWith import type EditorJS from '../../../../types/index'; describe('Ui module', function () { + describe('responsive layout', function () { + it('should not read holder width during initialization', function () { + cy.window() + .then(async (window) => { + const holder = window.document.createElement('div'); + let holderWidthRead = false; + + holder.id = 'editorjs'; + Object.defineProperty(holder, 'offsetWidth', { + configurable: true, + get: () => { + holderWidthRead = true; + + return 700; + }, + }); + window.document.body.appendChild(holder); + + const editor = new window.EditorJS({ + holder, + }); + + await editor.isReady; + + expect(holderWidthRead).to.be.false; + + editor.destroy(); + }); + }); + + it('should keep the plus button inside the holder after it becomes narrow', function () { + cy.viewport(1000, 800); + cy.createEditor(); + + cy.get('[data-cy=editorjs]') + .invoke('css', 'width', '500px') + .find('.ce-paragraph') + .click(); + + cy.get('[data-cy=editorjs]') + .then(($holder) => { + const holderRect = $holder[0].getBoundingClientRect(); + const plusButtonRect = $holder.find('.ce-toolbar__plus')[0].getBoundingClientRect(); + + expect(plusButtonRect.width).to.be.greaterThan(0); + expect(plusButtonRect.left).to.be.at.least(holderRect.left); + expect(plusButtonRect.right).to.be.at.most(holderRect.right); + }); + }); + }); + describe('documentKeydown', function () { describe('Backspace', function () { it('should remove selected blocks', function () { From 1172deb532d34894bb7b41c69daa66bfc48b1ce6 Mon Sep 17 00:00:00 2001 From: boyam01 Date: Thu, 3 Sep 2026 01:54:23 +0800 Subject: [PATCH 2/3] fix: preserve viewport overlays in compact editors Replace layout containment with a ResizeObserver-driven responsive class so fixed overlays keep viewport coordinates without restoring the synchronous width read. --- src/components/modules/ui.ts | 30 ++++++++++++++++++++++++++++- src/styles/rtl.css | 14 ++++++-------- src/styles/toolbar.css | 6 ++---- src/styles/toolbox.css | 8 +++----- src/styles/ui.css | 21 +++++++++----------- test/cypress/tests/modules/Ui.cy.ts | 20 +++++++++++++++++++ 6 files changed, 69 insertions(+), 30 deletions(-) diff --git a/src/components/modules/ui.ts b/src/components/modules/ui.ts index 603ca9e7f..040a8833f 100644 --- a/src/components/modules/ui.ts +++ b/src/components/modules/ui.ts @@ -49,11 +49,12 @@ export default class UI extends Module { * @returns {{editorWrapper: string, editorZone: string}} */ public get CSS(): { - editorWrapper: string; editorZone: string; editorZoneHidden: string; + editorWrapper: string; editorWrapperCompact: string; editorZone: string; editorZoneHidden: string; editorEmpty: string; editorRtlFix: string; } { return { editorWrapper: 'codex-editor', + editorWrapperCompact: 'codex-editor--compact', editorZone: 'codex-editor__redactor', editorZoneHidden: 'codex-editor__redactor--hidden', editorEmpty: 'codex-editor--empty', @@ -105,6 +106,11 @@ export default class UI extends Module { */ private contentRectCache: DOMRect | null = null; + /** + * Watches the editor wrapper without forcing synchronous layout during initialization + */ + private containerResizeObserver: ResizeObserver | null = null; + /** * Handle window resize only when it finished * @@ -226,6 +232,9 @@ export default class UI extends Module { * Clean editor`s UI */ public destroy(): void { + this.containerResizeObserver?.disconnect(); + this.containerResizeObserver = null; + this.nodes.holder.innerHTML = ''; this.unbindReadOnlyInsensitiveListeners(); @@ -297,9 +306,28 @@ export default class UI extends Module { this.nodes.wrapper.appendChild(this.nodes.redactor); this.nodes.holder.appendChild(this.nodes.wrapper); + this.watchContainerWidth(); + this.bindReadOnlyInsensitiveListeners(); } + /** + * Keeps controls inside wrappers that are narrower than the default content width + */ + private watchContainerWidth(): void { + this.containerResizeObserver = new ResizeObserver(([ entry ]) => { + if (entry === undefined) { + return; + } + + this.nodes.wrapper.classList.toggle( + this.CSS.editorWrapperCompact, + entry.contentRect.width < mobileScreenBreakpoint + ); + }); + this.containerResizeObserver.observe(this.nodes.wrapper); + } + /** * Appends CSS */ diff --git a/src/styles/rtl.css b/src/styles/rtl.css index 7aab1211a..606689bbd 100644 --- a/src/styles/rtl.css +++ b/src/styles/rtl.css @@ -65,15 +65,13 @@ } @media (--not-mobile) { - @container editor (width < 650px) { - .codex-editor.codex-editor--rtl .ce-toolbar__plus { - left: 0px; - right: 5px; - } + .codex-editor--compact.codex-editor--rtl .ce-toolbar__plus { + left: 0px; + right: 5px; + } - .codex-editor.codex-editor--rtl .ce-toolbar__actions { - left: -5px; - } + .codex-editor--compact.codex-editor--rtl .ce-toolbar__actions { + left: -5px; } } diff --git a/src/styles/toolbar.css b/src/styles/toolbar.css index e5a199c5c..b6fcad824 100644 --- a/src/styles/toolbar.css +++ b/src/styles/toolbar.css @@ -85,9 +85,7 @@ } @media (--not-mobile) { - @container editor (width < 650px) { - .codex-editor .ce-toolbar__plus { - left: 5px; - } + .codex-editor--compact .ce-toolbar__plus { + left: 5px; } } diff --git a/src/styles/toolbox.css b/src/styles/toolbox.css index 87df2125e..ea780bb16 100644 --- a/src/styles/toolbox.css +++ b/src/styles/toolbox.css @@ -3,10 +3,8 @@ } @media (--not-mobile){ - @container editor (width < 650px) { - .ce-toolbox .ce-popover { - right: 0; - left: unset; - } + .codex-editor--compact .ce-toolbox .ce-popover { + right: 0; + left: unset; } } diff --git a/src/styles/ui.css b/src/styles/ui.css index 22aaa9938..6ed1dfdbf 100644 --- a/src/styles/ui.css +++ b/src/styles/ui.css @@ -2,7 +2,6 @@ * Editor wrapper */ .codex-editor { - container: editor / inline-size; position: relative; box-sizing: border-box; z-index: 1; @@ -71,19 +70,17 @@ } @media (--not-mobile) { - @container editor (width < 650px) { - .codex-editor .codex-editor__redactor { - margin-right: var(--toolbar-actions-space); - } + .codex-editor--compact .codex-editor__redactor { + margin-right: var(--toolbar-actions-space); + } - .codex-editor.codex-editor--rtl .codex-editor__redactor { - margin-left: var(--toolbar-actions-space); - margin-right: 0; - } + .codex-editor--compact.codex-editor--rtl .codex-editor__redactor { + margin-left: var(--toolbar-actions-space); + margin-right: 0; + } - .codex-editor .ce-toolbar__actions { - right: -5px; - } + .codex-editor--compact .ce-toolbar__actions { + right: -5px; } } diff --git a/test/cypress/tests/modules/Ui.cy.ts b/test/cypress/tests/modules/Ui.cy.ts index 478ddc7de..cfe7dd050 100644 --- a/test/cypress/tests/modules/Ui.cy.ts +++ b/test/cypress/tests/modules/Ui.cy.ts @@ -51,6 +51,26 @@ describe('Ui module', function () { expect(plusButtonRect.right).to.be.at.most(holderRect.right); }); }); + + it('should keep the rectangle selection overlay fixed to the viewport', function () { + cy.viewport(1000, 800); + cy.createEditor(); + + cy.get('[data-cy=editorjs]') + .invoke('css', { + marginLeft: '40px', + width: '500px', + }) + .find('.codex-editor-overlay') + .then(($overlay) => { + const overlayRect = $overlay[0].getBoundingClientRect(); + + expect(overlayRect.left).to.equal(0); + expect(overlayRect.top).to.equal(0); + expect(overlayRect.right).to.equal(1000); + expect(overlayRect.bottom).to.equal(800); + }); + }); }); describe('documentKeydown', function () { From bc2dcb1e2e594901bdd0f5159498b16986b2f8ff Mon Sep 17 00:00:00 2001 From: boyam01 Date: Thu, 3 Sep 2026 02:55:34 +0800 Subject: [PATCH 3/3] fix: make toolbar layout fully responsive --- src/components/modules/ui.ts | 30 +------------ src/styles/block.css | 18 ++++++++ src/styles/rtl.css | 36 +++++++++++----- src/styles/toolbar.css | 24 ++++++++--- src/styles/toolbox.css | 7 ---- src/styles/ui.css | 16 ------- src/styles/variables.css | 4 +- test/cypress/tests/modules/Ui.cy.ts | 65 ++++++++++++++++++++++++++++- 8 files changed, 129 insertions(+), 71 deletions(-) diff --git a/src/components/modules/ui.ts b/src/components/modules/ui.ts index 040a8833f..603ca9e7f 100644 --- a/src/components/modules/ui.ts +++ b/src/components/modules/ui.ts @@ -49,12 +49,11 @@ export default class UI extends Module { * @returns {{editorWrapper: string, editorZone: string}} */ public get CSS(): { - editorWrapper: string; editorWrapperCompact: string; editorZone: string; editorZoneHidden: string; + editorWrapper: string; editorZone: string; editorZoneHidden: string; editorEmpty: string; editorRtlFix: string; } { return { editorWrapper: 'codex-editor', - editorWrapperCompact: 'codex-editor--compact', editorZone: 'codex-editor__redactor', editorZoneHidden: 'codex-editor__redactor--hidden', editorEmpty: 'codex-editor--empty', @@ -106,11 +105,6 @@ export default class UI extends Module { */ private contentRectCache: DOMRect | null = null; - /** - * Watches the editor wrapper without forcing synchronous layout during initialization - */ - private containerResizeObserver: ResizeObserver | null = null; - /** * Handle window resize only when it finished * @@ -232,9 +226,6 @@ export default class UI extends Module { * Clean editor`s UI */ public destroy(): void { - this.containerResizeObserver?.disconnect(); - this.containerResizeObserver = null; - this.nodes.holder.innerHTML = ''; this.unbindReadOnlyInsensitiveListeners(); @@ -306,28 +297,9 @@ export default class UI extends Module { this.nodes.wrapper.appendChild(this.nodes.redactor); this.nodes.holder.appendChild(this.nodes.wrapper); - this.watchContainerWidth(); - this.bindReadOnlyInsensitiveListeners(); } - /** - * Keeps controls inside wrappers that are narrower than the default content width - */ - private watchContainerWidth(): void { - this.containerResizeObserver = new ResizeObserver(([ entry ]) => { - if (entry === undefined) { - return; - } - - this.nodes.wrapper.classList.toggle( - this.CSS.editorWrapperCompact, - entry.contentRect.width < mobileScreenBreakpoint - ); - }); - this.containerResizeObserver.observe(this.nodes.wrapper); - } - /** * Appends CSS */ diff --git a/src/styles/block.css b/src/styles/block.css index d4288aae6..6921cb52c 100644 --- a/src/styles/block.css +++ b/src/styles/block.css @@ -35,6 +35,11 @@ &--stretched &__content { max-width: none; + + @media (--not-mobile) { + width: max(0px, calc(100% - var(--toolbar-actions-space))); + margin-left: var(--toolbar-actions-space); + } } &__content { @@ -42,6 +47,19 @@ max-width: var(--content-width); margin: 0 auto; transition: background-color 150ms ease; + + @media (--not-mobile) { + width: min( + var(--content-width), + max(0px, calc(100% - var(--toolbar-actions-space))) + ); + max-width: none; + margin-left: max( + var(--toolbar-actions-space), + calc((100% - var(--content-width)) / 2) + ); + margin-right: 0; + } } &--drop-target &__content { diff --git a/src/styles/rtl.css b/src/styles/rtl.css index 606689bbd..060693313 100644 --- a/src/styles/rtl.css +++ b/src/styles/rtl.css @@ -13,10 +13,9 @@ } &__actions { - right: auto; - left: calc(var(--toolbox-buttons-size) * -1); - @media (--mobile){ + right: auto; + left: calc(var(--toolbox-buttons-size) * -1); margin-left: 0; margin-right: auto; padding-right: 0; @@ -65,13 +64,30 @@ } @media (--not-mobile) { - .codex-editor--compact.codex-editor--rtl .ce-toolbar__plus { - left: 0px; - right: 5px; - } + .codex-editor.codex-editor--rtl { + .ce-block__content, + .ce-toolbar__content { + margin-left: 0; + margin-right: max( + var(--toolbar-actions-space), + calc((100% - var(--content-width)) / 2) + ); + } + + .ce-block--stretched .ce-block__content { + margin-right: var(--toolbar-actions-space); + } - .codex-editor--compact.codex-editor--rtl .ce-toolbar__actions { - left: -5px; + .ce-toolbar__actions { + right: auto; + left: 100%; + padding-right: 0; + padding-left: 5px; + } + + .ce-toolbar__settings-btn { + margin-left: 0; + margin-right: 3px; + } } } - diff --git a/src/styles/toolbar.css b/src/styles/toolbar.css index b6fcad824..1d337893d 100644 --- a/src/styles/toolbar.css +++ b/src/styles/toolbar.css @@ -16,6 +16,19 @@ max-width: var(--content-width); margin: 0 auto; position: relative; + + @media (--not-mobile) { + width: min( + var(--content-width), + max(0px, calc(100% - var(--toolbar-actions-space))) + ); + max-width: none; + margin-left: max( + var(--toolbar-actions-space), + calc((100% - var(--content-width)) / 2) + ); + margin-right: 0; + } } &__plus { @@ -52,6 +65,11 @@ @media (--mobile){ right: auto; } + + @media (--not-mobile){ + width: var(--toolbar-actions-space); + box-sizing: border-box; + } } &__settings-btn { @@ -83,9 +101,3 @@ } } } - -@media (--not-mobile) { - .codex-editor--compact .ce-toolbar__plus { - left: 5px; - } -} diff --git a/src/styles/toolbox.css b/src/styles/toolbox.css index ea780bb16..4abea4567 100644 --- a/src/styles/toolbox.css +++ b/src/styles/toolbox.css @@ -1,10 +1,3 @@ .ce-toolbox { } - -@media (--not-mobile){ - .codex-editor--compact .ce-toolbox .ce-popover { - right: 0; - left: unset; - } -} diff --git a/src/styles/ui.css b/src/styles/ui.css index 6ed1dfdbf..a01f03ad6 100644 --- a/src/styles/ui.css +++ b/src/styles/ui.css @@ -69,22 +69,6 @@ } } -@media (--not-mobile) { - .codex-editor--compact .codex-editor__redactor { - margin-right: var(--toolbar-actions-space); - } - - .codex-editor--compact.codex-editor--rtl .codex-editor__redactor { - margin-left: var(--toolbar-actions-space); - margin-right: 0; - } - - .codex-editor--compact .ce-toolbar__actions { - right: -5px; - } -} - - .codex-editor--toolbox-opened [contentEditable=true][data-placeholder]:focus::before { opacity: 0 !important; } diff --git a/src/styles/variables.css b/src/styles/variables.css index 272742e17..ff2bdc378 100644 --- a/src/styles/variables.css +++ b/src/styles/variables.css @@ -45,9 +45,9 @@ --content-width: 650px; /** - * Space reserved for Block Actions inside narrow editor containers + * Width reserved for Block Actions beside editor content */ - --toolbar-actions-space: 50px; + --toolbar-actions-space: 58px; /** * Toolbar Plus Button and Toolbox buttons height and width diff --git a/test/cypress/tests/modules/Ui.cy.ts b/test/cypress/tests/modules/Ui.cy.ts index cfe7dd050..fbd769aae 100644 --- a/test/cypress/tests/modules/Ui.cy.ts +++ b/test/cypress/tests/modules/Ui.cy.ts @@ -32,7 +32,7 @@ describe('Ui module', function () { }); }); - it('should keep the plus button inside the holder after it becomes narrow', function () { + it('should keep the plus button left of the content in a thin holder on a wide screen', function () { cy.viewport(1000, 800); cy.createEditor(); @@ -44,11 +44,74 @@ describe('Ui module', function () { cy.get('[data-cy=editorjs]') .then(($holder) => { const holderRect = $holder[0].getBoundingClientRect(); + const holderContentLeft = holderRect.left + $holder[0].clientLeft; const plusButtonRect = $holder.find('.ce-toolbar__plus')[0].getBoundingClientRect(); + const blockContentRect = $holder.find('.ce-block__content')[0].getBoundingClientRect(); expect(plusButtonRect.width).to.be.greaterThan(0); + expect(plusButtonRect.left).to.equal(holderContentLeft); + expect(plusButtonRect.right).to.be.at.most(blockContentRect.left); + }); + }); + + it('should preserve the mobile toolbar and toolbox layout', function () { + cy.viewport(375, 667); + cy.createEditor(); + + cy.get('[data-cy=editorjs]') + .find('.ce-paragraph') + .click(); + + cy.get('[data-cy=editorjs]') + .then(($holder) => { + const holderRect = $holder[0].getBoundingClientRect(); + const plusButtonRect = $holder.find('.ce-toolbar__plus')[0].getBoundingClientRect(); + expect(plusButtonRect.left).to.be.at.least(holderRect.left); expect(plusButtonRect.right).to.be.at.most(holderRect.right); + }) + .find('.ce-toolbar__plus') + .click(); + + cy.get('[data-cy=toolbox]') + .find('.ce-popover__container') + .should('be.visible') + .should(($popover) => { + const popoverRect = $popover[0].getBoundingClientRect(); + const viewport = $popover[0].ownerDocument.defaultView; + + expect(viewport).not.to.be.null; + expect(popoverRect.left).to.be.at.least(0); + expect(popoverRect.right).to.be.at.most(viewport?.innerWidth); + expect(popoverRect.top).to.be.at.least(0); + expect(popoverRect.bottom).to.be.at.most(viewport?.innerHeight); + }); + }); + + it('should mirror the responsive toolbar in a thin RTL holder', function () { + cy.viewport(1000, 800); + cy.createEditor({ + i18n: { + direction: 'rtl', + }, + }); + + cy.get('[data-cy=editorjs]') + .invoke('css', 'width', '500px') + .find('.ce-paragraph') + .click(); + + cy.get('[data-cy=editorjs]') + .then(($holder) => { + const holder = $holder[0]; + const holderRect = holder.getBoundingClientRect(); + const holderRightBorder = holder.offsetWidth - holder.clientWidth - holder.clientLeft; + const holderContentRight = holderRect.right - holderRightBorder; + const plusButtonRect = $holder.find('.ce-toolbar__plus')[0].getBoundingClientRect(); + const blockContentRect = $holder.find('.ce-block__content')[0].getBoundingClientRect(); + + expect(plusButtonRect.right).to.equal(holderContentRight); + expect(plusButtonRect.left).to.be.at.least(blockContentRect.right); }); });