Skip to content

Instantly share code, notes, and snippets.

@brendancarney
Created May 13, 2019 20:31
Show Gist options
  • Save brendancarney/d10ca54cefbdbcfa222d381735d74cce to your computer and use it in GitHub Desktop.
Save brendancarney/d10ca54cefbdbcfa222d381735d74cce to your computer and use it in GitHub Desktop.
slate-captions.js
import React from "react";
import { Block, Text } from "slate";
export function createCaptioned({ type, caption, data }) {
const block =
typeof caption === "string"
? Block.create({ type: "caption", nodes: [Text.create(caption)] })
: caption;
const captioned = Block.create({
object: "block",
type: "captioned-image",
nodes: [
Block.create({
object: "block",
type,
data
}),
Block.create({
object: "block",
type: "caption",
nodes: [block]
})
]
});
return captioned;
}
export default ({ type }) => {
return {
schema: {
blocks: {
[`captioned-${type}`]: {
nodes: [
{
match: { type },
min: 1,
max: 1
},
{
match: { type: "caption" },
min: 1,
max: 1
}
],
normalize: (editor, error) => {
switch (error.code) {
case "child_min_invalid":
// caption is missing; insert a caption
if (error.index === 1) {
editor.insertNodeByKey(error.node.key, 1, {
object: "block",
type: "caption"
});
} else {
// `type` is missing; remove captioned-`type`
editor.removeNodeByKey(error.node.key);
}
return;
default:
return;
}
}
},
caption: {
nodes: [
{
match: [{ object: "inline" }, { object: "text" }]
}
]
}
}
},
commands: {
insertCaptioned: (editor, { type, caption, data }) => {
const block = createCaptioned({ type, caption, data });
editor.insertBlock(block);
}
},
renderNode(props, editor, next) {
const { node, attributes, children } = props;
switch (node.type) {
case `captioned-${type}`:
return <figure {...attributes}>{children}</figure>;
case "caption":
return (
<figcaption style={{ textAlign: "center" }} {...attributes}>
{children}
</figcaption>
);
default:
return next();
}
},
onKeyDown(event, editor, next) {
if (event.key !== "Enter" || event.shiftKey) return next();
if (editor.value.startBlock.type !== "caption") return next();
const caption = editor.value.startBlock;
const document = editor.value.document;
const captioned = document.getParent(caption.key);
const parent = document.getParent(captioned.key);
const index = parent.nodes.indexOf(captioned);
editor.insertNodeByKey(parent.key, index + 1, {
object: "block",
type: "paragraph"
});
editor.moveToEndOfBlock(captioned).moveForward(1);
}
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment