Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,10 @@ https://github.com/ProseMirror/prosemirror-tables/blob/master/demo/index.html
.ProseMirror-active-search-match {
background-color: #ff6a0054;
}

.ProseMirror span::selection {
.ProseMirror span.sd-custom-selection::selection {
background: transparent;
}
.sd-custom-selection {
background-color: #d9d9d9;
border-radius: 0.1em;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@
.sd-editor-comment-highlight:hover {
background-color: #1354ff55;
}

.sd-editor-comment-highlight.sd-custom-selection {
background-color: #d6c0c6 !important;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@

/* temporary fix */
.sd-editor-list-item-node-view .sd-custom-selection {
font-size: inherit!important;
font-size: inherit !important;
}
4 changes: 0 additions & 4 deletions packages/super-editor/src/assets/styles/layout/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,3 @@
a {
text-decoration: auto;
}

.sd-custom-selection {
background-color: #accef7;
}
19 changes: 1 addition & 18 deletions packages/super-editor/src/components/SuperEditor.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup>
import 'tippy.js/dist/tippy.css';
import { NSkeleton } from 'naive-ui';
import { ref, onMounted, onBeforeUnmount, shallowRef, reactive, markRaw, onDeactivated } from 'vue';
import { ref, onMounted, onBeforeUnmount, shallowRef, reactive, markRaw } from 'vue';
import { Editor } from '@/index.js';
import { getStarterExtensions } from '@extensions/index.js';
import SlashMenu from './slash-menu/SlashMenu.vue';
Expand Down Expand Up @@ -223,26 +223,9 @@ const handleSuperEditorClick = (event) => {
}
};

const handleClickOutside = (event) => {
const pmElement = editorElem.value?.querySelector('.ProseMirror');
const isInsideEditor = pmElement?.contains(event.target);

if (!isInsideEditor) {
editor.value?.setOptions({
focusTarget: event.target,
});
}
};

onMounted(() => {
initializeData();
if (props.options?.suppressSkeletonLoader || !props.options?.collaborationProvider) editorReady.value = true;

document.addEventListener('mousedown', handleClickOutside);
});

onDeactivated(() => {
document.removeEventListener('mousedown', handleClickOutside);
});

const handleMarginClick = (event) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,53 +1,110 @@
import { Extension } from '@core/Extension.js';
import { AllSelection, Plugin, PluginKey, TextSelection } from 'prosemirror-state';
import { Plugin, PluginKey, TextSelection } from 'prosemirror-state';
import { Decoration, DecorationSet } from 'prosemirror-view';

export const CustomSelectionPluginKey = new PluginKey('CustomSelection');

const handleClickOutside = (event, editor) => {
const editorElem = editor?.options?.element;
if (!editorElem) return;

const isInsideEditor = editorElem?.contains(event.target);

if (!isInsideEditor) {
editor.setOptions({
focusTarget: event.target,
});
} else {
editor.setOptions({
focusTarget: null,
});
}
};

function getFocusMeta(tr) {
return tr.getMeta(CustomSelectionPluginKey);
}

function setFocusMeta(tr, value) {
return tr.setMeta(CustomSelectionPluginKey, value);
}

function getFocusState(state) {
return CustomSelectionPluginKey.getState(state);
}

export const CustomSelection = Extension.create({
name: 'customSelection',

addPmPlugins() {
const editor = this.editor;
const customSelectionPlugin = new Plugin({
key: CustomSelectionPluginKey,

state: {
init() {
return DecorationSet.empty;
init: () => false,
apply: (tr, value) => {
return getFocusMeta(tr) ?? value;
},
apply(tr, oldDecorationSet, oldState, newState) {
const sel = tr.selection;
let newDecos = [];

// Only apply to text selections or whole doc selections
if (sel.from !== sel.to && (tr.doc.resolve(sel.from).parent.isTextblock || sel instanceof AllSelection)) {
newDecos.push(
Decoration.inline(sel.from, sel.to, {
class: 'sd-custom-selection',
}),
);
}
},
view: () => {
document?.addEventListener('mousedown', (event) => handleClickOutside(event, editor));

return DecorationSet.create(newState.doc, newDecos);
},
return {
destroy: () => {
document?.removeEventListener('mouseout', handleClickOutside);
},
};
},
props: {
handleDOMEvents: {
focusout: (view, event) => {
const isDropDownOption = this.editor.options.focusTarget?.getAttribute('data-dropdown-option');
if (document.activeElement && !event.relatedTarget && !view.state.selection.empty && !isDropDownOption) {
mousedown: (view) => {
const { selection } = view.state;
const isToolbarButton = this.editor.options.focusTarget?.closest('.toolbar-button');

if (!isToolbarButton) {
view.dispatch(setFocusMeta(view.state.tr, false));
}
if (!selection.empty) {
this.editor.setOptions({
lastSelection: view.state.selection,
});
const clearSelectionTr = view.state.tr.setSelection(TextSelection.create(view.state.doc, 0));

view.dispatch(clearSelectionTr);
}
return false;
},
focus: (view) => {
const isToolbarButton = this.editor.options.focusTarget?.closest('.toolbar-button');

if (isToolbarButton) {
return;
}

view.dispatch(setFocusMeta(view.state.tr, false));
},

blur: (view) => {
const isToolbarButton = this.editor.options.focusTarget?.closest('.toolbar-button');

if (isToolbarButton) {
view.dispatch(setFocusMeta(view.state.tr, true));
return;
}

view.dispatch(setFocusMeta(view.state.tr, false));
},
},
decorations(state) {
return CustomSelectionPluginKey.getState(state);
decorations: (state) => {
const { selection, doc } = state;

if (selection.empty || !getFocusState(state)) {
return null;
}

return DecorationSet.create(doc, [
Decoration.inline(selection.from, selection.to, {
class: 'sd-custom-selection',
}),
]);
},
},
});
Expand Down
Loading