draftjs-conductor
Advanced tools
Comparing version 2.2.0 to 3.0.0
@@ -18,9 +18,6 @@ 'use strict'; | ||
// @flow | ||
/*:: import type { BlockNode } from "draft-js/lib/BlockNode";*/ | ||
// Default maximum block depth supported by Draft.js CSS. | ||
var DRAFT_DEFAULT_MAX_DEPTH = 4; // Default depth class prefix from Draft.js CSS. | ||
var DRAFT_DEFAULT_DEPTH_CLASS = "public-DraftStyleDefault-depth"; | ||
const DRAFT_DEFAULT_MAX_DEPTH = 4; | ||
// Default depth class prefix from Draft.js CSS. | ||
const DRAFT_DEFAULT_DEPTH_CLASS = "public-DraftStyleDefault-depth"; | ||
/** | ||
@@ -30,4 +27,3 @@ * Matching the counter styles of Google Docs and Draft.js v0.11. | ||
*/ | ||
var COUNTER_STYLES = ["decimal", "lower-alpha", "lower-roman"]; | ||
const COUNTER_STYLES = ["decimal", "lower-alpha", "lower-roman"]; | ||
/** | ||
@@ -41,25 +37,22 @@ * Generates CSS styles for list items, for a given selector pattern. | ||
*/ | ||
var generateListNestingStyles = function generateListNestingStyles(selectorPrefix | ||
/*: string*/ | ||
, minDepth | ||
/*: number*/ | ||
, maxDepth | ||
/*: number*/ | ||
, counterStyles | ||
/*: string[]*/ | ||
) { | ||
var styles = "\n.".concat(selectorPrefix, "1.public-DraftStyleDefault-orderedListItem::before { content: counter(ol1, ").concat(counterStyles[1 % counterStyles.length], ") \". \"}\n.").concat(selectorPrefix, "2.public-DraftStyleDefault-orderedListItem::before { content: counter(ol2, ").concat(counterStyles[2 % counterStyles.length], ") \". \"}\n.").concat(selectorPrefix, "4.public-DraftStyleDefault-orderedListItem::before { content: counter(ol4, ").concat(counterStyles[4 % counterStyles.length], ") \". \"}\n"); | ||
for (var depth = minDepth; depth <= maxDepth; depth++) { | ||
var d = String(depth); | ||
var prefix = "".concat(selectorPrefix).concat(d); | ||
var counter = "ol".concat(d); | ||
var counterStyle = counterStyles[depth % counterStyles.length]; | ||
var margin = 1.5 * (depth + 1); | ||
var m = String(margin); | ||
styles += "\n.".concat(prefix, ".public-DraftStyleDefault-listLTR { margin-left: ").concat(m, "em; }\n.").concat(prefix, ".public-DraftStyleDefault-listRTL { margin-right: ").concat(m, "em; }\n.").concat(prefix, ".public-DraftStyleDefault-orderedListItem::before { content: counter(").concat(counter, ", ").concat(counterStyle, ") '. '; counter-increment: ").concat(counter, "; }\n.").concat(prefix, ".public-DraftStyleDefault-reset { counter-reset: ").concat(counter, "; }"); | ||
} | ||
return styles; | ||
const generateListNestingStyles = (selectorPrefix, minDepth, maxDepth, counterStyles) => { | ||
let styles = ` | ||
.${selectorPrefix}1.public-DraftStyleDefault-orderedListItem::before { content: counter(ol1, ${counterStyles[1 % counterStyles.length]}) ". "} | ||
.${selectorPrefix}2.public-DraftStyleDefault-orderedListItem::before { content: counter(ol2, ${counterStyles[2 % counterStyles.length]}) ". "} | ||
.${selectorPrefix}4.public-DraftStyleDefault-orderedListItem::before { content: counter(ol4, ${counterStyles[4 % counterStyles.length]}) ". "} | ||
`; | ||
for (let depth = minDepth; depth <= maxDepth; depth++) { | ||
const d = String(depth); | ||
const prefix = `${selectorPrefix}${d}`; | ||
const counter = `ol${d}`; | ||
const counterStyle = counterStyles[depth % counterStyles.length]; | ||
const margin = 1.5 * (depth + 1); | ||
const m = String(margin); | ||
styles += ` | ||
.${prefix}.public-DraftStyleDefault-listLTR { margin-left: ${m}em; } | ||
.${prefix}.public-DraftStyleDefault-listRTL { margin-right: ${m}em; } | ||
.${prefix}.public-DraftStyleDefault-orderedListItem::before { content: counter(${counter}, ${counterStyle}) '. '; counter-increment: ${counter}; } | ||
.${prefix}.public-DraftStyleDefault-reset { counter-reset: ${counter}; }`; | ||
} | ||
return styles; | ||
}; | ||
@@ -70,16 +63,4 @@ /** | ||
*/ | ||
var getListNestingStyles = function getListNestingStyles(maxDepth | ||
/*: number*/ | ||
) { | ||
var minDepth | ||
/*: number*/ | ||
= arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DRAFT_DEFAULT_MAX_DEPTH + 1; | ||
var selectorPrefix | ||
/*: string*/ | ||
= arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : DRAFT_DEFAULT_DEPTH_CLASS; | ||
var counterStyles | ||
/*: string[]*/ | ||
= arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : COUNTER_STYLES; | ||
return generateListNestingStyles(selectorPrefix, minDepth, maxDepth, counterStyles); | ||
const getListNestingStyles = (maxDepth, minDepth = DRAFT_DEFAULT_MAX_DEPTH + 1, selectorPrefix = DRAFT_DEFAULT_DEPTH_CLASS, counterStyles = COUNTER_STYLES) => { | ||
return generateListNestingStyles(selectorPrefix, minDepth, maxDepth, counterStyles); | ||
}; | ||
@@ -91,109 +72,87 @@ /** | ||
*/ | ||
var blockDepthStyleFn = function blockDepthStyleFn(block | ||
/*: BlockNode*/ | ||
) { | ||
var depth = block.getDepth(); | ||
return depth > DRAFT_DEFAULT_MAX_DEPTH ? "".concat(DRAFT_DEFAULT_DEPTH_CLASS).concat(String(depth)) : ""; | ||
const blockDepthStyleFn = (block) => { | ||
const depth = block.getDepth(); | ||
return depth > DRAFT_DEFAULT_MAX_DEPTH | ||
? `${DRAFT_DEFAULT_DEPTH_CLASS}${String(depth)}` | ||
: ""; | ||
}; | ||
// @flow | ||
/*:: import type { ElementRef } from "react";*/ | ||
/*:: import type { Editor, EditorState as EditorStateType } from "draft-js";*/ | ||
// @ts-expect-error | ||
// Custom attribute to store Draft.js content in the HTML clipboard. | ||
var FRAGMENT_ATTR = "data-draftjs-conductor-fragment"; | ||
var DRAFT_DECORATOR = '[data-contents="true"] [contenteditable="false"]'; // Checks whether the selection is inside a decorator or not. | ||
const FRAGMENT_ATTR = "data-draftjs-conductor-fragment"; | ||
const DRAFT_DECORATOR = '[data-contents="true"] [contenteditable="false"]'; | ||
// Checks whether the selection is inside a decorator or not. | ||
// This is important to change the copy-cut behavior accordingly. | ||
var isSelectionInDecorator = function isSelectionInDecorator(selection | ||
/*: Selection*/ | ||
) { | ||
var anchorNode = selection.anchorNode, | ||
focusNode = selection.focusNode; | ||
if (!anchorNode || !focusNode) { | ||
return false; | ||
} | ||
var anchor = anchorNode instanceof Element ? anchorNode : anchorNode.parentElement; | ||
var focus = focusNode instanceof Element ? focusNode : focusNode.parentElement; | ||
var anchorDecorator = anchor && anchor.closest(DRAFT_DECORATOR); | ||
var focusDecorator = focus && focus.closest(DRAFT_DECORATOR); | ||
return anchorDecorator && focusDecorator && (anchorDecorator.contains(focusDecorator) || focusDecorator.contains(anchorDecorator)); | ||
}; // Get clipboard content from the selection like Draft.js would. | ||
var getSelectedContent = function getSelectedContent(editorState | ||
/*: EditorStateType*/ | ||
, editorRoot | ||
/*: HTMLElement*/ | ||
) { | ||
var _getDraftEditorSelect = getDraftEditorSelection__default['default'](editorState, editorRoot), | ||
selectionState = _getDraftEditorSelect.selectionState; | ||
var fragment = getContentStateFragment__default['default'](editorState.getCurrentContent(), selectionState); // If the selection contains no content (according to Draft.js), use the default browser behavior. | ||
// This happens when selecting text that's within contenteditable=false blocks in Draft.js. | ||
// See https://github.com/thibaudcolas/draftjs-conductor/issues/12. | ||
var isEmpty = fragment.every(function (block) { | ||
return block.getText().length === 0; | ||
}); | ||
return isEmpty ? null : fragment; | ||
}; // Overrides the default copy/cut behavior, adding the serialised Draft.js content to the clipboard data. | ||
const isSelectionInDecorator = (selection) => { | ||
const { anchorNode, focusNode } = selection; | ||
if (!anchorNode || !focusNode) { | ||
return false; | ||
} | ||
const anchor = anchorNode instanceof Element ? anchorNode : anchorNode.parentElement; | ||
const focus = focusNode instanceof Element ? focusNode : focusNode.parentElement; | ||
const anchorDecorator = anchor && anchor.closest(DRAFT_DECORATOR); | ||
const focusDecorator = focus && focus.closest(DRAFT_DECORATOR); | ||
return (anchorDecorator && | ||
focusDecorator && | ||
(anchorDecorator.contains(focusDecorator) || | ||
focusDecorator.contains(anchorDecorator))); | ||
}; | ||
// Get clipboard content from the selection like Draft.js would. | ||
const getSelectedContent = (editorState, editorRoot) => { | ||
const { selectionState } = getDraftEditorSelection__default["default"](editorState, editorRoot); | ||
const fragment = getContentStateFragment__default["default"](editorState.getCurrentContent(), selectionState); | ||
// If the selection contains no content (according to Draft.js), use the default browser behavior. | ||
// This happens when selecting text that's within contenteditable=false blocks in Draft.js. | ||
// See https://github.com/thibaudcolas/draftjs-conductor/issues/12. | ||
const isEmpty = fragment.every((block) => { | ||
return block.getText().length === 0; | ||
}); | ||
return isEmpty ? null : fragment; | ||
}; | ||
// Overrides the default copy/cut behavior, adding the serialised Draft.js content to the clipboard data. | ||
// See also https://github.com/basecamp/trix/blob/62145978f352b8d971cf009882ba06ca91a16292/src/trix/controllers/input_controller.coffee#L415-L422 | ||
// We serialise the editor content within HTML, not as a separate mime type, because Draft.js only allows access | ||
// to HTML in its paste event handler. | ||
var draftEditorCopyCutListener = function draftEditorCopyCutListener(ref | ||
/*: ElementRef<Editor>*/ | ||
, e | ||
/*: SyntheticClipboardEvent<>*/ | ||
) { | ||
var selection = window.getSelection(); // Completely skip event handling if clipboardData is not supported (IE11 is out). | ||
// Also skip if there is no selection ranges. | ||
// Or if the selection is fully within a decorator. | ||
if (!e.clipboardData || selection.rangeCount === 0 || isSelectionInDecorator(selection)) { | ||
return; | ||
} | ||
var fragment = getSelectedContent(ref._latestEditorState, ref.editor); // Override the default behavior if there is selected content. | ||
if (fragment) { | ||
var content = draftJs.ContentState.createFromBlockArray(fragment.toArray()); | ||
var serialisedContent = JSON.stringify(draftJs.convertToRaw(content)); // Create a temporary element to store the selection’s HTML. | ||
// See also Rangy's implementation: https://github.com/timdown/rangy/blob/1e55169d2e4d1d9458c2a87119addf47a8265276/src/core/domrange.js#L515-L520. | ||
var fragmentElt = document.createElement("div"); // Modern browsers only support a single range. | ||
fragmentElt.appendChild(selection.getRangeAt(0).cloneContents()); | ||
fragmentElt.setAttribute(FRAGMENT_ATTR, serialisedContent); // We set the style property to replicate the browser's behavior of inline styles in rich text copy-paste. | ||
// In Draft.js, this is important for line breaks to be interpreted correctly when pasted into another word processor. | ||
// See https://github.com/facebook/draft-js/blob/a1f4593d8fa949954053e5d5840d33ce1d1082c6/src/component/base/DraftEditor.react.js#L328. | ||
fragmentElt.setAttribute("style", "white-space: pre-wrap;"); | ||
e.clipboardData.setData("text/plain", selection.toString()); | ||
e.clipboardData.setData("text/html", fragmentElt.outerHTML); | ||
e.preventDefault(); | ||
} | ||
const draftEditorCopyCutListener = ( | ||
// @ts-expect-error | ||
ref, e) => { | ||
const selection = window.getSelection(); | ||
// Completely skip event handling if clipboardData is not supported (IE11 is out). | ||
// Also skip if there is no selection ranges. | ||
// Or if the selection is fully within a decorator. | ||
if (!e.clipboardData || | ||
selection.rangeCount === 0 || | ||
isSelectionInDecorator(selection)) { | ||
return; | ||
} | ||
// @ts-expect-error | ||
const fragment = getSelectedContent(ref._latestEditorState, ref.editor); | ||
// Override the default behavior if there is selected content. | ||
if (fragment) { | ||
const content = draftJs.ContentState.createFromBlockArray(fragment.toArray()); | ||
const serialisedContent = JSON.stringify(draftJs.convertToRaw(content)); | ||
// Create a temporary element to store the selection’s HTML. | ||
// See also Rangy's implementation: https://github.com/timdown/rangy/blob/1e55169d2e4d1d9458c2a87119addf47a8265276/src/core/domrange.js#L515-L520. | ||
const fragmentElt = document.createElement("div"); | ||
// Modern browsers only support a single range. | ||
fragmentElt.appendChild(selection.getRangeAt(0).cloneContents()); | ||
fragmentElt.setAttribute(FRAGMENT_ATTR, serialisedContent); | ||
// We set the style property to replicate the browser's behavior of inline styles in rich text copy-paste. | ||
// In Draft.js, this is important for line breaks to be interpreted correctly when pasted into another word processor. | ||
// See https://github.com/facebook/draft-js/blob/a1f4593d8fa949954053e5d5840d33ce1d1082c6/src/component/base/DraftEditor.react.js#L328. | ||
fragmentElt.setAttribute("style", "white-space: pre-wrap;"); | ||
e.clipboardData.setData("text/plain", selection.toString()); | ||
e.clipboardData.setData("text/html", fragmentElt.outerHTML); | ||
e.preventDefault(); | ||
} | ||
}; | ||
var onDraftEditorCopy = function onDraftEditorCopy(editor | ||
/*: Editor*/ | ||
, e | ||
/*: SyntheticClipboardEvent<>*/ | ||
) { | ||
draftEditorCopyCutListener(editor, e); | ||
editOnCopy__default['default'](editor, e); | ||
const onDraftEditorCopy = (editor, e) => { | ||
// @ts-expect-error | ||
draftEditorCopyCutListener(editor, e); | ||
editOnCopy__default["default"](editor, e); | ||
}; | ||
var onDraftEditorCut = function onDraftEditorCut(editor | ||
/*: Editor*/ | ||
, e | ||
/*: SyntheticClipboardEvent<>*/ | ||
) { | ||
draftEditorCopyCutListener(editor, e); | ||
editOnCut__default['default'](editor, e); | ||
const onDraftEditorCut = (editor, e) => { | ||
// @ts-expect-error | ||
draftEditorCopyCutListener(editor, e); | ||
editOnCut__default["default"](editor, e); | ||
}; | ||
@@ -203,17 +162,15 @@ /** | ||
*/ | ||
var registerCopySource = function registerCopySource(ref | ||
/*: ElementRef<Editor>*/ | ||
) { | ||
var editorElt = ref.editor; | ||
var onCopyCut = draftEditorCopyCutListener.bind(null, ref); | ||
editorElt.addEventListener("copy", onCopyCut); | ||
editorElt.addEventListener("cut", onCopyCut); | ||
return { | ||
unregister() { | ||
editorElt.removeEventListener("copy", onCopyCut); | ||
editorElt.removeEventListener("cut", onCopyCut); | ||
} | ||
}; | ||
// @ts-expect-error | ||
const registerCopySource = (ref) => { | ||
// @ts-expect-error | ||
const editorElt = ref.editor; | ||
const onCopyCut = draftEditorCopyCutListener.bind(null, ref); | ||
editorElt.addEventListener("copy", onCopyCut); | ||
editorElt.addEventListener("cut", onCopyCut); | ||
return { | ||
unregister() { | ||
editorElt.removeEventListener("copy", onCopyCut); | ||
editorElt.removeEventListener("cut", onCopyCut); | ||
}, | ||
}; | ||
}; | ||
@@ -224,31 +181,25 @@ /** | ||
*/ | ||
var getDraftEditorPastedContent = function getDraftEditorPastedContent(html | ||
/*: ?string*/ | ||
) { | ||
// Plain-text pastes are better handled by Draft.js. | ||
if (html === "" || typeof html === "undefined" || html === null) { | ||
const getDraftEditorPastedContent = (html) => { | ||
// Plain-text pastes are better handled by Draft.js. | ||
if (html === "" || typeof html === "undefined" || html === null) { | ||
return null; | ||
} | ||
const doc = new DOMParser().parseFromString(html, "text/html"); | ||
const fragmentElt = doc.querySelector(`[${FRAGMENT_ATTR}]`); | ||
// Handle the paste if it comes from draftjs-conductor. | ||
if (fragmentElt) { | ||
const fragmentAttr = fragmentElt.getAttribute(FRAGMENT_ATTR); | ||
let rawContent; | ||
try { | ||
// If JSON parsing fails, leave paste handling to Draft.js. | ||
// There is no reason for this to happen, unless the clipboard was altered somehow. | ||
// @ts-expect-error | ||
rawContent = JSON.parse(fragmentAttr); | ||
} | ||
catch (error) { | ||
return null; | ||
} | ||
return draftJs.convertFromRaw(rawContent); | ||
} | ||
return null; | ||
} | ||
var doc = new DOMParser().parseFromString(html, "text/html"); | ||
var fragmentElt = doc.querySelector("[".concat(FRAGMENT_ATTR, "]")); // Handle the paste if it comes from draftjs-conductor. | ||
if (fragmentElt) { | ||
var fragmentAttr = fragmentElt.getAttribute(FRAGMENT_ATTR); | ||
var rawContent; | ||
try { | ||
// If JSON parsing fails, leave paste handling to Draft.js. | ||
// There is no reason for this to happen, unless the clipboard was altered somehow. | ||
// $FlowFixMe | ||
rawContent = JSON.parse(fragmentAttr); | ||
} catch (error) { | ||
return null; | ||
} | ||
return draftJs.convertFromRaw(rawContent); | ||
} | ||
return null; | ||
}; | ||
@@ -260,25 +211,13 @@ /** | ||
*/ | ||
var handleDraftEditorPastedText = function handleDraftEditorPastedText(html | ||
/*: ?string*/ | ||
, editorState | ||
/*: EditorStateType*/ | ||
) { | ||
var pastedContent = getDraftEditorPastedContent(html); | ||
if (pastedContent) { | ||
var fragment = pastedContent.getBlockMap(); | ||
var content = draftJs.Modifier.replaceWithFragment(editorState.getCurrentContent(), editorState.getSelection(), fragment); | ||
return draftJs.EditorState.push(editorState, content, "insert-fragment"); | ||
} | ||
return false; | ||
const handleDraftEditorPastedText = (html, editorState) => { | ||
const pastedContent = getDraftEditorPastedContent(html); | ||
if (pastedContent) { | ||
const fragment = pastedContent.getBlockMap(); | ||
const content = draftJs.Modifier.replaceWithFragment(editorState.getCurrentContent(), editorState.getSelection(), fragment); | ||
return draftJs.EditorState.push(editorState, content, "insert-fragment"); | ||
} | ||
return false; | ||
}; | ||
// @flow | ||
/*:: import type { RawDraftContentState } from "draft-js/lib/RawDraftContentState";*/ | ||
/*:: import type { DraftDecoratorType } from "draft-js/lib/DraftDecoratorType";*/ | ||
var EMPTY_CONTENT_STATE = null; | ||
const EMPTY_CONTENT_STATE = null; | ||
/** | ||
@@ -288,18 +227,12 @@ * Creates a new EditorState from a RawDraftContentState, or an empty editor state by | ||
*/ | ||
var createEditorStateFromRaw = function createEditorStateFromRaw(rawContentState | ||
/*: ?RawDraftContentState*/ | ||
, decorator | ||
/*:: ?: ?DraftDecoratorType*/ | ||
) { | ||
var editorState; | ||
if (rawContentState) { | ||
var contentState = draftJs.convertFromRaw(rawContentState); | ||
editorState = draftJs.EditorState.createWithContent(contentState, decorator); | ||
} else { | ||
editorState = draftJs.EditorState.createEmpty(decorator); | ||
} | ||
return editorState; | ||
const createEditorStateFromRaw = (rawContentState, decorator) => { | ||
let editorState; | ||
if (rawContentState) { | ||
const contentState = draftJs.convertFromRaw(rawContentState); | ||
editorState = draftJs.EditorState.createWithContent(contentState, decorator); | ||
} | ||
else { | ||
editorState = draftJs.EditorState.createEmpty(decorator); | ||
} | ||
return editorState; | ||
}; | ||
@@ -310,13 +243,12 @@ /** | ||
*/ | ||
var serialiseEditorStateToRaw = function serialiseEditorStateToRaw(editorState | ||
/*: EditorState*/ | ||
) { | ||
var contentState = editorState.getCurrentContent(); | ||
var rawContentState = draftJs.convertToRaw(contentState); | ||
var isEmpty = rawContentState.blocks.every(function (block) { | ||
var isEmptyBlock = block.text.trim().length === 0 && (!block.entityRanges || block.entityRanges.length === 0) && (!block.inlineStyleRanges || block.inlineStyleRanges.length === 0); | ||
return isEmptyBlock; | ||
}); | ||
return isEmpty ? EMPTY_CONTENT_STATE : rawContentState; | ||
const serialiseEditorStateToRaw = (editorState) => { | ||
const contentState = editorState.getCurrentContent(); | ||
const rawContentState = draftJs.convertToRaw(contentState); | ||
const isEmpty = rawContentState.blocks.every((block) => { | ||
const isEmptyBlock = block.text.trim().length === 0 && | ||
(!block.entityRanges || block.entityRanges.length === 0) && | ||
(!block.inlineStyleRanges || block.inlineStyleRanges.length === 0); | ||
return isEmptyBlock; | ||
}); | ||
return isEmpty ? EMPTY_CONTENT_STATE : rawContentState; | ||
}; | ||
@@ -323,0 +255,0 @@ |
@@ -1,2 +0,1 @@ | ||
// @flow | ||
import getContentStateFragment from 'draft-js/lib/getContentStateFragment'; | ||
@@ -8,9 +7,6 @@ import getDraftEditorSelection from 'draft-js/lib/getDraftEditorSelection'; | ||
// @flow | ||
/*:: import type { BlockNode } from "draft-js/lib/BlockNode";*/ | ||
// Default maximum block depth supported by Draft.js CSS. | ||
var DRAFT_DEFAULT_MAX_DEPTH = 4; // Default depth class prefix from Draft.js CSS. | ||
var DRAFT_DEFAULT_DEPTH_CLASS = "public-DraftStyleDefault-depth"; | ||
const DRAFT_DEFAULT_MAX_DEPTH = 4; | ||
// Default depth class prefix from Draft.js CSS. | ||
const DRAFT_DEFAULT_DEPTH_CLASS = "public-DraftStyleDefault-depth"; | ||
/** | ||
@@ -20,4 +16,3 @@ * Matching the counter styles of Google Docs and Draft.js v0.11. | ||
*/ | ||
var COUNTER_STYLES = ["decimal", "lower-alpha", "lower-roman"]; | ||
const COUNTER_STYLES = ["decimal", "lower-alpha", "lower-roman"]; | ||
/** | ||
@@ -31,25 +26,22 @@ * Generates CSS styles for list items, for a given selector pattern. | ||
*/ | ||
var generateListNestingStyles = function generateListNestingStyles(selectorPrefix | ||
/*: string*/ | ||
, minDepth | ||
/*: number*/ | ||
, maxDepth | ||
/*: number*/ | ||
, counterStyles | ||
/*: string[]*/ | ||
) { | ||
var styles = "\n.".concat(selectorPrefix, "1.public-DraftStyleDefault-orderedListItem::before { content: counter(ol1, ").concat(counterStyles[1 % counterStyles.length], ") \". \"}\n.").concat(selectorPrefix, "2.public-DraftStyleDefault-orderedListItem::before { content: counter(ol2, ").concat(counterStyles[2 % counterStyles.length], ") \". \"}\n.").concat(selectorPrefix, "4.public-DraftStyleDefault-orderedListItem::before { content: counter(ol4, ").concat(counterStyles[4 % counterStyles.length], ") \". \"}\n"); | ||
for (var depth = minDepth; depth <= maxDepth; depth++) { | ||
var d = String(depth); | ||
var prefix = "".concat(selectorPrefix).concat(d); | ||
var counter = "ol".concat(d); | ||
var counterStyle = counterStyles[depth % counterStyles.length]; | ||
var margin = 1.5 * (depth + 1); | ||
var m = String(margin); | ||
styles += "\n.".concat(prefix, ".public-DraftStyleDefault-listLTR { margin-left: ").concat(m, "em; }\n.").concat(prefix, ".public-DraftStyleDefault-listRTL { margin-right: ").concat(m, "em; }\n.").concat(prefix, ".public-DraftStyleDefault-orderedListItem::before { content: counter(").concat(counter, ", ").concat(counterStyle, ") '. '; counter-increment: ").concat(counter, "; }\n.").concat(prefix, ".public-DraftStyleDefault-reset { counter-reset: ").concat(counter, "; }"); | ||
} | ||
return styles; | ||
const generateListNestingStyles = (selectorPrefix, minDepth, maxDepth, counterStyles) => { | ||
let styles = ` | ||
.${selectorPrefix}1.public-DraftStyleDefault-orderedListItem::before { content: counter(ol1, ${counterStyles[1 % counterStyles.length]}) ". "} | ||
.${selectorPrefix}2.public-DraftStyleDefault-orderedListItem::before { content: counter(ol2, ${counterStyles[2 % counterStyles.length]}) ". "} | ||
.${selectorPrefix}4.public-DraftStyleDefault-orderedListItem::before { content: counter(ol4, ${counterStyles[4 % counterStyles.length]}) ". "} | ||
`; | ||
for (let depth = minDepth; depth <= maxDepth; depth++) { | ||
const d = String(depth); | ||
const prefix = `${selectorPrefix}${d}`; | ||
const counter = `ol${d}`; | ||
const counterStyle = counterStyles[depth % counterStyles.length]; | ||
const margin = 1.5 * (depth + 1); | ||
const m = String(margin); | ||
styles += ` | ||
.${prefix}.public-DraftStyleDefault-listLTR { margin-left: ${m}em; } | ||
.${prefix}.public-DraftStyleDefault-listRTL { margin-right: ${m}em; } | ||
.${prefix}.public-DraftStyleDefault-orderedListItem::before { content: counter(${counter}, ${counterStyle}) '. '; counter-increment: ${counter}; } | ||
.${prefix}.public-DraftStyleDefault-reset { counter-reset: ${counter}; }`; | ||
} | ||
return styles; | ||
}; | ||
@@ -60,16 +52,4 @@ /** | ||
*/ | ||
var getListNestingStyles = function getListNestingStyles(maxDepth | ||
/*: number*/ | ||
) { | ||
var minDepth | ||
/*: number*/ | ||
= arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DRAFT_DEFAULT_MAX_DEPTH + 1; | ||
var selectorPrefix | ||
/*: string*/ | ||
= arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : DRAFT_DEFAULT_DEPTH_CLASS; | ||
var counterStyles | ||
/*: string[]*/ | ||
= arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : COUNTER_STYLES; | ||
return generateListNestingStyles(selectorPrefix, minDepth, maxDepth, counterStyles); | ||
const getListNestingStyles = (maxDepth, minDepth = DRAFT_DEFAULT_MAX_DEPTH + 1, selectorPrefix = DRAFT_DEFAULT_DEPTH_CLASS, counterStyles = COUNTER_STYLES) => { | ||
return generateListNestingStyles(selectorPrefix, minDepth, maxDepth, counterStyles); | ||
}; | ||
@@ -81,109 +61,87 @@ /** | ||
*/ | ||
var blockDepthStyleFn = function blockDepthStyleFn(block | ||
/*: BlockNode*/ | ||
) { | ||
var depth = block.getDepth(); | ||
return depth > DRAFT_DEFAULT_MAX_DEPTH ? "".concat(DRAFT_DEFAULT_DEPTH_CLASS).concat(String(depth)) : ""; | ||
const blockDepthStyleFn = (block) => { | ||
const depth = block.getDepth(); | ||
return depth > DRAFT_DEFAULT_MAX_DEPTH | ||
? `${DRAFT_DEFAULT_DEPTH_CLASS}${String(depth)}` | ||
: ""; | ||
}; | ||
// @flow | ||
/*:: import type { ElementRef } from "react";*/ | ||
/*:: import type { Editor, EditorState as EditorStateType } from "draft-js";*/ | ||
// @ts-expect-error | ||
// Custom attribute to store Draft.js content in the HTML clipboard. | ||
var FRAGMENT_ATTR = "data-draftjs-conductor-fragment"; | ||
var DRAFT_DECORATOR = '[data-contents="true"] [contenteditable="false"]'; // Checks whether the selection is inside a decorator or not. | ||
const FRAGMENT_ATTR = "data-draftjs-conductor-fragment"; | ||
const DRAFT_DECORATOR = '[data-contents="true"] [contenteditable="false"]'; | ||
// Checks whether the selection is inside a decorator or not. | ||
// This is important to change the copy-cut behavior accordingly. | ||
var isSelectionInDecorator = function isSelectionInDecorator(selection | ||
/*: Selection*/ | ||
) { | ||
var anchorNode = selection.anchorNode, | ||
focusNode = selection.focusNode; | ||
if (!anchorNode || !focusNode) { | ||
return false; | ||
} | ||
var anchor = anchorNode instanceof Element ? anchorNode : anchorNode.parentElement; | ||
var focus = focusNode instanceof Element ? focusNode : focusNode.parentElement; | ||
var anchorDecorator = anchor && anchor.closest(DRAFT_DECORATOR); | ||
var focusDecorator = focus && focus.closest(DRAFT_DECORATOR); | ||
return anchorDecorator && focusDecorator && (anchorDecorator.contains(focusDecorator) || focusDecorator.contains(anchorDecorator)); | ||
}; // Get clipboard content from the selection like Draft.js would. | ||
var getSelectedContent = function getSelectedContent(editorState | ||
/*: EditorStateType*/ | ||
, editorRoot | ||
/*: HTMLElement*/ | ||
) { | ||
var _getDraftEditorSelect = getDraftEditorSelection(editorState, editorRoot), | ||
selectionState = _getDraftEditorSelect.selectionState; | ||
var fragment = getContentStateFragment(editorState.getCurrentContent(), selectionState); // If the selection contains no content (according to Draft.js), use the default browser behavior. | ||
// This happens when selecting text that's within contenteditable=false blocks in Draft.js. | ||
// See https://github.com/thibaudcolas/draftjs-conductor/issues/12. | ||
var isEmpty = fragment.every(function (block) { | ||
return block.getText().length === 0; | ||
}); | ||
return isEmpty ? null : fragment; | ||
}; // Overrides the default copy/cut behavior, adding the serialised Draft.js content to the clipboard data. | ||
const isSelectionInDecorator = (selection) => { | ||
const { anchorNode, focusNode } = selection; | ||
if (!anchorNode || !focusNode) { | ||
return false; | ||
} | ||
const anchor = anchorNode instanceof Element ? anchorNode : anchorNode.parentElement; | ||
const focus = focusNode instanceof Element ? focusNode : focusNode.parentElement; | ||
const anchorDecorator = anchor && anchor.closest(DRAFT_DECORATOR); | ||
const focusDecorator = focus && focus.closest(DRAFT_DECORATOR); | ||
return (anchorDecorator && | ||
focusDecorator && | ||
(anchorDecorator.contains(focusDecorator) || | ||
focusDecorator.contains(anchorDecorator))); | ||
}; | ||
// Get clipboard content from the selection like Draft.js would. | ||
const getSelectedContent = (editorState, editorRoot) => { | ||
const { selectionState } = getDraftEditorSelection(editorState, editorRoot); | ||
const fragment = getContentStateFragment(editorState.getCurrentContent(), selectionState); | ||
// If the selection contains no content (according to Draft.js), use the default browser behavior. | ||
// This happens when selecting text that's within contenteditable=false blocks in Draft.js. | ||
// See https://github.com/thibaudcolas/draftjs-conductor/issues/12. | ||
const isEmpty = fragment.every((block) => { | ||
return block.getText().length === 0; | ||
}); | ||
return isEmpty ? null : fragment; | ||
}; | ||
// Overrides the default copy/cut behavior, adding the serialised Draft.js content to the clipboard data. | ||
// See also https://github.com/basecamp/trix/blob/62145978f352b8d971cf009882ba06ca91a16292/src/trix/controllers/input_controller.coffee#L415-L422 | ||
// We serialise the editor content within HTML, not as a separate mime type, because Draft.js only allows access | ||
// to HTML in its paste event handler. | ||
var draftEditorCopyCutListener = function draftEditorCopyCutListener(ref | ||
/*: ElementRef<Editor>*/ | ||
, e | ||
/*: SyntheticClipboardEvent<>*/ | ||
) { | ||
var selection = window.getSelection(); // Completely skip event handling if clipboardData is not supported (IE11 is out). | ||
// Also skip if there is no selection ranges. | ||
// Or if the selection is fully within a decorator. | ||
if (!e.clipboardData || selection.rangeCount === 0 || isSelectionInDecorator(selection)) { | ||
return; | ||
} | ||
var fragment = getSelectedContent(ref._latestEditorState, ref.editor); // Override the default behavior if there is selected content. | ||
if (fragment) { | ||
var content = ContentState.createFromBlockArray(fragment.toArray()); | ||
var serialisedContent = JSON.stringify(convertToRaw(content)); // Create a temporary element to store the selection’s HTML. | ||
// See also Rangy's implementation: https://github.com/timdown/rangy/blob/1e55169d2e4d1d9458c2a87119addf47a8265276/src/core/domrange.js#L515-L520. | ||
var fragmentElt = document.createElement("div"); // Modern browsers only support a single range. | ||
fragmentElt.appendChild(selection.getRangeAt(0).cloneContents()); | ||
fragmentElt.setAttribute(FRAGMENT_ATTR, serialisedContent); // We set the style property to replicate the browser's behavior of inline styles in rich text copy-paste. | ||
// In Draft.js, this is important for line breaks to be interpreted correctly when pasted into another word processor. | ||
// See https://github.com/facebook/draft-js/blob/a1f4593d8fa949954053e5d5840d33ce1d1082c6/src/component/base/DraftEditor.react.js#L328. | ||
fragmentElt.setAttribute("style", "white-space: pre-wrap;"); | ||
e.clipboardData.setData("text/plain", selection.toString()); | ||
e.clipboardData.setData("text/html", fragmentElt.outerHTML); | ||
e.preventDefault(); | ||
} | ||
const draftEditorCopyCutListener = ( | ||
// @ts-expect-error | ||
ref, e) => { | ||
const selection = window.getSelection(); | ||
// Completely skip event handling if clipboardData is not supported (IE11 is out). | ||
// Also skip if there is no selection ranges. | ||
// Or if the selection is fully within a decorator. | ||
if (!e.clipboardData || | ||
selection.rangeCount === 0 || | ||
isSelectionInDecorator(selection)) { | ||
return; | ||
} | ||
// @ts-expect-error | ||
const fragment = getSelectedContent(ref._latestEditorState, ref.editor); | ||
// Override the default behavior if there is selected content. | ||
if (fragment) { | ||
const content = ContentState.createFromBlockArray(fragment.toArray()); | ||
const serialisedContent = JSON.stringify(convertToRaw(content)); | ||
// Create a temporary element to store the selection’s HTML. | ||
// See also Rangy's implementation: https://github.com/timdown/rangy/blob/1e55169d2e4d1d9458c2a87119addf47a8265276/src/core/domrange.js#L515-L520. | ||
const fragmentElt = document.createElement("div"); | ||
// Modern browsers only support a single range. | ||
fragmentElt.appendChild(selection.getRangeAt(0).cloneContents()); | ||
fragmentElt.setAttribute(FRAGMENT_ATTR, serialisedContent); | ||
// We set the style property to replicate the browser's behavior of inline styles in rich text copy-paste. | ||
// In Draft.js, this is important for line breaks to be interpreted correctly when pasted into another word processor. | ||
// See https://github.com/facebook/draft-js/blob/a1f4593d8fa949954053e5d5840d33ce1d1082c6/src/component/base/DraftEditor.react.js#L328. | ||
fragmentElt.setAttribute("style", "white-space: pre-wrap;"); | ||
e.clipboardData.setData("text/plain", selection.toString()); | ||
e.clipboardData.setData("text/html", fragmentElt.outerHTML); | ||
e.preventDefault(); | ||
} | ||
}; | ||
var onDraftEditorCopy = function onDraftEditorCopy(editor | ||
/*: Editor*/ | ||
, e | ||
/*: SyntheticClipboardEvent<>*/ | ||
) { | ||
draftEditorCopyCutListener(editor, e); | ||
editOnCopy(editor, e); | ||
const onDraftEditorCopy = (editor, e) => { | ||
// @ts-expect-error | ||
draftEditorCopyCutListener(editor, e); | ||
editOnCopy(editor, e); | ||
}; | ||
var onDraftEditorCut = function onDraftEditorCut(editor | ||
/*: Editor*/ | ||
, e | ||
/*: SyntheticClipboardEvent<>*/ | ||
) { | ||
draftEditorCopyCutListener(editor, e); | ||
editOnCut(editor, e); | ||
const onDraftEditorCut = (editor, e) => { | ||
// @ts-expect-error | ||
draftEditorCopyCutListener(editor, e); | ||
editOnCut(editor, e); | ||
}; | ||
@@ -193,17 +151,15 @@ /** | ||
*/ | ||
var registerCopySource = function registerCopySource(ref | ||
/*: ElementRef<Editor>*/ | ||
) { | ||
var editorElt = ref.editor; | ||
var onCopyCut = draftEditorCopyCutListener.bind(null, ref); | ||
editorElt.addEventListener("copy", onCopyCut); | ||
editorElt.addEventListener("cut", onCopyCut); | ||
return { | ||
unregister() { | ||
editorElt.removeEventListener("copy", onCopyCut); | ||
editorElt.removeEventListener("cut", onCopyCut); | ||
} | ||
}; | ||
// @ts-expect-error | ||
const registerCopySource = (ref) => { | ||
// @ts-expect-error | ||
const editorElt = ref.editor; | ||
const onCopyCut = draftEditorCopyCutListener.bind(null, ref); | ||
editorElt.addEventListener("copy", onCopyCut); | ||
editorElt.addEventListener("cut", onCopyCut); | ||
return { | ||
unregister() { | ||
editorElt.removeEventListener("copy", onCopyCut); | ||
editorElt.removeEventListener("cut", onCopyCut); | ||
}, | ||
}; | ||
}; | ||
@@ -214,31 +170,25 @@ /** | ||
*/ | ||
var getDraftEditorPastedContent = function getDraftEditorPastedContent(html | ||
/*: ?string*/ | ||
) { | ||
// Plain-text pastes are better handled by Draft.js. | ||
if (html === "" || typeof html === "undefined" || html === null) { | ||
const getDraftEditorPastedContent = (html) => { | ||
// Plain-text pastes are better handled by Draft.js. | ||
if (html === "" || typeof html === "undefined" || html === null) { | ||
return null; | ||
} | ||
const doc = new DOMParser().parseFromString(html, "text/html"); | ||
const fragmentElt = doc.querySelector(`[${FRAGMENT_ATTR}]`); | ||
// Handle the paste if it comes from draftjs-conductor. | ||
if (fragmentElt) { | ||
const fragmentAttr = fragmentElt.getAttribute(FRAGMENT_ATTR); | ||
let rawContent; | ||
try { | ||
// If JSON parsing fails, leave paste handling to Draft.js. | ||
// There is no reason for this to happen, unless the clipboard was altered somehow. | ||
// @ts-expect-error | ||
rawContent = JSON.parse(fragmentAttr); | ||
} | ||
catch (error) { | ||
return null; | ||
} | ||
return convertFromRaw(rawContent); | ||
} | ||
return null; | ||
} | ||
var doc = new DOMParser().parseFromString(html, "text/html"); | ||
var fragmentElt = doc.querySelector("[".concat(FRAGMENT_ATTR, "]")); // Handle the paste if it comes from draftjs-conductor. | ||
if (fragmentElt) { | ||
var fragmentAttr = fragmentElt.getAttribute(FRAGMENT_ATTR); | ||
var rawContent; | ||
try { | ||
// If JSON parsing fails, leave paste handling to Draft.js. | ||
// There is no reason for this to happen, unless the clipboard was altered somehow. | ||
// $FlowFixMe | ||
rawContent = JSON.parse(fragmentAttr); | ||
} catch (error) { | ||
return null; | ||
} | ||
return convertFromRaw(rawContent); | ||
} | ||
return null; | ||
}; | ||
@@ -250,25 +200,13 @@ /** | ||
*/ | ||
var handleDraftEditorPastedText = function handleDraftEditorPastedText(html | ||
/*: ?string*/ | ||
, editorState | ||
/*: EditorStateType*/ | ||
) { | ||
var pastedContent = getDraftEditorPastedContent(html); | ||
if (pastedContent) { | ||
var fragment = pastedContent.getBlockMap(); | ||
var content = Modifier.replaceWithFragment(editorState.getCurrentContent(), editorState.getSelection(), fragment); | ||
return EditorState.push(editorState, content, "insert-fragment"); | ||
} | ||
return false; | ||
const handleDraftEditorPastedText = (html, editorState) => { | ||
const pastedContent = getDraftEditorPastedContent(html); | ||
if (pastedContent) { | ||
const fragment = pastedContent.getBlockMap(); | ||
const content = Modifier.replaceWithFragment(editorState.getCurrentContent(), editorState.getSelection(), fragment); | ||
return EditorState.push(editorState, content, "insert-fragment"); | ||
} | ||
return false; | ||
}; | ||
// @flow | ||
/*:: import type { RawDraftContentState } from "draft-js/lib/RawDraftContentState";*/ | ||
/*:: import type { DraftDecoratorType } from "draft-js/lib/DraftDecoratorType";*/ | ||
var EMPTY_CONTENT_STATE = null; | ||
const EMPTY_CONTENT_STATE = null; | ||
/** | ||
@@ -278,18 +216,12 @@ * Creates a new EditorState from a RawDraftContentState, or an empty editor state by | ||
*/ | ||
var createEditorStateFromRaw = function createEditorStateFromRaw(rawContentState | ||
/*: ?RawDraftContentState*/ | ||
, decorator | ||
/*:: ?: ?DraftDecoratorType*/ | ||
) { | ||
var editorState; | ||
if (rawContentState) { | ||
var contentState = convertFromRaw(rawContentState); | ||
editorState = EditorState.createWithContent(contentState, decorator); | ||
} else { | ||
editorState = EditorState.createEmpty(decorator); | ||
} | ||
return editorState; | ||
const createEditorStateFromRaw = (rawContentState, decorator) => { | ||
let editorState; | ||
if (rawContentState) { | ||
const contentState = convertFromRaw(rawContentState); | ||
editorState = EditorState.createWithContent(contentState, decorator); | ||
} | ||
else { | ||
editorState = EditorState.createEmpty(decorator); | ||
} | ||
return editorState; | ||
}; | ||
@@ -300,15 +232,14 @@ /** | ||
*/ | ||
var serialiseEditorStateToRaw = function serialiseEditorStateToRaw(editorState | ||
/*: EditorState*/ | ||
) { | ||
var contentState = editorState.getCurrentContent(); | ||
var rawContentState = convertToRaw(contentState); | ||
var isEmpty = rawContentState.blocks.every(function (block) { | ||
var isEmptyBlock = block.text.trim().length === 0 && (!block.entityRanges || block.entityRanges.length === 0) && (!block.inlineStyleRanges || block.inlineStyleRanges.length === 0); | ||
return isEmptyBlock; | ||
}); | ||
return isEmpty ? EMPTY_CONTENT_STATE : rawContentState; | ||
const serialiseEditorStateToRaw = (editorState) => { | ||
const contentState = editorState.getCurrentContent(); | ||
const rawContentState = convertToRaw(contentState); | ||
const isEmpty = rawContentState.blocks.every((block) => { | ||
const isEmptyBlock = block.text.trim().length === 0 && | ||
(!block.entityRanges || block.entityRanges.length === 0) && | ||
(!block.inlineStyleRanges || block.inlineStyleRanges.length === 0); | ||
return isEmptyBlock; | ||
}); | ||
return isEmpty ? EMPTY_CONTENT_STATE : rawContentState; | ||
}; | ||
export { DRAFT_DEFAULT_DEPTH_CLASS, DRAFT_DEFAULT_MAX_DEPTH, blockDepthStyleFn, createEditorStateFromRaw, generateListNestingStyles, getDraftEditorPastedContent, getListNestingStyles, handleDraftEditorPastedText, onDraftEditorCopy, onDraftEditorCut, registerCopySource, serialiseEditorStateToRaw }; |
{ | ||
"name": "draftjs-conductor", | ||
"version": "2.2.0", | ||
"version": "3.0.0", | ||
"description": "📝✨ Little Draft.js helpers to make rich text editors “just work”", | ||
@@ -9,3 +9,3 @@ "author": "Thibaud Colas", | ||
"module": "dist/draftjs-conductor.esm.js", | ||
"flow": "dist/draftjs-conductor.cjs.js.flow", | ||
"types": "dist/draftjs-conductor.d.ts", | ||
"sideEffects": false, | ||
@@ -32,27 +32,25 @@ "keywords": [ | ||
"dist/*.js", | ||
"dist/*.flow" | ||
"dist/*.d.ts" | ||
], | ||
"browserslist": { | ||
"production": [ | ||
">0.2%", | ||
"not dead", | ||
"not op_mini all", | ||
"not IE 11" | ||
], | ||
"development": [ | ||
">0.2%", | ||
"not dead", | ||
"not op_mini all", | ||
"not IE 11" | ||
"browserslist": "> 1%, not IE 11", | ||
"jest": { | ||
"collectCoverageFrom": [ | ||
"src/lib/**/*.{js,jsx,ts,tsx}", | ||
"!<rootDir>/node_modules/" | ||
] | ||
}, | ||
"devDependencies": { | ||
"@babel/plugin-transform-flow-comments": "7.12.13", | ||
"@commitlint/cli": "12.1.1", | ||
"@commitlint/config-conventional": "12.1.1", | ||
"@semantic-release/changelog": "5.0.1", | ||
"@semantic-release/exec": "5.0.0", | ||
"@semantic-release/git": "9.0.0", | ||
"coveralls": "3.1.0", | ||
"danger": "10.6.4", | ||
"@commitlint/cli": "17.0.2", | ||
"@commitlint/config-conventional": "17.0.2", | ||
"@rollup/plugin-typescript": "8.3.2", | ||
"@semantic-release/changelog": "6.0.1", | ||
"@semantic-release/exec": "6.0.3", | ||
"@semantic-release/git": "10.0.1", | ||
"@types/draft-js": "0.10.45", | ||
"@types/enzyme": "3.10.12", | ||
"@types/jest": "27.5.2", | ||
"@types/react": "16.14.26", | ||
"@types/react-dom": "16.9.16", | ||
"coveralls": "3.1.1", | ||
"danger": "11.0.7", | ||
"draft-js": "0.11.7", | ||
@@ -63,29 +61,28 @@ "draft-js-10": "npm:draft-js@0.10.5", | ||
"enzyme-to-json": "3.6.2", | ||
"flow-bin": "0.131.0", | ||
"immutable": "~3.7.6", | ||
"prettier": "2.2.1", | ||
"normalize.css": "7.0.0", | ||
"prettier": "2.6.2", | ||
"react": "16.14.0", | ||
"react-dom": "16.14.0", | ||
"react-scripts": "4.0.3", | ||
"react-scripts": "5.0.1", | ||
"react-test-renderer": "16.14.0", | ||
"rollup": "2.45.1", | ||
"rollup-plugin-babel": "4.4.0", | ||
"semantic-release": "17.4.2", | ||
"source-map-explorer": "2.5.2" | ||
"rollup": "2.75.5", | ||
"rollup-plugin-dts": "4.2.2", | ||
"semantic-release": "19.0.2", | ||
"snapshot-diff": "0.9.0", | ||
"typescript": "4.7.2" | ||
}, | ||
"peerDependencies": { | ||
"draft-js": "^0.10.5 || ^0.11.0 || ^0.12.0" | ||
"draft-js": "^0.10.4 || ^0.11.0 || ^0.12.0" | ||
}, | ||
"scripts": { | ||
"start": "react-scripts start", | ||
"build": "CI=true react-scripts build && source-map-explorer build/static/js/*.js --html > build/source-map-explorer.html && rollup -c", | ||
"test": "npm run test:coverage -s", | ||
"test:coverage": "CI=true react-scripts test --env=jsdom --coverage", | ||
"build": "CI=true react-scripts build && rollup -c", | ||
"test": "CI=true react-scripts test --env=jsdom --coverage", | ||
"test:watch": "react-scripts test --env=jsdom", | ||
"report:coverage": "open coverage/lcov-report/index.html", | ||
"report:build": "open public/source-map-explorer.html", | ||
"report:package": "npm pack --loglevel notice 2>&1 >/dev/null | sed -e 's/^npm notice //' | tee build/package.txt && rm *.tgz", | ||
"lint": "prettier --check '**/?(.)*.{md,css,scss,js,json,yaml,yml,html}'", | ||
"format": "prettier --write '**/?(.)*.{md,css,scss,js,json,yaml,yml,html}'", | ||
"test:ci": "npm run lint -s && npm run build -s && flow --quiet && npm run test:coverage -s -- --outputFile build/test-results.json --json", | ||
"lint": "prettier --check '**/?(.)*.{md,css,scss,js,ts,tsx,json,yaml,yml,html}'", | ||
"format": "prettier --write '**/?(.)*.{md,css,scss,js,ts,tsx,json,yaml,yml,html}'", | ||
"test:ci": "npm run lint -s && npm run build -s && npm run test -s -- --outputFile build/test-results.json --json", | ||
"prepare": "./.githooks/deploy.sh", | ||
@@ -92,0 +89,0 @@ "prepublishOnly": "npm run build -s" |
@@ -107,3 +107,7 @@ # [Draft.js conductor](https://thibaudcolas.github.io/draftjs-conductor/) [<img src="https://raw.githubusercontent.com/thibaudcolas/draftail.org/main/.github/draftail-logo.svg?sanitize=true" width="90" height="90" align="right">](https://www.draftail.org/) | ||
handlePastedText(text: string, html: ?string, editorState: EditorState) { | ||
handlePastedText( | ||
text: string, | ||
html: string | null, | ||
editorState: EditorState, | ||
) { | ||
let newState = handleDraftEditorPastedText(html, editorState); | ||
@@ -110,0 +114,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
552
237
41539
30
6
1