From 4791f95d6be68e590d0a80689d89be4c05e9ffc3 Mon Sep 17 00:00:00 2001 From: vellichora Date: Tue, 7 Jan 2020 06:43:26 -0500 Subject: starting integrating brush tool into richtextmenu --- src/client/util/RichTextMenu.scss | 10 +++ src/client/util/RichTextMenu.tsx | 137 +++++++++++++++++++++++++++++++++++-- src/client/views/AntimodeMenu.scss | 2 +- src/client/views/AntimodeMenu.tsx | 12 ++-- 4 files changed, 150 insertions(+), 11 deletions(-) create mode 100644 src/client/util/RichTextMenu.scss (limited to 'src') diff --git a/src/client/util/RichTextMenu.scss b/src/client/util/RichTextMenu.scss new file mode 100644 index 000000000..f14703006 --- /dev/null +++ b/src/client/util/RichTextMenu.scss @@ -0,0 +1,10 @@ +.button-dropdown-wrapper { + position: relative; + + .dropdown { + position: absolute; + top: 30px; + left: 0; + background-color: black; + } +} \ No newline at end of file diff --git a/src/client/util/RichTextMenu.tsx b/src/client/util/RichTextMenu.tsx index 6b6a2620e..fa65adca5 100644 --- a/src/client/util/RichTextMenu.tsx +++ b/src/client/util/RichTextMenu.tsx @@ -5,10 +5,10 @@ import { observer } from "mobx-react"; import { Mark, MarkType, Node as ProsNode, NodeType, ResolvedPos, Schema } from "prosemirror-model"; import { schema } from "./RichTextSchema"; import { EditorView } from "prosemirror-view"; -import { EditorState, NodeSelection } from "prosemirror-state"; +import { EditorState, NodeSelection, TextSelection } from "prosemirror-state"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { IconProp, library } from '@fortawesome/fontawesome-svg-core'; -import { faBold, faItalic, faUnderline, faStrikethrough, faSubscript, faSuperscript, faIndent } from "@fortawesome/free-solid-svg-icons"; +import { faBold, faItalic, faUnderline, faStrikethrough, faSubscript, faSuperscript, faIndent, faEyeDropper, faCaretDown } from "@fortawesome/free-solid-svg-icons"; import { MenuItem, Dropdown } from "prosemirror-menu"; import { updateBullets } from "./ProsemirrorExampleTransfer"; import { FieldViewProps } from "../views/nodes/FieldView"; @@ -16,9 +16,10 @@ import { NumCast } from "../../new_fields/Types"; import { FormattedTextBoxProps } from "../views/nodes/FormattedTextBox"; import { unimplementedFunction } from "../../Utils"; import { wrapInList } from "prosemirror-schema-list"; +import "./RichTextMenu.scss"; const { toggleMark, setBlockType } = require("prosemirror-commands"); -library.add(faBold, faItalic, faUnderline, faStrikethrough, faSuperscript, faSubscript, faIndent); +library.add(faBold, faItalic, faUnderline, faStrikethrough, faSuperscript, faSubscript, faIndent, faEyeDropper, faCaretDown); @observer export default class RichTextMenu extends AntimodeMenu { @@ -31,6 +32,9 @@ export default class RichTextMenu extends AntimodeMenu { @observable private activeFontFamily: string = ""; @observable private activeListType: string = ""; + @observable private brushIsEmpty: boolean = true; + @observable private brushMarks: Set = new Set(); + constructor(props: Readonly<{}>) { super(props); RichTextMenu.Instance = this; @@ -121,6 +125,13 @@ export default class RichTextMenu extends AntimodeMenu { return styles; } + getMarksInSelection(state: EditorState) { + const found = new Set(); + const { from, to } = state.selection as TextSelection; + state.doc.nodesBetween(from, to, (node) => node.marks?.forEach(m => found.add(m))); + return found; + } + destroy() { console.log("destroy"); } @@ -142,7 +153,7 @@ export default class RichTextMenu extends AntimodeMenu { } return ( - ); @@ -259,6 +270,123 @@ export default class RichTextMenu extends AntimodeMenu { return true; } + createBrushButton() { + const self = this; + function onClick(e: React.PointerEvent) { + console.log("clicked button"); + // dom.addEventListener("pointerdown", e => { + e.preventDefault(); + self.view && self.view.focus(); + // if (dom.contains(e.target as Node)) { + e.stopPropagation(); + // command(this.view.state, this.view.dispatch, this.view); + // } + // }); + + self.view && self.brush_function(self.view.state, self.view.dispatch); + + // // update dropdown with marks + // const newBrushDropdowndom = self.createBrushDropdown().render(self.view).dom; + // self._brushDropdownDom && self.tooltip.replaceChild(newBrushDropdowndom, self._brushDropdownDom); + // self._brushDropdownDom = newBrushDropdowndom; + } + + let label = "Stored marks: "; + if (this.brushMarks && this.brushMarks.size > 0) { + this.brushMarks.forEach((mark: Mark) => { + const markType = mark.type; + label += markType.name; + label += ", "; + }); + label = label.substring(0, label.length - 2); + } else { + label = "No marks are currently stored"; + } + + return ( +
+ + +
+

{label}

+ + {/* */} +
+
+ ); + } + + @action + clearBrush() { + this.brushIsEmpty = true; + this.brushMarks = new Set(); + } + + @action + brush_function(state: EditorState, dispatch: any) { + if (!this.view) return; + + if (this.brushIsEmpty) { + const selected_marks = this.getMarksInSelection(this.view.state); + // if (this._brushdom) { + if (selected_marks.size >= 0) { + this.brushMarks = selected_marks; + // const newbrush = this.createBrush(true).render(this.view).dom; + // this.tooltip.replaceChild(newbrush, this._brushdom); + // this._brushdom = newbrush; + this.brushIsEmpty = !this.brushIsEmpty; + // TooltipTextMenuManager.Instance._brushIsEmpty = !TooltipTextMenuManager.Instance._brushIsEmpty; + } + // } + } + else { + const { from, to, $from } = this.view.state.selection; + // if (this._brushdom) { + if (!this.view.state.selection.empty && $from && $from.nodeAfter) { + if (this.brushMarks && to - from > 0) { + this.view.dispatch(this.view.state.tr.removeMark(from, to)); + Array.from(this.brushMarks).filter(m => m.type !== schema.marks.user_mark).forEach((mark: Mark) => { + this.setMark(mark, this.view!.state, this.view!.dispatch); + }); + } + } + else { + // const newbrush = this.createBrush(false).render(this.view).dom; + // this.tooltip.replaceChild(newbrush, this._brushdom); + // this._brushdom = newbrush; + this.brushIsEmpty = !this.brushIsEmpty; + // TooltipTextMenuManager.Instance._brushIsEmpty = !TooltipTextMenuManager.Instance._brushIsEmpty; + } + // } + } + console.log("brush marks are ", this.brushMarks); + } + + // createColorButton() { + // const self = this; + // function onClick(e: React.PointerEvent) { + // console.log("clicked button"); + // // dom.addEventListener("pointerdown", e => { + // e.preventDefault(); + // self.view && self.view.focus(); + // // if (dom.contains(e.target as Node)) { + // e.stopPropagation(); + // // command(this.view.state, this.view.dispatch, this.view); + // // } + // // }); + // self.view && command && command(self.view!.state, self.view!.dispatch, self.view); + // self.view && onclick && onclick(self.view!.state, self.view!.dispatch, self.view); + // } + + // return ( + // + // ); + // } + reference_node(pos: ResolvedPos): ProsNode | null { if (!this.view) return null; @@ -354,6 +482,7 @@ export default class RichTextMenu extends AntimodeMenu { this.createButton("strikethrough", "Strikethrough", toggleMark(schema.marks.strikethrough)), this.createButton("superscript", "Superscript", toggleMark(schema.marks.superscript)), this.createButton("subscript", "Subscript", toggleMark(schema.marks.subscript)), + this.createBrushButton(), this.createButton("indent", "Summarize", undefined, this.insertSummarizer), this.createMarksDropdown(this.activeFontSize, fontSizeOptions), this.createMarksDropdown(this.activeFontFamily, fontFamilyOptions), diff --git a/src/client/views/AntimodeMenu.scss b/src/client/views/AntimodeMenu.scss index f3da5f284..a45f3346a 100644 --- a/src/client/views/AntimodeMenu.scss +++ b/src/client/views/AntimodeMenu.scss @@ -5,7 +5,7 @@ background: #323232; box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.25); border-radius: 0px 6px 6px 6px; - overflow: hidden; + // overflow: hidden; display: flex; .antimodeMenu-button { diff --git a/src/client/views/AntimodeMenu.tsx b/src/client/views/AntimodeMenu.tsx index 408df8bc2..2e9d29ef9 100644 --- a/src/client/views/AntimodeMenu.tsx +++ b/src/client/views/AntimodeMenu.tsx @@ -62,12 +62,12 @@ export default abstract class AntimodeMenu extends React.Component { @action protected pointerLeave = (e: React.PointerEvent) => { - if (!this.Pinned) { - this._transition = "opacity 0.5s"; - this._transitionDelay = "1s"; - this._opacity = 0.2; - setTimeout(() => this.fadeOut(false), 3000); - } + // if (!this.Pinned) { + // this._transition = "opacity 0.5s"; + // this._transitionDelay = "1s"; + // this._opacity = 0.2; + // setTimeout(() => this.fadeOut(false), 3000); + // } } @action -- cgit v1.2.3-70-g09d2