Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update: ShadowRoot support #849

Merged
merged 7 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
27 changes: 27 additions & 0 deletions packages/core/src/api/parsers/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Create a Blob from a File object
* @param file
* @returns Blob or null
*/
export function createBlobFromFile(file: File): Promise<Blob | null> {
matthewlipski marked this conversation as resolved.
Show resolved Hide resolved
return new Promise((resolve) => {
if (!file) {
resolve(null);
}

const reader = new FileReader();
reader.onload = () => {
const result = reader.result as string;
fetch(result)
.then((res) => res.blob())
.then((blob) => {
resolve(blob);
})
.catch(() => {
resolve(null);
});
};

reader.readAsDataURL(file);
});
}
8 changes: 4 additions & 4 deletions packages/core/src/extensions/FilePanel/FilePanelPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class FilePanelView<I extends InlineContentSchema, S extends StyleSchema>
// Setting capture=true ensures that any parent container of the editor that
// gets scrolled will trigger the scroll event. Scroll events do not bubble
// and so won't propagate to the document by default.
document.addEventListener("scroll", this.scrollHandler, true);
pmView.root.addEventListener("scroll", this.scrollHandler, true);
}

mouseDownHandler = () => {
Expand All @@ -69,7 +69,7 @@ export class FilePanelView<I extends InlineContentSchema, S extends StyleSchema>

scrollHandler = () => {
if (this.state?.show) {
const blockElement = document.querySelector(
const blockElement = this.pmView.root.querySelector(
`[data-node-type="blockContainer"][data-id="${this.state.block.id}"]`
)!;

Expand All @@ -84,7 +84,7 @@ export class FilePanelView<I extends InlineContentSchema, S extends StyleSchema>
} = this.pluginKey.getState(view.state);

if (!this.state?.show && pluginState.block && this.editor.isEditable) {
const blockElement = document.querySelector(
const blockElement = this.pmView.root.querySelector(
`[data-node-type="blockContainer"][data-id="${pluginState.block.id}"]`
)!;

Expand Down Expand Up @@ -124,7 +124,7 @@ export class FilePanelView<I extends InlineContentSchema, S extends StyleSchema>

this.pmView.dom.removeEventListener("dragstart", this.dragstartHandler);

document.removeEventListener("scroll", this.scrollHandler, true);
this.pmView.root.removeEventListener("scroll", this.scrollHandler, true);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export class FormattingToolbarView implements PluginView {
// Setting capture=true ensures that any parent container of the editor that
// gets scrolled will trigger the scroll event. Scroll events do not bubble
// and so won't propagate to the document by default.
document.addEventListener("scroll", this.scrollHandler, true);
pmView.root.addEventListener("scroll", this.scrollHandler, true);
}

viewMousedownHandler = () => {
Expand Down Expand Up @@ -147,7 +147,7 @@ export class FormattingToolbarView implements PluginView {
this.pmView.dom.removeEventListener("dragstart", this.dragHandler);
this.pmView.dom.removeEventListener("dragover", this.dragHandler);

document.removeEventListener("scroll", this.scrollHandler, true);
this.pmView.root.removeEventListener("scroll", this.scrollHandler, true);
}

closeMenu = () => {
Expand Down
16 changes: 12 additions & 4 deletions packages/core/src/extensions/LinkToolbar/LinkToolbarPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,16 @@ class LinkToolbarView implements PluginView {
};

this.pmView.dom.addEventListener("mouseover", this.mouseOverHandler);
document.addEventListener("click", this.clickHandler, true);
this.pmView.root.addEventListener(
"click",
this.clickHandler as EventListener,
true
);

// Setting capture=true ensures that any parent container of the editor that
// gets scrolled will trigger the scroll event. Scroll events do not bubble
// and so won't propagate to the document by default.
document.addEventListener("scroll", this.scrollHandler, true);
this.pmView.root.addEventListener("scroll", this.scrollHandler, true);
}

mouseOverHandler = (event: MouseEvent) => {
Expand Down Expand Up @@ -271,8 +275,12 @@ class LinkToolbarView implements PluginView {

destroy() {
this.pmView.dom.removeEventListener("mouseover", this.mouseOverHandler);
document.removeEventListener("scroll", this.scrollHandler, true);
document.removeEventListener("click", this.clickHandler, true);
this.pmView.root.removeEventListener("scroll", this.scrollHandler, true);
this.pmView.root.removeEventListener(
"click",
this.clickHandler as EventListener,
true
);
}
}

Expand Down
13 changes: 11 additions & 2 deletions packages/core/src/extensions/Placeholder/PlaceholderPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ export const PlaceholderPlugin = (
if (nonce) {
styleEl.setAttribute("nonce", nonce);
}
document.head.appendChild(styleEl);
if (editor._tiptapEditor.view.root instanceof ShadowRoot) {
editor._tiptapEditor.view.root.append(styleEl);
} else if (editor._tiptapEditor.view.root instanceof Document) {
matthewlipski marked this conversation as resolved.
Show resolved Hide resolved
editor._tiptapEditor.view.root.head.appendChild(styleEl);
}

const styleSheet = styleEl.sheet!;

const getBaseSelector = (additionalSelectors = "") =>
Expand Down Expand Up @@ -62,7 +67,11 @@ export const PlaceholderPlugin = (

return {
destroy: () => {
document.head.removeChild(styleEl);
if (editor._tiptapEditor.view.root instanceof ShadowRoot) {
editor._tiptapEditor.view.root.removeChild(styleEl);
} else if (editor._tiptapEditor.view.root instanceof Document) {
editor._tiptapEditor.view.root.head.removeChild(styleEl);
}
},
};
},
Expand Down
67 changes: 50 additions & 17 deletions packages/core/src/extensions/SideMenu/SideMenuPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ function setDragImage(view: EditorView, from: number, to = from) {
}

// dataTransfer.setDragImage(element) only works if element is attached to the DOM.
unsetDragImage();
unsetDragImage(view.root);
dragImageElement = parentClone;

// TODO: This is hacky, need a better way of assigning classes to the editor so that they can also be applied to the
Expand All @@ -146,12 +146,12 @@ function setDragImage(view: EditorView, from: number, to = from) {
dragImageElement.className =
dragImageElement.className + " bn-drag-preview " + inheritedClasses;

document.body.appendChild(dragImageElement);
view.root.appendChild(dragImageElement);
matthewlipski marked this conversation as resolved.
Show resolved Hide resolved
}

function unsetDragImage() {
function unsetDragImage(rootEl: Document | ShadowRoot) {
if (dragImageElement !== undefined) {
document.body.removeChild(dragImageElement);
rootEl.removeChild(dragImageElement);
dragImageElement = undefined;
}
}
Expand All @@ -177,7 +177,7 @@ function dragStart<
top: e.clientY,
};

const elements = document.elementsFromPoint(coords.left, coords.top);
const elements = view.root.elementsFromPoint(coords.left, coords.top);
let blockEl = undefined;

for (const element of elements) {
Expand Down Expand Up @@ -283,22 +283,37 @@ export class SideMenuView<
this.pmView.dom.firstChild! as HTMLElement
).getBoundingClientRect().x;

document.body.addEventListener("drop", this.onDrop, true);
document.body.addEventListener("dragover", this.onDragOver);
this.pmView.root.addEventListener(
"drop",
this.onDrop as EventListener,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make this work without the cast?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without the cast no, there is another way where we explicitly type it with the type of the handler. Like so:

this.pmView.root.addEventListener(
"drop",
(event: Event) => this.onDrop(event as DragEvent),
true
);

Let me know the one you prefer to keep as standard and I can do the necessary updates!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we also conditionally add the listeners only if view.root instanceof Document? Since shadow roots don't support listeners anyway

true
);
this.pmView.root.addEventListener(
"dragover",
this.onDragOver as EventListener
);
this.pmView.dom.addEventListener("dragstart", this.onDragStart);

// Shows or updates menu position whenever the cursor moves, if the menu isn't frozen.
document.body.addEventListener("mousemove", this.onMouseMove, true);
this.pmView.root.addEventListener(
"mousemove",
this.onMouseMove as EventListener,
true
);

// Unfreezes the menu whenever the user clicks.
this.pmView.dom.addEventListener("mousedown", this.onMouseDown);
// Hides and unfreezes the menu whenever the user presses a key.
document.body.addEventListener("keydown", this.onKeyDown, true);
this.pmView.root.addEventListener(
"keydown",
this.onKeyDown as EventListener,
true
);

// Setting capture=true ensures that any parent container of the editor that
// gets scrolled will trigger the scroll event. Scroll events do not bubble
// and so won't propagate to the document by default.
document.addEventListener("scroll", this.onScroll, true);
this.pmView.root.addEventListener("scroll", this.onScroll, true);
}

updateState = () => {
Expand All @@ -322,7 +337,10 @@ export class SideMenuView<
top: this.mousePos.y,
};

const elements = document.elementsFromPoint(coords.left, coords.top);
const elements = this.pmView.root.elementsFromPoint(
coords.left,
coords.top
);
let block = undefined;

for (const element of elements) {
Expand Down Expand Up @@ -553,13 +571,28 @@ export class SideMenuView<
this.state.show = false;
this.emitUpdate(this.state);
}
document.body.removeEventListener("mousemove", this.onMouseMove, true);
document.body.removeEventListener("dragover", this.onDragOver);
this.pmView.root.removeEventListener(
"mousemove",
this.onMouseMove as EventListener,
true
);
this.pmView.root.removeEventListener(
"dragover",
this.onDragOver as EventListener
);
this.pmView.dom.removeEventListener("dragstart", this.onDragStart);
document.body.removeEventListener("drop", this.onDrop, true);
document.removeEventListener("scroll", this.onScroll, true);
this.pmView.root.removeEventListener(
"drop",
this.onDrop as EventListener,
true
);
this.pmView.root.removeEventListener("scroll", this.onScroll, true);
this.pmView.dom.removeEventListener("mousedown", this.onMouseDown);
document.body.removeEventListener("keydown", this.onKeyDown, true);
this.pmView.root.removeEventListener(
"keydown",
this.onKeyDown as EventListener,
true
);
}

addBlock() {
Expand Down Expand Up @@ -665,7 +698,7 @@ export class SideMenuProsemirrorPlugin<
/**
* Handles drag & drop events for blocks.
*/
blockDragEnd = () => unsetDragImage();
blockDragEnd = () => unsetDragImage(this.editor.prosemirrorView.root);
/**
* Freezes the side menu. When frozen, the side menu will stay
* attached to the same block regardless of which block is hovered by the
Expand Down
12 changes: 7 additions & 5 deletions packages/core/src/extensions/SuggestionMenu/SuggestionPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class SuggestionMenuView<
> {
public state?: SuggestionMenuState;
public emitUpdate: (triggerCharacter: string) => void;

private rootEl?: Document | ShadowRoot;
pluginState: SuggestionPluginState;

constructor(
Expand All @@ -37,15 +37,17 @@ class SuggestionMenuView<
emitUpdate(menuName, this.state);
};

this.rootEl = this.editor._tiptapEditor.view.root;

// Setting capture=true ensures that any parent container of the editor that
// gets scrolled will trigger the scroll event. Scroll events do not bubble
// and so won't propagate to the document by default.
document.addEventListener("scroll", this.handleScroll, true);
this.rootEl.addEventListener("scroll", this.handleScroll, true);
}

handleScroll = () => {
if (this.state?.show) {
const decorationNode = document.querySelector(
const decorationNode = this.rootEl?.querySelector(
`[data-decoration-id="${this.pluginState!.decorationId}"]`
);
this.state.referencePos = decorationNode!.getBoundingClientRect();
Expand Down Expand Up @@ -79,7 +81,7 @@ class SuggestionMenuView<
return;
}

const decorationNode = document.querySelector(
const decorationNode = this.rootEl?.querySelector(
`[data-decoration-id="${this.pluginState!.decorationId}"]`
);

Expand All @@ -95,7 +97,7 @@ class SuggestionMenuView<
}

destroy() {
document.removeEventListener("scroll", this.handleScroll, true);
this.rootEl?.removeEventListener("scroll", this.handleScroll, true);
}

closeMenu = () => {
Expand Down
Loading
Loading