New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

draftjs-conductor

Package Overview
Dependencies
Maintainers
2
Versions
21
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

draftjs-conductor - npm Package Compare versions

Comparing version 2.2.0 to 3.0.0

dist/draftjs-conductor.d.ts

400

dist/draftjs-conductor.cjs.js

@@ -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 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc