diff options
Diffstat (limited to 'src/client/views/nodes/formattedText')
5 files changed, 72 insertions, 72 deletions
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss index 3a1a72910..99b4a84fc 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.scss +++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss @@ -349,7 +349,7 @@ footnote::before { touch-action: none; span { font-family: inherit; - background-color: inherit; + // background-color: inherit; // intended to allow texts to inherit background from list container, but this prevents css highlights e.,g highlight text from others display: inline; // needs to be inline for search highlighting to appear // display: contents; // BUT needs to be 'contents' to avoid Chrome bug where extra space is added above and <ol> lists when inside a prosemirror span } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 99a2f4ab9..ba37c3265 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -65,6 +65,7 @@ import { FootnoteView } from './FootnoteView'; import './FormattedTextBox.scss'; import { findLinkMark, FormattedTextBoxComment } from './FormattedTextBoxComment'; import { buildKeymap, updateBullets } from './ProsemirrorExampleTransfer'; +// eslint-disable-next-line import/extensions import { removeMarkWithAttrs } from './prosemirrorPatches'; import { RichTextMenu, RichTextMenuPlugin } from './RichTextMenu'; import { RichTextRules } from './RichTextRules'; @@ -291,7 +292,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB }); }; AnchorMenu.Instance.Highlight = undoable((color: string) => { - this._editorView?.state && RichTextMenu.Instance?.setHighlight(color); + this._editorView?.state && RichTextMenu.Instance?.setFontField(color, 'fontHighlight'); return undefined; }, 'highlght text'); AnchorMenu.Instance.onMakeAnchor = () => this.getAnchor(true); @@ -637,8 +638,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB const pos = view.posAtCoords({ left: de.x, top: de.y })?.pos; pos && view.dispatch(view.state.tr.insert(pos, node)); added = !!pos; // pos will be null if you don't drop onto an actual text location - } catch (e) { - console.log('Drop failed', e); + } catch (err) { + console.log('Drop failed', err); added = false; } finally { this._inDrop = false; @@ -778,7 +779,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB this, e, this.sidebarMove, - (e, movement, isClick) => !isClick && batch.end(), + (moveEv, movement, isClick) => !isClick && batch.end(), () => { this.toggleSidebar(); batch.end(); @@ -1301,7 +1302,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB this._disposers.selected = reaction( () => this._props.rootSelected?.(), action(selected => { - // selected && setTimeout(() => this.prepareForTyping()); + this.prepareForTyping(); if (FormattedTextBox._globalHighlights.has('Bold Text')) { // eslint-disable-next-line operator-assignment this.layoutDoc[DocCss] = this.layoutDoc[DocCss] + 1; // css change happens outside of mobx/react, so this will notify anyone interested in the layout that it has changed @@ -1498,8 +1499,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size)))); this.tryUpdateDoc(true); // calling select() above will make isContentActive() true only after a render .. which means the selectAll() above won't write to the Document and the incomingValue will overwrite the selection with the non-updated data - } else if (curText && !FormattedTextBox.DontSelectInitialText) { - selectAll(this._editorView.state, this._editorView?.dispatch); + } else if (!FormattedTextBox.DontSelectInitialText) { + const mark = schema.marks.user_mark.create({ userid: ClientUtils.CurrentUserEmail(), modified: Math.floor(Date.now() / 1000) }); + selectAll(this._editorView.state, (tx: Transaction) => { + this._editorView?.dispatch(tx.deleteSelection().addStoredMark(mark)); + }); this.tryUpdateDoc(true); // calling select() above will make isContentActive() true only after a render .. which means the selectAll() above won't write to the Document and the incomingValue will overwrite the selection with the non-updated data } else { const $from = this._editorView.state.selection.anchor ? this._editorView.state.doc.resolve(this._editorView.state.selection.anchor - 1) : undefined; @@ -1526,17 +1530,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB // add user mark for any first character that was typed since the user mark that gets set in KeyPress won't have been called yet. prepareForTyping = () => { - if (!this._editorView) return; - const docDefaultMarks = [ - ...(Doc.UserDoc().fontColor !== 'transparent' && Doc.UserDoc().fontColor ? [schema.mark(schema.marks.pFontColor, { color: StrCast(Doc.UserDoc().fontColor) })] : []), - ...(Doc.UserDoc().fontStyle === 'italics' ? [schema.mark(schema.marks.em)] : []), - ...(Doc.UserDoc().textDecoration === 'underline' ? [schema.mark(schema.marks.underline)] : []), - ...(Doc.UserDoc().fontFamily ? [schema.mark(schema.marks.pFontFamily, { fontFamily: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontFamily) })] : []), - ...(Doc.UserDoc().fontSize ? [schema.mark(schema.marks.pFontSize, { fontSize: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontSize) })] : []), - ...(Doc.UserDoc().fontWeight === 'bold' ? [schema.mark(schema.marks.strong)] : []), - ...[schema.marks.user_mark.create({ userid: ClientUtils.CurrentUserEmail(), modified: Math.floor(Date.now() / 1000) })], - ]; - this._editorView?.dispatch(this._editorView?.state.tr.setStoredMarks(docDefaultMarks)); + if (this._editorView) { + const { text, paragraph } = schema.nodes; + const selNode = this._editorView.state.selection.$anchor.node(); + if (this._editorView.state.selection.from === 1 && this._editorView.state.selection.empty && [undefined, text, paragraph].includes(selNode?.type)) { + const docDefaultMarks = [schema.marks.user_mark.create({ userid: ClientUtils.CurrentUserEmail(), modified: Math.floor(Date.now() / 1000) })]; + this._editorView.state.selection.empty && this._editorView.state.selection.from === 1 && this._editorView?.dispatch(this._editorView?.state.tr.setStoredMarks(docDefaultMarks).removeStoredMark(schema.marks.pFontColor)); + } + } }; componentWillUnmount() { @@ -1601,10 +1602,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB const state = this.EditorView?.state; if (state && this.ProseRef?.children[0].className.includes('-focused') && this._props.isContentActive() && !e.button) { if (!state.selection.empty && !(state.selection instanceof NodeSelection)) this.setupAnchorMenu(); - let target = e.target as any; // hrefs are stored on the dataset of the <a> node that wraps the hyerlink <span> - for (let target = e.target as any; target && !target.dataset?.targethrefs; target = target.parentElement); - while (target && !target.dataset?.targethrefs) target = target.parentElement; - FormattedTextBoxComment.update(this, this.EditorView!, undefined, target?.dataset?.targethrefs, target?.dataset.linkdoc, target?.dataset.nopreview === 'true'); + let clickTarget = e.target as any; // hrefs are stored on the dataset of the <a> node that wraps the hyerlink <span> + for (let { target } = e as any; target && !target.dataset?.targethrefs; target = target.parentElement); + while (clickTarget && !clickTarget.dataset?.targethrefs) clickTarget = clickTarget.parentElement; + FormattedTextBoxComment.update(this, this.EditorView!, undefined, clickTarget?.dataset?.targethrefs, clickTarget?.dataset.linkdoc, clickTarget?.dataset.nopreview === 'true'); } }; @action @@ -1724,9 +1725,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB if (!(this.EditorView?.state.selection instanceof NodeSelection)) { this.autoLink(); if (this._editorView?.state.tr) { - const tr = stordMarks?.reduce((tr, m) => { - tr.addStoredMark(m); - return tr; + const tr = stordMarks?.reduce((tr2, m) => { + tr2.addStoredMark(m); + return tr2; }, this._editorView.state.tr); tr && this._editorView.dispatch(tr); } @@ -2038,7 +2039,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB }; _oldWheel: any; @computed get fontColor() { - return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color); + return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontColor); } @computed get fontSize() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontSize); diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts index 073ed91c3..5d448d40e 100644 --- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts +++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts @@ -7,7 +7,7 @@ import { liftTarget } from 'prosemirror-transform'; import { EditorView } from 'prosemirror-view'; import { ClientUtils } from '../../../../ClientUtils'; import { Utils } from '../../../../Utils'; -import { AclAdmin, AclAugment, AclEdit } from '../../../../fields/DocSymbols'; +import { AclAdmin, AclAugment, AclEdit, DocData } from '../../../../fields/DocSymbols'; import { GetEffectiveAcl } from '../../../../fields/util'; import { Docs } from '../../../documents/Documents'; import { RTFMarkup } from '../../../util/RTFMarkup'; @@ -48,11 +48,12 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any): KeyMa } const canEdit = (state: any) => { - switch (GetEffectiveAcl(props.TemplateDataDocument)) { + const permissions = GetEffectiveAcl(props.TemplateDataDocument ?? props.Document[DocData]); + switch (permissions) { case AclAugment: { const prevNode = state.selection.$cursor.nodeBefore; - const prevUser = !prevNode ? ClientUtils.CurrentUserEmail() : prevNode.marks[prevNode.marks.length - 1].attrs.userid; + const prevUser = !prevNode ? ClientUtils.CurrentUserEmail() : prevNode.marks.lastElement()?.attrs.userid; if (prevUser !== ClientUtils.CurrentUserEmail()) { return false; } @@ -278,7 +279,7 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any): KeyMa dispatch(updateBullets(tx, schema)); if (view.state.selection.$anchor.node(-1)?.type === schema.nodes.list_item) { // gets rid of an extra paragraph when joining two list items together. - joinBackward(view.state, (tx: Transaction) => view.dispatch(tx)); + joinBackward(view.state, (tx2: Transaction) => view.dispatch(tx2)); } }) ) { @@ -344,7 +345,7 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any): KeyMa !splitBlockKeepMarks(state, (tx3: Transaction) => { const tonode = tx3.selection.$to.node(); if (tx3.selection.to && tx3.doc.nodeAt(tx3.selection.to - 1)) { - const tx4 = tx3.setNodeMarkup(tx3.selection.to - 1, tonode.type, fromattrs, tonode.marks); + const tx4 = tx3.setNodeMarkup(tx3.selection.to - 1, tonode.type, fromattrs, tonode.marks).setStoredMarks(marks || []); dispatch(tx4); } @@ -365,7 +366,8 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any): KeyMa // Command to create a blank space bind('Space', () => { - if (props.TemplateDataDocument && ![AclAdmin, AclAugment, AclEdit].includes(GetEffectiveAcl(props.TemplateDataDocument))) return true; + const editDoc = props.TemplateDataDocument ?? props.Document[DocData]; + if (editDoc && ![AclAdmin, AclAugment, AclEdit].includes(GetEffectiveAcl(editDoc))) return true; return false; }); diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 6108383c2..6c12b9991 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -10,7 +10,6 @@ import { EditorView } from 'prosemirror-view'; import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { BoolCast, Cast, StrCast } from '../../../../fields/Types'; -import { numberRange } from '../../../../Utils'; import { DocServer } from '../../../DocServer'; import { LinkManager } from '../../../util/LinkManager'; import { SelectionManager } from '../../../util/SelectionManager'; @@ -147,12 +146,13 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> { const { activeHighlights } = active; const refDoc = SelectionManager.Views.lastElement()?.layoutDoc ?? Doc.UserDoc(); const refField = (pfx => (pfx ? pfx + '_' : ''))(SelectionManager.Views.lastElement()?.LayoutFieldKey); + const refVal = (field: string, dflt: string) => StrCast(refDoc[refField + field], StrCast(Doc.UserDoc()[field], dflt)); this._activeListType = this.getActiveListStyle(); this._activeAlignment = this.getActiveAlignment(); - this._activeFontFamily = !activeFamilies.length ? StrCast(this.TextView?.Document._text_fontFamily, StrCast(refDoc[refField + 'fontFamily'], 'Arial')) : activeFamilies.length === 1 ? String(activeFamilies[0]) : 'various'; - this._activeFontSize = !activeSizes.length ? StrCast(this.TextView?.Document.fontSize, StrCast(refDoc[refField + 'fontSize'], '10px')) : activeSizes[0]; - this._activeFontColor = !activeColors.length ? StrCast(this.TextView?.Document.fontColor, StrCast(refDoc[refField + 'fontColor'], 'black')) : activeColors.length > 0 ? String(activeColors[0]) : '...'; + this._activeFontFamily = !activeFamilies.length ? StrCast(this.TextView?.Document._text_fontFamily, refVal('fontFamily', 'Arial')) : activeFamilies.length === 1 ? String(activeFamilies[0]) : 'various'; + this._activeFontSize = !activeSizes.length ? StrCast(this.TextView?.Document.fontSize, refVal('fontSize', '10px')) : activeSizes[0]; + this._activeFontColor = !activeColors.length ? StrCast(this.TextView?.Document.fontColor, refVal('fontColor', 'black')) : activeColors.length > 0 ? String(activeColors[0]) : '...'; this._activeHighlightColor = !activeHighlights.length ? '' : activeHighlights.length > 0 ? String(activeHighlights[0]) : '...'; // update link in current selection @@ -161,12 +161,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> { setMark = (mark: Mark, state: EditorState, dispatch: any, dontToggle: boolean = false) => { if (mark) { - const liFirst = numberRange(state.selection.$from.depth + 1).find(i => state.selection.$from.node(i)?.type === state.schema.nodes.list_item); - const liTo = numberRange(state.selection.$to.depth + 1).find(i => state.selection.$to.node(i)?.type === state.schema.nodes.list_item); - const olFirst = numberRange(state.selection.$from.depth + 1).find(i => state.selection.$from.node(i)?.type === state.schema.nodes.ordered_list); - const nodeOl = (liFirst && liTo && state.selection.$from.node(liFirst) !== state.selection.$to.node(liTo) && olFirst) || (!liFirst && !liTo && olFirst); - const fromRange = numberRange(state.selection.from).reverse(); - const newPos = nodeOl ? fromRange.find(i => state.doc.nodeAt(i)?.type === state.schema.nodes.ordered_list) ?? state.selection.from : state.selection.from; + const newPos = state.selection.$anchor.node()?.type === schema.nodes.ordered_list ? state.selection.from : state.selection.from; const node = (state.selection as NodeSelection).node ?? (newPos >= 0 ? state.doc.nodeAt(newPos) : undefined); if (node?.type === schema.nodes.ordered_list || node?.type === schema.nodes.list_item) { const hasMark = node.marks.some(m => m.type === mark.type); @@ -174,18 +169,16 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> { const addAnyway = node.marks.filter(m => m.type === mark.type && Object.keys(m.attrs).some(akey => m.attrs[akey] !== mark.attrs[akey])); const markup = state.tr.setNodeMarkup(newPos, node.type, node.attrs, hasMark && !addAnyway ? otherMarks : [...otherMarks, mark]); dispatch(updateBullets(markup, state.schema)); - } else { - const state = this.view?.state; - if (state) { - const { tr } = state; - if (dontToggle) { - tr.addMark(state.selection.from, state.selection.to, mark); - dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(state.selection.from), tr.doc.resolve(state.selection.to)))); // bcz: need to redo the selection because ctrl-a selections disappear otherwise - } else { - toggleMark(mark.type, mark.attrs)(state, dispatch); - } + } else if (state) { + const { tr } = state; + if (dontToggle) { + tr.addMark(state.selection.from, state.selection.to, mark); + dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(state.selection.from), tr.doc.resolve(state.selection.to)))); // bcz: need to redo the selection because ctrl-a selections disappear otherwise + } else { + toggleMark(mark.type, mark.attrs)(state, dispatch); } } + this.updateMenu(this.view, undefined, undefined, this.layoutDoc); } }; @@ -242,7 +235,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> { m.type === state.schema.marks.pFontFamily && activeFamilies.add(m.attrs.fontFamily); m.type === state.schema.marks.pFontColor && activeColors.add(m.attrs.fontColor); m.type === state.schema.marks.pFontSize && activeSizes.add(m.attrs.fontSize); - m.type === state.schema.marks.pFontHighlight && activeHighlights.add(String(m.attrs.fontHigh)); + m.type === state.schema.marks.pFontHighlight && activeHighlights.add(String(m.attrs.fontHighlight)); }); } else if (SelectionManager.Views.some(dv => dv.ComponentView instanceof EquationBox)) { SelectionManager.Views.forEach(dv => StrCast(dv.Document._text_fontSize) && activeSizes.add(StrCast(dv.Document._text_fontSize))); @@ -359,18 +352,21 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> { setFontField = (value: string, fontField: 'fontSize' | 'fontFamily' | 'fontColor' | 'fontHighlight') => { if (this.view) { - if (this.view.state.selection.from === 1 && this.view.state.selection.empty && (!this.view.state.doc.nodeAt(1) || !this.view.state.doc.nodeAt(1)?.marks.some(m => m.type.name === value))) { + const { text, paragraph } = this.view.state.schema.nodes; + const selNode = this.view.state.selection.$anchor.node(); + if (this.view.state.selection.from === 1 && this.view.state.selection.empty && [undefined, text, paragraph].includes(selNode?.type)) { this.TextView.dataDoc[this.TextView.fieldKey + `_${fontField}`] = value; this.view.focus(); - } else { - const attrs: { [key: string]: string } = {}; - attrs[fontField] = value; - const fmark = this.view?.state.schema.marks['pF' + fontField.substring(1)].create(attrs); - this.setMark(fmark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(fmark)), true); - this.view.focus(); } - } else Doc.UserDoc()[fontField] = value; - this.updateMenu(this.view, undefined, this.props, this.layoutDoc); + const attrs: { [key: string]: string } = {}; + attrs[fontField] = value; + const fmark = this.view?.state.schema.marks['pF' + fontField.substring(1)].create(attrs); + this.setMark(fmark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(fmark)), true); + this.view.focus(); + } else { + Doc.UserDoc()[fontField] = value; + this.updateMenu(this.view, undefined, this.props, this.layoutDoc); + } }; // TODO: remove doesn't work diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts index 184487b7d..5bf942218 100644 --- a/src/client/views/nodes/formattedText/nodes_rts.ts +++ b/src/client/views/nodes/formattedText/nodes_rts.ts @@ -3,6 +3,7 @@ import { listItem, orderedList } from 'prosemirror-schema-list'; import { ParagraphNodeSpec, toParagraphDOM, getParagraphNodeAttrs } from './ParagraphNodeSpec'; import { DocServer } from '../../../DocServer'; import { Doc, Field, FieldType } from '../../../../fields/Doc'; +import { schema } from './schema_rts'; const blockquoteDOM: DOMOutputSpec = ['blockquote', 0]; const hrDOM: DOMOutputSpec = ['hr']; @@ -353,7 +354,7 @@ export const nodes: { [index: string]: NodeSpec } = { }, { style: 'list-style-type=disc', - getAttrs(dom: any) { + getAttrs() { return { mapStyle: 'bullet' }; }, }, @@ -373,10 +374,10 @@ export const nodes: { [index: string]: NodeSpec } = { ], toDOM(node: Node) { const map = node.attrs.bulletStyle ? node.attrs.mapStyle + node.attrs.bulletStyle : ''; - const fhigh = (found => (found ? `background-color: ${found};` : ''))(node.marks.find(m => m.type.name === 'marker')?.attrs.highlight); - const fsize = (found => (found ? `font-size: ${found};` : ''))(node.marks.find(m => m.type.name === 'pFontSize')?.attrs.fontSize); - const ffam = (found => (found ? `font-family: ${found};` : ''))(node.marks.find(m => m.type.name === 'pFontFamily')?.attrs.family); - const fcol = (found => (found ? `color: ${found};` : ''))(node.marks.find(m => m.type.name === 'pFontColor')?.attrs.color); + const fhigh = (found => (found ? `background-color: ${found};` : ''))(node.marks.find(m => m.type === schema.marks.pFontHighlight)?.attrs.fontHighlight); + const fsize = (found => (found ? `font-size: ${found};` : ''))(node.marks.find(m => m.type === schema.marks.pFontSize)?.attrs.fontSize); + const ffam = (found => (found ? `font-family: ${found};` : ''))(node.marks.find(m => m.type === schema.marks.pFontFamily)?.attrs.fontFamily); + const fcol = (found => (found ? `color: ${found};` : ''))(node.marks.find(m => m.type === schema.marks.pFontColor)?.attrs.fontColor); const marg = node.attrs.indent ? `margin-left: ${node.attrs.indent};` : ''; if (node.attrs.mapStyle === 'bullet') { return [ @@ -421,10 +422,10 @@ export const nodes: { [index: string]: NodeSpec } = { }, ], toDOM(node: Node) { - const fhigh = (found => (found ? `background-color: ${found};` : ''))(node.marks.find(m => m.type.name === 'marker')?.attrs.highlight); - const fsize = (found => (found ? `font-size: ${found};` : ''))(node.marks.find(m => m.type.name === 'pFontSize')?.attrs.fontSize); - const ffam = (found => (found ? `font-family: ${found};` : ''))(node.marks.find(m => m.type.name === 'pFontFamily')?.attrs.family); - const fcol = (found => (found ? `color: ${found};` : ''))(node.marks.find(m => m.type.name === 'pFontColor')?.attrs.color); + const fhigh = (found => (found ? `background-color: ${found};` : ''))(node.marks.find(m => m.type === schema.marks.pFontHighlight)?.attrs.fontHighlight); + const fsize = (found => (found ? `font-size: ${found};` : ''))(node.marks.find(m => m.type === schema.marks.pFontSize)?.attrs.fontSize); + const ffam = (found => (found ? `font-family: ${found};` : ''))(node.marks.find(m => m.type === schema.marks.pFontFamily)?.attrs.fontFamily); + const fcol = (found => (found ? `color: ${found};` : ''))(node.marks.find(m => m.type === schema.marks.pFontColor)?.attrs.fontColor); const map = node.attrs.bulletStyle ? node.attrs.mapStyle + node.attrs.bulletStyle : ''; return [ 'li', |
