Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
* Fixed Property Explorer by providing values for properties that are not automatically resolved ([#2832](https://github.com/epam/UUI/issues/2832))
* Fixed tree table indentation when child rows have no checkbox: child rows now reserve consistent checkbox space for alignment ([#2844](https://github.com/epam/UUI/issues/2844))
* [Tooltip]: fixed tooltip not showing on keyboard focus for complex elements with focusable children (e.g. Switch) ([#2959](https://github.com/epam/UUI/issues/2959))
* [RTE]: fixed incorrect floating toolbar position when in shadow DOM ([#3073](https://github.com/epam/UUI/issues/3073))


# 6.4.3 - 04.02.2026
Expand Down
25 changes: 0 additions & 25 deletions uui-editor/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,31 +63,6 @@ export const isEditorValueEmpty = (value: Value) => {
return false;
};

export class SelectionUtils {
static getSelection(params: { shadowRoot: ShadowRoot | undefined }) {
const { shadowRoot } = params;
if (shadowRoot) {
if ((shadowRoot as any).getSelection) {
// Chrome/Edge. See details here: https://caniuse.com/mdn-api_shadowroot_getselection
return (shadowRoot as any).getSelection();
}
}
// Works fine in other cases
return window.getSelection();
}

static getSelectionRange0(params: { selection: Selection; shadowRoot: ShadowRoot | undefined }) {
const { selection, shadowRoot } = params;
if (shadowRoot) {
if ((selection as any).getComposedRanges) {
// Webkit. https://w3c.github.io/selection-api/#dom-selection-getcomposedranges
return (selection as any).getComposedRanges(shadowRoot)[0];
}
}
return selection.getRangeAt(0);
}
}

export const createTempEditor = (plugins: PlatePlugin[]): PlateEditor => {
return createPlateEditor({
plugins: createPlugins((plugins).flat(), {
Expand Down
58 changes: 12 additions & 46 deletions uui-editor/src/implementation/PositionedToolbar.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
import { Dropdown } from '@epam/uui';
import { findNode, toDOMNode, useEditorState, useEventEditorSelectors } from '@udecode/plate-common';
import { findNode, toDOMNode, toDOMRange, useEditorState, useEventEditorSelectors } from '@udecode/plate-common';
import { getCellTypes } from '@udecode/plate-table';
import cx from 'classnames';
import React, { useRef } from 'react';
import React from 'react';
import { Range } from 'slate';
import { offset } from '@floating-ui/react';

import { isImageSelected, isTextSelected, SelectionUtils } from '../helpers';
import { isImageSelected, isTextSelected } from '../helpers';
import css from './PositionedToolbar.module.scss';

interface ToolbarProps {
editor: any;
children: any;
isImage?: boolean;
isTable?: boolean;
placement?: 'top' | 'bottom' | 'right' | 'left';
}

export function FloatingToolbar(props: ToolbarProps): any {
const ref = useRef<HTMLElement | null>(undefined);
const editor = useEditorState(); // TODO: use useEditorRef
const editor = useEditorState();

// useEventEditorSelectors.focus() hook is not working correctly at Safari in ShadowDOM,
// editor focus state changes on tripple click
// TODO: Consider upgrading Plate @udecode/* to check if this is fixed
const inFocus = useEventEditorSelectors.focus() === editor.id;

const getVirtualReferenceElement = () => {
Expand All @@ -30,11 +32,11 @@ export function FloatingToolbar(props: ToolbarProps): any {
});

const domNode = toDOMNode(editor, selectedNode);

if (!domNode) {
return null;
}

return {
getBoundingClientRect(): DOMRect {
return domNode.getBoundingClientRect();
Expand All @@ -44,18 +46,9 @@ export function FloatingToolbar(props: ToolbarProps): any {

return {
getBoundingClientRect(): DOMRect {
const shadowRoot = (() => {
if (ref.current) {
const rootNode = ref.current.getRootNode();
const isShadow = rootNode instanceof ShadowRoot;
const range = toDOMRange(editor, editor.selection);

if (isShadow) {
return rootNode;
}
}
})();

return getSelectionBoundingClientRect({ shadowRoot });
return range.getBoundingClientRect();
},
};
};
Expand Down Expand Up @@ -95,30 +88,3 @@ export function FloatingToolbar(props: ToolbarProps): any {
/>
);
}

const getDefaultBoundingClientRect = () => (({
width: 0,
height: 0,
x: 0,
y: 0,
top: -9999,
left: -9999,
right: 9999,
bottom: 9999,
}) as DOMRect);

/**
* Get bounding client rect of the window selection
*/
const getSelectionBoundingClientRect = (params: { shadowRoot: ShadowRoot | undefined }): DOMRect => {
const { shadowRoot } = params;
const selection = SelectionUtils.getSelection({ shadowRoot });

if (!selection || selection.rangeCount < 1) {
return getDefaultBoundingClientRect();
}

const domRange = SelectionUtils.getSelectionRange0({ selection, shadowRoot });

return domRange.getBoundingClientRect();
};
2 changes: 1 addition & 1 deletion uui-editor/src/implementation/Toolbars.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export function Toolbars({
return (
<Fragment>
{ toolbarPosition === 'floating' && (
<FloatingToolbar placement="top" isImage={ false } editor={ editorRef }>
<FloatingToolbar placement="top" isImage={ false }>
{ floating }
</FloatingToolbar>
) }
Expand Down
1 change: 0 additions & 1 deletion uui-editor/src/plugins/tablePlugin/tablePlugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ function TableRenderer(props: any) {
<TableToolbarContent canUnmerge={ canUnmerge } />
)
}
editor={ editor }
isTable
/>
) }
Expand Down
Loading