@portabletext/editor
Version:
Portable Text Editor made in React
1,324 lines (1,323 loc) • 420 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: !0 });
var reactCompilerRuntime = require("react-compiler-runtime"), React = require("react"), useEffectEvent = require("use-effect-event"), useEditor = require("./_chunks-cjs/use-editor.cjs"), jsxRuntime = require("react/jsx-runtime"), react = require("@xstate/react"), noop = require("lodash/noop.js"), slate = require("slate"), slateReact = require("slate-react"), debug$g = require("debug"), slateDom = require("slate-dom"), selectionPoint = require("./_chunks-cjs/selection-point.cjs"), util_isEqualSelectionPoints = require("./_chunks-cjs/util.is-equal-selection-points.cjs"), util_selectionPointToBlockOffset = require("./_chunks-cjs/util.selection-point-to-block-offset.cjs"), isEqual = require("lodash/isEqual.js"), types = require("@sanity/types"), selector_isSelectionExpanded = require("./_chunks-cjs/selector.is-selection-expanded.cjs"), selector_isSelectingEntireBlocks = require("./_chunks-cjs/selector.is-selecting-entire-blocks.cjs"), getRandomValues = require("get-random-values-esm"), behaviors_index = require("./behaviors/index.cjs"), uniq = require("lodash/uniq.js"), rxjs = require("rxjs"), xstate = require("xstate"), blockTools = require("@portabletext/block-tools"), toHtml = require("@portabletext/to-html"), schema = require("@sanity/schema"), flatten = require("lodash/flatten.js"), omit = require("lodash/omit.js"), util_childSelectionPointToBlockOffset = require("./_chunks-cjs/util.child-selection-point-to-block-offset.cjs"), patches = require("@portabletext/patches"), get = require("lodash/get.js"), isUndefined = require("lodash/isUndefined.js"), omitBy = require("lodash/omitBy.js"), immer = require("immer"), startCase = require("lodash.startcase"), isPlainObject = require("lodash/isPlainObject.js");
function _interopDefaultCompat(e) {
return e && typeof e == "object" && "default" in e ? e : { default: e };
}
var React__default = /* @__PURE__ */ _interopDefaultCompat(React), noop__default = /* @__PURE__ */ _interopDefaultCompat(noop), debug__default = /* @__PURE__ */ _interopDefaultCompat(debug$g), isEqual__default = /* @__PURE__ */ _interopDefaultCompat(isEqual), getRandomValues__default = /* @__PURE__ */ _interopDefaultCompat(getRandomValues), uniq__default = /* @__PURE__ */ _interopDefaultCompat(uniq), flatten__default = /* @__PURE__ */ _interopDefaultCompat(flatten), omit__default = /* @__PURE__ */ _interopDefaultCompat(omit), get__default = /* @__PURE__ */ _interopDefaultCompat(get), isUndefined__default = /* @__PURE__ */ _interopDefaultCompat(isUndefined), omitBy__default = /* @__PURE__ */ _interopDefaultCompat(omitBy), startCase__default = /* @__PURE__ */ _interopDefaultCompat(startCase), isPlainObject__default = /* @__PURE__ */ _interopDefaultCompat(isPlainObject);
function EditorEventListener(props) {
const $ = reactCompilerRuntime.c(5), editor = useEditor.useEditor(), on = useEffectEvent.useEffectEvent(props.on);
let t0;
$[0] !== editor || $[1] !== on ? (t0 = () => {
const subscription = editor.on("*", on);
return () => {
subscription.unsubscribe();
};
}, $[0] = editor, $[1] = on, $[2] = t0) : t0 = $[2];
let t1;
return $[3] !== editor ? (t1 = [editor], $[3] = editor, $[4] = t1) : t1 = $[4], React.useEffect(t0, t1), null;
}
const rootName = "sanity-pte:";
debug__default.default(rootName);
function debugWithName(name) {
const namespace = `${rootName}${name}`;
return debug__default.default && debug__default.default.enabled(namespace) ? debug__default.default(namespace) : debug__default.default(rootName);
}
const VOID_CHILD_KEY = "void-child";
function keepObjectEquality(object, keyMap) {
const value = keyMap[object._key];
return value && isEqual__default.default(object, value) ? value : (keyMap[object._key] = object, object);
}
function toSlateValue(value, {
schemaTypes
}, keyMap = {}) {
return value && Array.isArray(value) ? value.map((block) => {
const {
_type,
_key,
...rest
} = block;
if (block && block._type === schemaTypes.block.name) {
const textBlock = block;
let hasInlines = !1;
const hasMissingStyle = typeof textBlock.style > "u", hasMissingMarkDefs = typeof textBlock.markDefs > "u", hasMissingChildren = typeof textBlock.children > "u", children = (textBlock.children || []).map((child) => {
const {
_type: cType,
_key: cKey,
...cRest
} = child;
return cType !== "span" ? (hasInlines = !0, keepObjectEquality({
_type: cType,
_key: cKey,
children: [{
_key: VOID_CHILD_KEY,
_type: "span",
text: "",
marks: []
}],
value: cRest,
__inline: !0
}, keyMap)) : child;
});
return !hasMissingStyle && !hasMissingMarkDefs && !hasMissingChildren && !hasInlines && slate.Element.isElement(block) ? block : (hasMissingStyle && (rest.style = schemaTypes.styles[0].name), keepObjectEquality({
_type,
_key,
...rest,
children
}, keyMap));
}
return keepObjectEquality({
_type,
_key,
children: [{
_key: VOID_CHILD_KEY,
_type: "span",
text: "",
marks: []
}],
value: rest
}, keyMap);
}) : [];
}
function fromSlateValue(value, textBlockType, keyMap = {}) {
return value.map((block) => {
const {
_key,
_type
} = block;
if (!_key || !_type)
throw new Error("Not a valid block");
if (_type === textBlockType && "children" in block && Array.isArray(block.children) && _key) {
let hasInlines = !1;
const children = block.children.map((child) => {
const {
_type: _cType
} = child;
if ("value" in child && _cType !== "span") {
hasInlines = !0;
const {
value: v,
_key: k,
_type: t,
__inline: _i,
children: _c,
...rest
} = child;
return keepObjectEquality({
...rest,
...v,
_key: k,
_type: t
}, keyMap);
}
return child;
});
return hasInlines ? keepObjectEquality({
...block,
children,
_key,
_type
}, keyMap) : block;
}
const blockValue = "value" in block && block.value;
return keepObjectEquality({
_key,
_type,
...typeof blockValue == "object" ? blockValue : {}
}, keyMap);
});
}
function isEqualToEmptyEditor(children, schemaTypes) {
return children === void 0 || children && Array.isArray(children) && children.length === 0 || children && Array.isArray(children) && children.length === 1 && slate.Element.isElement(children[0]) && children[0]._type === schemaTypes.block.name && "style" in children[0] && children[0].style === schemaTypes.styles[0].name && !("listItem" in children[0]) && Array.isArray(children[0].children) && children[0].children.length === 1 && slate.Text.isText(children[0].children[0]) && children[0].children[0]._type === "span" && !children[0].children[0].marks?.join("") && children[0].children[0].text === "";
}
function getBlockPath({
editor,
_key
}) {
const [, blockPath] = Array.from(slate.Editor.nodes(editor, {
at: [],
match: (n) => n._key === _key
})).at(0) ?? [void 0, void 0], blockIndex = blockPath?.at(0);
if (blockIndex !== void 0)
return [blockIndex];
}
function getFocusBlock({
editor
}) {
if (!editor.selection)
return [void 0, void 0];
try {
return slate.Editor.node(editor, editor.selection.focus.path.slice(0, 1)) ?? [void 0, void 0];
} catch {
return [void 0, void 0];
}
}
function getFocusSpan({
editor
}) {
if (!editor.selection)
return [void 0, void 0];
try {
const [node, path] = slate.Editor.node(editor, editor.selection.focus.path);
if (editor.isTextSpan(node))
return [node, path];
} catch {
return [void 0, void 0];
}
return [void 0, void 0];
}
function getSelectionStartBlock({
editor
}) {
if (!editor.selection)
return [void 0, void 0];
const selectionStartPoint = slate.Range.start(editor.selection);
return getPointBlock({
editor,
point: selectionStartPoint
});
}
function getSelectionEndBlock({
editor
}) {
if (!editor.selection)
return [void 0, void 0];
const selectionEndPoint = slate.Range.end(editor.selection);
return getPointBlock({
editor,
point: selectionEndPoint
});
}
function getPointBlock({
editor,
point
}) {
try {
const [block] = slate.Editor.node(editor, point.path.slice(0, 1)) ?? [void 0, void 0];
return block ? [block, point.path.slice(0, 1)] : [void 0, void 0];
} catch {
return [void 0, void 0];
}
}
function getFocusChild({
editor
}) {
const [focusBlock, focusBlockPath] = getFocusBlock({
editor
}), childIndex = editor.selection?.focus.path.at(1);
if (!focusBlock || !focusBlockPath || childIndex === void 0)
return [void 0, void 0];
try {
const focusChild = slate.Node.child(focusBlock, childIndex);
return focusChild ? [focusChild, [...focusBlockPath, childIndex]] : [void 0, void 0];
} catch {
return [void 0, void 0];
}
}
function getPointChild({
editor,
point
}) {
const [block, blockPath] = getPointBlock({
editor,
point
}), childIndex = point.path.at(1);
if (!block || !blockPath || childIndex === void 0)
return [void 0, void 0];
try {
const pointChild = slate.Node.child(block, childIndex);
return pointChild ? [pointChild, [...blockPath, childIndex]] : [void 0, void 0];
} catch {
return [void 0, void 0];
}
}
function getFirstBlock({
editor
}) {
if (editor.children.length === 0)
return [void 0, void 0];
const firstBlockPath = slate.Editor.start(editor, []).path.at(0);
try {
return firstBlockPath !== void 0 ? slate.Editor.node(editor, [firstBlockPath]) ?? [void 0, void 0] : [void 0, void 0];
} catch {
return [void 0, void 0];
}
}
function getLastBlock({
editor
}) {
if (editor.children.length === 0)
return [void 0, void 0];
const lastBlockPath = slate.Editor.end(editor, []).path.at(0);
try {
return lastBlockPath !== void 0 ? slate.Editor.node(editor, [lastBlockPath]) ?? [void 0, void 0] : [void 0, void 0];
} catch {
return [void 0, void 0];
}
}
function getNodeBlock({
editor,
schema: schema2,
node
}) {
if (slate.Editor.isEditor(node))
return;
if (isBlockElement({
editor,
schema: schema2
}, node))
return elementToBlock({
schema: schema2,
element: node
});
const parent = Array.from(slate.Editor.nodes(editor, {
mode: "highest",
at: [],
match: (n) => isBlockElement({
editor,
schema: schema2
}, n) && n.children.some((child) => child._key === node._key)
})).at(0)?.at(0);
return slate.Element.isElement(parent) ? elementToBlock({
schema: schema2,
element: parent
}) : void 0;
}
function elementToBlock({
schema: schema2,
element
}) {
return fromSlateValue([element], schema2.block.name)?.at(0);
}
function isBlockElement({
editor,
schema: schema2
}, node) {
return slate.Element.isElement(node) && !editor.isInline(node) && (schema2.block.name === node._type || schema2.blockObjects.some((blockObject) => blockObject.name === node._type));
}
function isListItemActive({
editor,
listItem
}) {
if (!editor.selection)
return !1;
const selectedBlocks = [...slate.Editor.nodes(editor, {
at: editor.selection,
match: (node) => editor.isTextBlock(node)
})];
return selectedBlocks.length > 0 ? selectedBlocks.every(([node]) => editor.isListBlock(node) && node.listItem === listItem) : !1;
}
function isStyleActive({
editor,
style
}) {
if (!editor.selection)
return !1;
const selectedBlocks = [...slate.Editor.nodes(editor, {
at: editor.selection,
match: (node) => editor.isTextBlock(node)
})];
return selectedBlocks.length > 0 ? selectedBlocks.every(([node]) => node.style === style) : !1;
}
function slateRangeToSelection({
schema: schema2,
editor,
range
}) {
const [anchorBlock] = getPointBlock({
editor,
point: range.anchor
}), [focusBlock] = getPointBlock({
editor,
point: range.focus
});
if (!anchorBlock || !focusBlock)
return null;
const [anchorChild] = anchorBlock._type === schema2.block.name ? getPointChild({
editor,
point: range.anchor
}) : [void 0, void 0], [focusChild] = focusBlock._type === schema2.block.name ? getPointChild({
editor,
point: range.focus
}) : [void 0, void 0], selection = {
anchor: {
path: [{
_key: anchorBlock._key
}],
offset: range.anchor.offset
},
focus: {
path: [{
_key: focusBlock._key
}],
offset: range.focus.offset
},
backward: slate.Range.isBackward(range)
};
return anchorChild && (selection.anchor.path.push("children"), selection.anchor.path.push({
_key: anchorChild._key
})), focusChild && (selection.focus.path.push("children"), selection.focus.path.push({
_key: focusChild._key
})), selection;
}
function getEventPosition({
editorActor,
slateEditor,
event
}) {
if (editorActor.getSnapshot().matches({
setup: "setting up"
}))
return;
const eventNode = getEventNode({
slateEditor,
event
});
if (!eventNode)
return;
const eventBlock = getNodeBlock({
editor: slateEditor,
schema: editorActor.getSnapshot().context.schema,
node: eventNode
}), eventPositionBlock = getEventPositionBlock({
node: eventNode,
slateEditor,
event
}), eventSelection = getEventSelection({
schema: editorActor.getSnapshot().context.schema,
slateEditor,
event
});
if (eventBlock && eventPositionBlock && !eventSelection && !slate.Editor.isEditor(eventNode))
return {
block: eventPositionBlock,
isEditor: !1,
selection: {
anchor: selectionPoint.getBlockStartPoint({
context: editorActor.getSnapshot().context,
block: {
node: eventBlock,
path: [{
_key: eventBlock._key
}]
}
}),
focus: util_isEqualSelectionPoints.getBlockEndPoint({
context: editorActor.getSnapshot().context,
block: {
node: eventBlock,
path: [{
_key: eventBlock._key
}]
}
})
}
};
if (!eventPositionBlock || !eventSelection)
return;
const eventSelectionFocusBlockKey = selectionPoint.getBlockKeyFromSelectionPoint(eventSelection.focus);
if (eventSelectionFocusBlockKey !== void 0)
return util_selectionPointToBlockOffset.isSelectionCollapsed(eventSelection) && eventBlock && eventSelectionFocusBlockKey !== eventBlock._key ? {
block: eventPositionBlock,
isEditor: !1,
selection: {
anchor: selectionPoint.getBlockStartPoint({
context: editorActor.getSnapshot().context,
block: {
node: eventBlock,
path: [{
_key: eventBlock._key
}]
}
}),
focus: util_isEqualSelectionPoints.getBlockEndPoint({
context: editorActor.getSnapshot().context,
block: {
node: eventBlock,
path: [{
_key: eventBlock._key
}]
}
})
}
} : {
block: eventPositionBlock,
isEditor: slate.Editor.isEditor(eventNode),
selection: eventSelection
};
}
function getEventNode({
slateEditor,
event
}) {
return slateDom.DOMEditor.hasTarget(slateEditor, event.target) ? slateDom.DOMEditor.toSlateNode(slateEditor, event.target) : void 0;
}
function getEventPositionBlock({
node,
slateEditor,
event
}) {
const [firstBlock] = getFirstBlock({
editor: slateEditor
});
if (!firstBlock)
return;
const firstBlockRect = slateDom.DOMEditor.toDOMNode(slateEditor, firstBlock).getBoundingClientRect();
if (event.pageY < firstBlockRect.top)
return "start";
const [lastBlock] = getLastBlock({
editor: slateEditor
});
if (!lastBlock)
return;
const lastBlockRef = slateDom.DOMEditor.toDOMNode(slateEditor, lastBlock).getBoundingClientRect();
if (event.pageY > lastBlockRef.bottom)
return "end";
const elementRect = slateDom.DOMEditor.toDOMNode(slateEditor, node).getBoundingClientRect(), top = elementRect.top, height = elementRect.height;
return Math.abs(top - event.pageY) < height / 2 ? "start" : "end";
}
function getEventSelection({
schema: schema2,
slateEditor,
event
}) {
const range = getSlateRangeFromEvent(slateEditor, event);
return range ? slateRangeToSelection({
schema: schema2,
editor: slateEditor,
range
}) : null;
}
function getSlateRangeFromEvent(editor, event) {
if (!event.target || !slateDom.isDOMNode(event.target))
return;
const window2 = slateDom.DOMEditor.getWindow(editor);
let domRange;
if (window2.document.caretPositionFromPoint !== void 0) {
const position = window2.document.caretPositionFromPoint(event.clientX, event.clientY);
if (position)
try {
domRange = window2.document.createRange(), domRange.setStart(position.offsetNode, position.offset), domRange.setEnd(position.offsetNode, position.offset);
} catch {
}
} else if (window2.document.caretRangeFromPoint !== void 0)
domRange = window2.document.caretRangeFromPoint(event.clientX, event.clientY) ?? void 0;
else {
console.warn("Neither caretPositionFromPoint nor caretRangeFromPoint is supported");
return;
}
if (!domRange)
return;
let range;
try {
range = slateDom.DOMEditor.toSlateRange(editor, domRange, {
exactMatch: !1,
// It can still throw even with this option set to true
suppressThrow: !1
});
} catch {
}
return range;
}
function toSlatePath(path, editor) {
if (!editor)
return [];
const [block, blockPath] = Array.from(slate.Editor.nodes(editor, {
at: [],
match: (n) => types.isKeySegment(path[0]) && n._key === path[0]._key
}))[0] || [void 0, void 0];
if (!block || !slate.Element.isElement(block))
return [];
if (editor.isVoid(block))
return [blockPath[0], 0];
const childPath = [path[2]], childIndex = block.children.findIndex((child) => isEqual__default.default([{
_key: child._key
}], childPath));
if (childIndex >= 0 && block.children[childIndex]) {
const child = block.children[childIndex];
return slate.Element.isElement(child) && editor.isVoid(child) ? blockPath.concat(childIndex).concat(0) : blockPath.concat(childIndex);
}
return [blockPath[0], 0];
}
function toSlateRange(selection, editor) {
if (!selection || !editor)
return null;
const anchor = {
path: toSlatePath(selection.anchor.path, editor),
offset: selection.anchor.offset
}, focus = {
path: toSlatePath(selection.focus.path, editor),
offset: selection.focus.offset
};
return focus.path.length === 0 || anchor.path.length === 0 ? null : anchor && focus ? {
anchor,
focus
} : null;
}
function moveRangeByOperation(range, operation) {
const anchor = slate.Point.transform(range.anchor, operation), focus = slate.Point.transform(range.focus, operation);
return anchor === null || focus === null ? null : slate.Point.equals(anchor, range.anchor) && slate.Point.equals(focus, range.focus) ? range : {
anchor,
focus
};
}
function normalizePoint(point, value) {
if (!point || !value)
return null;
const newPath = [];
let newOffset = point.offset || 0;
const blockKey = typeof point.path[0] == "object" && "_key" in point.path[0] && point.path[0]._key, childKey = typeof point.path[2] == "object" && "_key" in point.path[2] && point.path[2]._key, block = value.find((blk) => blk._key === blockKey);
if (block)
newPath.push({
_key: block._key
});
else
return null;
if (block && point.path[1] === "children") {
if (!block.children || Array.isArray(block.children) && block.children.length === 0)
return null;
const child = Array.isArray(block.children) && block.children.find((cld) => cld._key === childKey);
if (child)
newPath.push("children"), newPath.push({
_key: child._key
}), newOffset = child.text && child.text.length >= point.offset ? point.offset : child.text && child.text.length || 0;
else
return null;
}
return {
path: newPath,
offset: newOffset
};
}
function normalizeSelection(selection, value) {
if (!selection || !value || value.length === 0)
return null;
let newAnchor = null, newFocus = null;
const {
anchor,
focus
} = selection;
return anchor && value.find((blk) => isEqual__default.default({
_key: blk._key
}, anchor.path[0])) && (newAnchor = normalizePoint(anchor, value)), focus && value.find((blk) => isEqual__default.default({
_key: blk._key
}, focus.path[0])) && (newFocus = normalizePoint(focus, value)), newAnchor && newFocus ? {
anchor: newAnchor,
focus: newFocus,
backward: selection.backward
} : null;
}
const IS_PROCESSING_REMOTE_CHANGES = /* @__PURE__ */ new WeakMap(), KEY_TO_SLATE_ELEMENT = /* @__PURE__ */ new WeakMap(), KEY_TO_VALUE_ELEMENT = /* @__PURE__ */ new WeakMap(), SLATE_TO_PORTABLE_TEXT_RANGE = /* @__PURE__ */ new WeakMap(), EditorActorContext = React.createContext({});
function DropIndicator() {
const $ = reactCompilerRuntime.c(1);
let t0;
return $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsxRuntime.jsx("div", { contentEditable: !1, className: "pt-drop-indicator", style: {
position: "absolute",
width: "100%",
height: 1,
borderBottom: "1px solid currentColor",
zIndex: 5
}, children: /* @__PURE__ */ jsxRuntime.jsx("span", {}) }), $[0] = t0) : t0 = $[0], t0;
}
function RenderDefaultBlockObject(props) {
const $ = reactCompilerRuntime.c(4);
let t0;
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = {
userSelect: "none"
}, $[0] = t0) : t0 = $[0];
let t1;
return $[1] !== props.blockObject._key || $[2] !== props.blockObject._type ? (t1 = /* @__PURE__ */ jsxRuntime.jsxs("div", { style: t0, children: [
"[",
props.blockObject._type,
": ",
props.blockObject._key,
"]"
] }), $[1] = props.blockObject._key, $[2] = props.blockObject._type, $[3] = t1) : t1 = $[3], t1;
}
function RenderDefaultInlineObject(props) {
const $ = reactCompilerRuntime.c(4);
let t0;
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = {
userSelect: "none"
}, $[0] = t0) : t0 = $[0];
let t1;
return $[1] !== props.inlineObject._key || $[2] !== props.inlineObject._type ? (t1 = /* @__PURE__ */ jsxRuntime.jsxs("span", { style: t0, children: [
"[",
props.inlineObject._type,
": ",
props.inlineObject._key,
"]"
] }), $[1] = props.inlineObject._key, $[2] = props.inlineObject._type, $[3] = t1) : t1 = $[3], t1;
}
function getDragSelection({
eventSelection,
snapshot
}) {
let dragSelection = eventSelection;
if (selector_isSelectingEntireBlocks.getFocusInlineObject({
context: {
...snapshot.context,
selection: eventSelection
}
}))
return dragSelection;
const draggingCollapsedSelection = selector_isSelectionExpanded.isSelectionCollapsed({
context: {
...snapshot.context,
selection: eventSelection
}
}), draggedTextBlock = selector_isSelectionExpanded.getFocusTextBlock({
context: {
...snapshot.context,
selection: eventSelection
}
}), draggedSpan = selector_isSelectionExpanded.getFocusSpan({
context: {
...snapshot.context,
selection: eventSelection
}
});
draggingCollapsedSelection && draggedTextBlock && draggedSpan && (dragSelection = {
anchor: selectionPoint.getBlockStartPoint({
context: snapshot.context,
block: draggedTextBlock
}),
focus: util_isEqualSelectionPoints.getBlockEndPoint({
context: snapshot.context,
block: draggedTextBlock
})
});
const selectedBlocks = selector_isSelectionExpanded.getSelectedBlocks(snapshot);
if (snapshot.context.selection && selector_isSelectionExpanded.isSelectionExpanded(snapshot) && selectedBlocks.length > 1) {
const selectionStartBlock = selector_isSelectionExpanded.getSelectionStartBlock(snapshot), selectionEndBlock = selector_isSelectionExpanded.getSelectionEndBlock(snapshot);
if (!selectionStartBlock || !selectionEndBlock)
return dragSelection;
const selectionStartPoint = selectionPoint.getBlockStartPoint({
context: snapshot.context,
block: selectionStartBlock
}), selectionEndPoint = util_isEqualSelectionPoints.getBlockEndPoint({
context: snapshot.context,
block: selectionEndBlock
});
selector_isSelectingEntireBlocks.isOverlappingSelection(eventSelection)({
...snapshot,
context: {
...snapshot.context,
selection: {
anchor: selectionStartPoint,
focus: selectionEndPoint
}
}
}) && (dragSelection = {
anchor: selectionStartPoint,
focus: selectionEndPoint
});
}
return dragSelection;
}
const defaultKeyGenerator = () => randomKey(12), getByteHexTable = /* @__PURE__ */ (() => {
let table;
return () => {
if (table)
return table;
table = [];
for (let i = 0; i < 256; ++i)
table[i] = (i + 256).toString(16).slice(1);
return table;
};
})();
function whatwgRNG(length = 16) {
const rnds8 = new Uint8Array(length);
return getRandomValues__default.default(rnds8), rnds8;
}
function randomKey(length) {
const table = getByteHexTable();
return whatwgRNG(length).reduce((str, n) => str + table[n], "").slice(0, length);
}
function createEditorPriority(config) {
return {
id: defaultKeyGenerator(),
name: config?.name,
reference: config?.reference
};
}
const corePriority = createEditorPriority({
name: "core"
});
function createCoreBlockElementBehaviorsConfig({
key,
onSetDragPositionBlock
}) {
return [{
behavior: behaviors_index.defineBehavior({
on: "drag.dragover",
guard: ({
snapshot,
event
}) => {
const dropFocusBlock = selector_isSelectionExpanded.getFocusBlock({
context: {
...snapshot.context,
selection: event.position.selection
}
});
if (!dropFocusBlock || dropFocusBlock.node._key !== key)
return !1;
const dragOrigin = event.dragOrigin;
if (!dragOrigin)
return !1;
const dragSelection = getDragSelection({
eventSelection: dragOrigin.selection,
snapshot
});
return selector_isSelectionExpanded.getSelectedBlocks({
context: {
...snapshot.context,
selection: dragSelection
}
}).some((draggedBlock) => draggedBlock.node._key === key) ? !1 : selector_isSelectingEntireBlocks.isSelectingEntireBlocks({
context: {
...snapshot.context,
selection: dragSelection
}
});
},
actions: [({
event
}) => [{
type: "effect",
effect: () => {
onSetDragPositionBlock(event.position.block);
}
}]]
}),
priority: createEditorPriority({
reference: {
priority: corePriority,
importance: "lower"
}
})
}, {
behavior: behaviors_index.defineBehavior({
on: "drag.*",
guard: ({
event
}) => event.type !== "drag.dragover",
actions: [({
event
}) => [{
type: "effect",
effect: () => {
onSetDragPositionBlock(void 0);
}
}, behaviors_index.forward(event)]]
}),
priority: createEditorPriority({
reference: {
priority: corePriority,
importance: "lower"
}
})
}];
}
function useCoreBlockElementBehaviors(t0) {
const $ = reactCompilerRuntime.c(5), {
key,
onSetDragPositionBlock
} = t0, editorActor = React.useContext(EditorActorContext);
let t1, t2;
$[0] !== editorActor || $[1] !== key || $[2] !== onSetDragPositionBlock ? (t1 = () => {
const behaviorConfigs = createCoreBlockElementBehaviorsConfig({
key,
onSetDragPositionBlock
});
for (const behaviorConfig of behaviorConfigs)
editorActor.send({
type: "add behavior",
behaviorConfig
});
return () => {
for (const behaviorConfig_0 of behaviorConfigs)
editorActor.send({
type: "remove behavior",
behaviorConfig: behaviorConfig_0
});
};
}, t2 = [editorActor, key, onSetDragPositionBlock], $[0] = editorActor, $[1] = key, $[2] = onSetDragPositionBlock, $[3] = t1, $[4] = t2) : (t1 = $[3], t2 = $[4]), React.useEffect(t1, t2);
}
function RenderBlockObject(props) {
const [dragPositionBlock, setDragPositionBlock] = React.useState(), blockObjectRef = React.useRef(null), slateEditor = slateReact.useSlateStatic(), selected = slateReact.useSelected(), editorActor = React.useContext(EditorActorContext);
useCoreBlockElementBehaviors({
key: props.element._key,
onSetDragPositionBlock: setDragPositionBlock
});
const legacySchemaType = react.useSelector(editorActor, (s) => s.context.getLegacySchema().blockObjects.find((blockObject) => blockObject.name === props.element._type));
legacySchemaType || console.error(`Block object type ${props.element._type} not found in Schema`);
const focused = selected && slateEditor.selection !== null && slate.Range.isCollapsed(slateEditor.selection);
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ...props.attributes, className: "pt-block pt-object-block", "data-block-key": props.element._key, "data-block-name": props.element._type, "data-block-type": "object", children: [
dragPositionBlock === "start" ? /* @__PURE__ */ jsxRuntime.jsx(DropIndicator, {}) : null,
props.children,
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: blockObjectRef, contentEditable: !1, draggable: !props.readOnly, children: props.renderBlock && legacySchemaType ? props.renderBlock({
children: /* @__PURE__ */ jsxRuntime.jsx(RenderDefaultBlockObject, { blockObject: props.blockObject }),
editorElementRef: blockObjectRef,
focused,
path: [{
_key: props.element._key
}],
schemaType: legacySchemaType,
selected,
type: legacySchemaType,
value: props.blockObject
}) : /* @__PURE__ */ jsxRuntime.jsx(RenderDefaultBlockObject, { blockObject: props.blockObject }) }),
dragPositionBlock === "end" ? /* @__PURE__ */ jsxRuntime.jsx(DropIndicator, {}) : null
] });
}
function RenderInlineObject(props) {
const inlineObjectRef = React.useRef(null), slateEditor = slateReact.useSlateStatic(), selected = slateReact.useSelected(), editorActor = React.useContext(EditorActorContext), legacySchemaType = react.useSelector(editorActor, (s) => s.context.getLegacySchema().inlineObjects.find((inlineObject) => inlineObject.name === props.element._type));
legacySchemaType || console.error(`Inline object type ${props.element._type} not found in Schema`);
const focused = selected && slateEditor.selection !== null && slate.Range.isCollapsed(slateEditor.selection), path = slateDom.DOMEditor.findPath(slateEditor, props.element), [block] = getPointBlock({
editor: slateEditor,
point: {
path,
offset: 0
}
});
return block || console.error(`Unable to find parent block of inline object ${props.element._key}`), /* @__PURE__ */ jsxRuntime.jsxs("span", { ...props.attributes, draggable: !props.readOnly, className: "pt-inline-object", "data-child-key": props.inlineObject._key, "data-child-name": props.inlineObject._type, "data-child-type": "object", children: [
props.children,
/* @__PURE__ */ jsxRuntime.jsx("span", { ref: inlineObjectRef, style: {
display: "inline-block"
}, children: props.renderChild && block && legacySchemaType ? props.renderChild({
annotations: [],
children: /* @__PURE__ */ jsxRuntime.jsx(RenderDefaultInlineObject, { inlineObject: props.inlineObject }),
editorElementRef: inlineObjectRef,
selected,
focused,
path: [{
_key: block._key
}, "children", {
_key: props.element._key
}],
schemaType: legacySchemaType,
value: props.inlineObject,
type: legacySchemaType
}) : /* @__PURE__ */ jsxRuntime.jsx(RenderDefaultInlineObject, { inlineObject: props.inlineObject }) })
] });
}
function RenderTextBlock(props) {
const [dragPositionBlock, setDragPositionBlock] = React.useState(), blockRef = React.useRef(null), slateEditor = slateReact.useSlateStatic(), selected = slateReact.useSelected(), editorActor = React.useContext(EditorActorContext);
useCoreBlockElementBehaviors({
key: props.element._key,
onSetDragPositionBlock: setDragPositionBlock
});
const legacySchema = react.useSelector(editorActor, (s) => s.context.getLegacySchema()), focused = selected && slateEditor.selection !== null && slate.Range.isCollapsed(slateEditor.selection);
let children = props.children;
const legacyBlockSchemaType = legacySchema.block;
if (props.renderStyle && props.textBlock.style) {
const legacyStyleSchemaType = props.textBlock.style !== void 0 ? legacySchema.styles.find((style) => style.value === props.textBlock.style) : void 0;
legacyStyleSchemaType ? children = props.renderStyle({
block: props.textBlock,
children,
editorElementRef: blockRef,
focused,
path: [{
_key: props.textBlock._key
}],
schemaType: legacyStyleSchemaType,
selected,
value: props.textBlock.style
}) : console.error(`Unable to find Schema type for text block style ${props.textBlock.style}`);
}
if (props.renderListItem && props.textBlock.listItem) {
const legacyListItemSchemaType = legacySchema.lists.find((list) => list.value === props.textBlock.listItem);
legacyListItemSchemaType ? children = props.renderListItem({
block: props.textBlock,
children,
editorElementRef: blockRef,
focused,
level: props.textBlock.level ?? 1,
path: [{
_key: props.textBlock._key
}],
selected,
value: props.textBlock.listItem,
schemaType: legacyListItemSchemaType
}) : console.error(`Unable to find Schema type for text block list item ${props.textBlock.listItem}`);
}
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ...props.attributes, className: ["pt-block", "pt-text-block", ...props.textBlock.style ? [`pt-text-block-style-${props.textBlock.style}`] : [], ...props.textBlock.listItem ? ["pt-list-item", `pt-list-item-${props.textBlock.listItem}`, `pt-list-item-level-${props.textBlock.level ?? 1}`] : []].join(" "), spellCheck: props.spellCheck, "data-block-key": props.textBlock._key, "data-block-name": props.textBlock._type, "data-block-type": "text", ...props.textBlock.listItem !== void 0 ? {
"data-list-item": props.textBlock.listItem
} : {}, ...props.textBlock.level !== void 0 ? {
"data-level": props.textBlock.level
} : {}, ...props.textBlock.style !== void 0 ? {
"data-style": props.textBlock.style
} : {}, children: [
dragPositionBlock === "start" ? /* @__PURE__ */ jsxRuntime.jsx(DropIndicator, {}) : null,
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: blockRef, children: props.renderBlock ? props.renderBlock({
children,
editorElementRef: blockRef,
focused,
level: props.textBlock.level,
listItem: props.textBlock.listItem,
path: [{
_key: props.textBlock._key
}],
selected,
schemaType: legacyBlockSchemaType,
style: props.textBlock.style,
type: legacyBlockSchemaType,
value: props.textBlock
}) : children }),
dragPositionBlock === "end" ? /* @__PURE__ */ jsxRuntime.jsx(DropIndicator, {}) : null
] });
}
function RenderElement(props) {
const $ = reactCompilerRuntime.c(43), editorActor = React.useContext(EditorActorContext), schema2 = react.useSelector(editorActor, _temp$1);
if ("__inline" in props.element && props.element.__inline === !0) {
let t02;
$[0] !== props.element ? (t02 = "value" in props.element && typeof props.element.value == "object" ? props.element.value : {}, $[0] = props.element, $[1] = t02) : t02 = $[1];
let t12;
$[2] !== props.element._key || $[3] !== props.element._type || $[4] !== t02 ? (t12 = {
_key: props.element._key,
_type: props.element._type,
...t02
}, $[2] = props.element._key, $[3] = props.element._type, $[4] = t02, $[5] = t12) : t12 = $[5];
const inlineObject = t12;
schema2.inlineObjects.find((inlineObject_0) => inlineObject_0.name === props.element._type) || console.error(`Unable to find Inline Object "${props.element._type}" in Schema`);
let t22;
$[6] !== inlineObject || $[7] !== props.element._key || $[8] !== props.element._type ? (t22 = inlineObject ?? {
_key: props.element._key,
_type: props.element._type
}, $[6] = inlineObject, $[7] = props.element._key, $[8] = props.element._type, $[9] = t22) : t22 = $[9];
let t32;
return $[10] !== props.attributes || $[11] !== props.children || $[12] !== props.element || $[13] !== props.readOnly || $[14] !== props.renderChild || $[15] !== t22 ? (t32 = /* @__PURE__ */ jsxRuntime.jsx(RenderInlineObject, { attributes: props.attributes, element: props.element, inlineObject: t22, readOnly: props.readOnly, renderChild: props.renderChild, children: props.children }), $[10] = props.attributes, $[11] = props.children, $[12] = props.element, $[13] = props.readOnly, $[14] = props.renderChild, $[15] = t22, $[16] = t32) : t32 = $[16], t32;
}
if (selectionPoint.isTextBlock({
schema: schema2
}, props.element)) {
let t02;
return $[17] !== props.attributes || $[18] !== props.children || $[19] !== props.element || $[20] !== props.readOnly || $[21] !== props.renderBlock || $[22] !== props.renderListItem || $[23] !== props.renderStyle || $[24] !== props.spellCheck ? (t02 = /* @__PURE__ */ jsxRuntime.jsx(RenderTextBlock, { attributes: props.attributes, element: props.element, readOnly: props.readOnly, renderBlock: props.renderBlock, renderListItem: props.renderListItem, renderStyle: props.renderStyle, spellCheck: props.spellCheck, textBlock: props.element, children: props.children }), $[17] = props.attributes, $[18] = props.children, $[19] = props.element, $[20] = props.readOnly, $[21] = props.renderBlock, $[22] = props.renderListItem, $[23] = props.renderStyle, $[24] = props.spellCheck, $[25] = t02) : t02 = $[25], t02;
}
let t0;
$[26] !== props.element ? (t0 = "value" in props.element && typeof props.element.value == "object" ? props.element.value : {}, $[26] = props.element, $[27] = t0) : t0 = $[27];
let t1;
$[28] !== props.element._key || $[29] !== props.element._type || $[30] !== t0 ? (t1 = {
_key: props.element._key,
_type: props.element._type,
...t0
}, $[28] = props.element._key, $[29] = props.element._type, $[30] = t0, $[31] = t1) : t1 = $[31];
const blockObject = t1;
schema2.blockObjects.find((blockObject_0) => blockObject_0.name === props.element._type) || console.error(`Unable to find Block Object "${props.element._type}" in Schema`);
let t2;
$[32] !== blockObject || $[33] !== props.element._key || $[34] !== props.element._type ? (t2 = blockObject ?? {
_key: props.element._key,
_type: props.element._type
}, $[32] = blockObject, $[33] = props.element._key, $[34] = props.element._type, $[35] = t2) : t2 = $[35];
let t3;
return $[36] !== props.attributes || $[37] !== props.children || $[38] !== props.element || $[39] !== props.readOnly || $[40] !== props.renderBlock || $[41] !== t2 ? (t3 = /* @__PURE__ */ jsxRuntime.jsx(RenderBlockObject, { attributes: props.attributes, blockObject: t2, element: props.element, readOnly: props.readOnly, renderBlock: props.renderBlock, children: props.children }), $[36] = props.attributes, $[37] = props.children, $[38] = props.element, $[39] = props.readOnly, $[40] = props.renderBlock, $[41] = t2, $[42] = t3) : t3 = $[42], t3;
}
function _temp$1(s) {
return s.context.schema;
}
const PortableTextEditorContext = React.createContext(null), usePortableTextEditor = () => {
const editor = React.useContext(PortableTextEditorContext);
if (!editor)
throw new Error("The `usePortableTextEditor` hook must be used inside the <PortableTextEditor> component's context.");
return editor;
}, forEachActor = (actorRef, callback) => {
callback(actorRef);
const children = actorRef.getSnapshot().children;
children && Object.values(children).forEach((child) => {
forEachActor(child, callback);
});
};
function stopActor(actorRef) {
const persistedSnapshots = [];
forEachActor(actorRef, (ref) => {
persistedSnapshots.push([ref, ref.getSnapshot()]), ref.observers = /* @__PURE__ */ new Set();
});
const systemSnapshot = actorRef.system.getSnapshot?.();
actorRef.stop(), actorRef.system._snapshot = systemSnapshot, persistedSnapshots.forEach(([ref, snapshot]) => {
ref._processingStatus = 0, ref._snapshot = snapshot;
});
}
const converterJson = {
mimeType: "application/json",
serialize: ({
snapshot,
event
}) => {
const portableTextConverter = snapshot.context.converters.find((converter) => converter.mimeType === "application/x-portable-text");
return portableTextConverter ? {
...portableTextConverter.serialize({
snapshot,
event
}),
mimeType: "application/json",
originEvent: event.originEvent
} : {
type: "serialization.failure",
mimeType: "application/json",
originEvent: event.originEvent,
reason: "No application/x-portable-text Converter found"
};
},
deserialize: ({
snapshot,
event
}) => {
const portableTextConverter = snapshot.context.converters.find((converter) => converter.mimeType === "application/x-portable-text");
return portableTextConverter ? {
...portableTextConverter.deserialize({
snapshot,
event
}),
mimeType: "application/json"
} : {
type: "deserialization.failure",
mimeType: "application/json",
reason: "No application/x-portable-text Converter found"
};
}
}, converterPortableText = {
mimeType: "application/x-portable-text",
serialize: ({
snapshot,
event
}) => {
const selection = snapshot.context.selection;
if (!selection)
return {
type: "serialization.failure",
mimeType: "application/x-portable-text",
originEvent: event.originEvent,
reason: "No selection"
};
const blocks = selectionPoint.sliceBlocks({
context: {
selection,
schema: snapshot.context.schema
},
blocks: snapshot.context.value
});
return blocks.length === 0 ? {
type: "serialization.failure",
mimeType: "application/x-portable-text",
reason: "No blocks serialized",
originEvent: event.originEvent
} : {
type: "serialization.success",
data: JSON.stringify(blocks),
mimeType: "application/x-portable-text",
originEvent: event.originEvent
};
},
deserialize: ({
snapshot,
event
}) => {
const blocks = JSON.parse(event.data);
if (!Array.isArray(blocks))
return {
type: "deserialization.failure",
mimeType: "application/x-portable-text",
reason: "Data is not an array"
};
const parsedBlocks = blocks.flatMap((block) => {
const parsedBlock = selectionPoint.parseBlock({
context: snapshot.context,
block,
options: {
refreshKeys: !0,
validateFields: !1
}
});
return parsedBlock ? [parsedBlock] : [];
});
return parsedBlocks.length === 0 && blocks.length > 0 ? {
type: "deserialization.failure",
mimeType: "application/x-portable-text",
reason: "No blocks were parsed"
} : {
type: "deserialization.success",
data: parsedBlocks,
mimeType: "application/x-portable-text"
};
}
};
function createConverterTextHtml(legacySchema) {
return {
mimeType: "text/html",
serialize: ({
snapshot,
event
}) => {
const selection = snapshot.context.selection;
if (!selection)
return {
type: "serialization.failure",
mimeType: "text/html",
originEvent: event.originEvent,
reason: "No selection"
};
const blocks = selectionPoint.sliceBlocks({
context: {
selection,
schema: snapshot.context.schema
},
blocks: snapshot.context.value
}), html = toHtml.toHTML(blocks, {
onMissingComponent: !1,
components: {
unknownType: ({
children
}) => children !== void 0 ? `${children}` : ""
}
});
return html === "" ? {
type: "serialization.failure",
mimeType: "text/html",
originEvent: event.originEvent,
reason: "Serialized HTML is empty"
} : {
type: "serialization.success",
data: html,
mimeType: "text/html",
originEvent: event.originEvent
};
},
deserialize: ({
snapshot,
event
}) => {
const parsedBlocks = blockTools.htmlToBlocks(event.data, legacySchema.portableText, {
keyGenerator: snapshot.context.keyGenerator,
unstable_whitespaceOnPasteMode: legacySchema.block.options.unstable_whitespaceOnPasteMode
}).flatMap((block) => {
const parsedBlock = selectionPoint.parseBlock({
context: snapshot.context,
block,
options: {
refreshKeys: !1,
validateFields: !0
}
});
return parsedBlock ? [parsedBlock] : [];
});
return parsedBlocks.length === 0 ? {
type: "deserialization.failure",
mimeType: "text/html",
reason: "No blocks deserialized"
} : {
type: "deserialization.success",
data: parsedBlocks,
mimeType: "text/html"
};
}
};
}
function createConverterTextPlain(legacySchema) {
return {
mimeType: "text/plain",
serialize: ({
snapshot,
event
}) => {
const selection = snapshot.context.selection;
return selection ? {
type: "serialization.success",
data: selectionPoint.sliceBlocks({
context: {
selection,
schema: snapshot.context.schema
},
blocks: snapshot.context.value
}).map((block) => selectionPoint.isTextBlock(snapshot.context, block) ? block.children.map((child) => child._type === snapshot.context.schema.span.name ? child.text : event.originEvent === "drag.dragstart" ? `[${snapshot.context.schema.inlineObjects.find((inlineObjectType) => inlineObjectType.name === child._type)?.title ?? "Object"}]` : "").join("") : event.originEvent === "drag.dragstart" ? `[${snapshot.context.schema.blockObjects.find((blockObjectType) => blockObjectType.name === block._type)?.title ?? "Object"}]` : "").filter((block) => block !== "").join(`
`),
mimeType: "text/plain",
originEvent: event.originEvent
} : {
type: "serialization.failure",
mimeType: "text/plain",
originEvent: event.originEvent,
reason: "No selection"
};
},
deserialize: ({
snapshot,
event
}) => {
const textToHtml = `<html><body>${escapeHtml(event.data).split(/\n{2,}/).map((line) => line ? `<p>${line.replace(/(?:\r\n|\r|\n)/g, "<br/>")}</p>` : "<p></p>").join("")}</body></html>`, parsedBlocks = blockTools.htmlToBlocks(textToHtml, legacySchema.portableText, {
keyGenerator: snapshot.context.keyGenerator
}).flatMap((block) => {
const parsedBlock = selectionPoint.parseBlock({
context: snapshot.context,
block,
options: {
refreshKeys: !1,
validateFields: !0
}
});
return parsedBlock ? [parsedBlock] : [];
});
return parsedBlocks.length === 0 ? {
type: "deserialization.failure",
mimeType: "text/plain",
reason: "No blocks deserialized"
} : {
type: "deserialization.success",
data: parsedBlocks,
mimeType: "text/plain"
};
}
};
}
const entityMap = {
"&": "&",
"<": "<",
">": ">",
'"': """,
"'": "'",
"/": "/",
"`": "`",
"=": "="
};
function escapeHtml(str) {
return String(str).replace(/[&<>"'`=/]/g, (s) => entityMap[s]);
}
function createCoreConverters(legacySchema) {
return [converterJson, converterPortableText, createConverterTextHtml(legacySchema), createConverterTextPlain(legacySchema)];
}
function compileType(rawType) {
return schema.Schema.compile({
name: "blockTypeSchema",
types: [rawType]
}).get(rawType.name);
}
function createPlaceholderBlock(context) {
return {
_type: context.schema.block.name,
_key: context.keyGenerator(),
style: context.schema.styles[0].name ?? "normal",
markDefs: [],
children: [{
_type: context.schema.span.name,
_key: context.keyGenerator(),
text: "",
marks: []
}]
};
}
function getActiveAnnotations({
markState,
schema: schema2
}) {
return (markState?.marks ?? []).filter((mark) => !schema2.decorators.map((decorator) => decorator.name).includes(mark));
}
function getActiveDecorators({
decoratorState,
markState,
schema: schema2
}) {
const decorators = schema2.decorators.map((decorator) => decorator.name);
let activeDecorators = (markState?.marks ?? []).filter((mark) => decorators.includes(mark));
for (const decorator in decoratorState)
decoratorState[decorator] === !1 ? activeDecorators = activeDecorators.filter((activeDecorator) =>