Editor slotted into a scrollable shadow tree

Two composed web components: <ck-manual-editor-host> keeps the editor in a shadow root of its own and is slotted into <ck-manual-slot-frame>, whose shadow tree wraps its <slot> in a scrollable div.frame (position: relative; overflow: auto; max-height: 300px).

Slotting does not move a node: it stays a child of the host in the node tree while rendering inside the slot. Clipping, scrolling and positioning follow the flattened tree, so a walk over the node tree leaves for <body> and skips div.frame – the element that actually lays the editor out. Everything below is expected to pass in the open mode. In the closed mode Element#assignedSlot is null, so the walk falls back to the node tree and the checks fail. That is a known limitation, not a regression.

Sweep the overlay toggle too. On, the overlay layer (balloons, dialogs, tooltips) gets a container of its own at the end of <body>. Off, it mounts inside the editor component's own root, so it renders inside the frame and is positioned against div.frame – and cannot escape the frame's clipping, so a balloon anchored at the frame's edge is cut off by design.

What to do

  1. Balloons clip to the frame. Scroll the frame until the editable is half out of view, then select a word near its edge. The balloon toolbar has to follow further scrolling and disappear once the selection scrolls out. Same for the link balloon (caret in the link) and the block toolbar handle.
  2. The toolbar sticks to the frame. Click into the editable, then scroll the frame. The toolbar has to stick to the frame's top edge, not to the window, and not scroll away with the content. It is focus-gated, so an unfocused editor never sticks.
  3. The frame scrolls the selection into view. Put the caret in the last paragraph, scroll the frame back to the top, then type. The frame has to scroll, not the window.
  4. Nothing is clipped away wrongly. Open the heading and font dropdowns, a dialog (find & replace) and the menu bar – all positioned against the editable as the frame shows it.

Reach the editor as window.editor and the frame as document.querySelector( 'ck-manual-slot-frame' ).frame, which stays reachable in the closed mode, where host.shadowRoot is null.