@portabletext/plugin-one-line
Version:
🤏 Restricts the Portable Text Editor to a single line
104 lines (103 loc) • 3.15 kB
JavaScript
import { useEditor } from "@portabletext/editor";
import { defineBehavior, execute, raise } from "@portabletext/editor/behaviors";
import * as selectors from "@portabletext/editor/selectors";
import * as utils from "@portabletext/editor/utils";
import { useEffect } from "react";
const oneLineBehaviors = [
/**
* Hitting Enter on an expanded selection should just delete that selection
* without causing a line break.
*/
defineBehavior({
on: "insert.break",
guard: ({ snapshot }) => snapshot.context.selection && selectors.isSelectionExpanded(snapshot) ? { selection: snapshot.context.selection } : !1,
actions: [(_, { selection }) => [execute({ type: "delete", at: selection })]]
}),
/**
* All other cases of `insert.break` should be aborted.
*/
defineBehavior({
on: "insert.break",
actions: []
}),
/**
* `insert.block` `before` or `after` is not allowed in a one-line editor.
*/
defineBehavior({
on: "insert.block",
guard: ({ event }) => event.placement === "before" || event.placement === "after",
actions: []
}),
/**
* An ordinary `insert.block` is acceptable if it's a text block. In that
* case it will get merged into the existing text block.
*/
defineBehavior({
on: "insert.block",
guard: ({ snapshot, event }) => !(!selectors.getFocusTextBlock(snapshot) || !utils.isTextBlock(snapshot.context, event.block)),
actions: [
({ event }) => [
execute({
type: "insert.block",
block: event.block,
placement: "auto",
select: "end"
})
]
]
}),
/**
* Fallback Behavior to avoid `insert.block` in case the Behaviors above all
* end up with a falsy guard.
*/
defineBehavior({
on: "insert.block",
actions: []
}),
/**
* If multiple blocks are inserted, then the non-text blocks are filtered out
* and the text blocks are merged into one block
*/
defineBehavior({
on: "insert.blocks",
guard: ({ snapshot, event }) => {
const textBlocks = event.blocks.filter(
(block) => utils.isTextBlock(snapshot.context, block)
);
return textBlocks.length === 0 ? !1 : textBlocks.reduce((targetBlock, incomingBlock) => utils.mergeTextBlocks({
context: snapshot.context,
targetBlock,
incomingBlock
}));
},
actions: [
// `insert.block` is raised so the Behavior above can handle the
// insertion
(_, block) => [raise({ type: "insert.block", block, placement: "auto" })]
]
}),
/**
* Fallback Behavior to avoid `insert.blocks` in case the Behavior above
* ends up with a falsy guard.
*/
defineBehavior({
on: "insert.blocks",
actions: []
})
];
function OneLinePlugin() {
const editor = useEditor();
return useEffect(() => {
const unregisterBehaviors = oneLineBehaviors.map(
(behavior) => editor.registerBehavior({ behavior })
);
return () => {
for (const unregisterBehavior of unregisterBehaviors)
unregisterBehavior();
};
}, [editor]), null;
}
export {
OneLinePlugin
};
//# sourceMappingURL=index.js.map