Skip to content

Commit

Permalink
Add blockquotes
Browse files Browse the repository at this point in the history
  • Loading branch information
allisonking committed Feb 25, 2025
1 parent 55dac64 commit fc8e229
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 3 deletions.
14 changes: 14 additions & 0 deletions packages/context-editor/src/commands/blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ const toggleBlockType = (options: ToggleOptions<NodeType>) => {
return setBlockFunction(state, dispatch);
};

const toggleWrap = (options: ToggleOptions<NodeType>) => {
const { state, type, dispatch } = options;
if (blockTypeIsActive(options)) {
return lift(state, dispatch);
}
return wrapIn(type)(state, dispatch);
};

const createBlockTypeToggle = (options: {
typeName: string;
withAttrs?: Attrs;
Expand All @@ -73,3 +81,9 @@ export const heading3Toggle = createHeadingBlockTypeToggle(3);
export const heading4Toggle = createHeadingBlockTypeToggle(4);
export const heading5Toggle = createHeadingBlockTypeToggle(5);
export const heading6Toggle = createHeadingBlockTypeToggle(6);
export const blockquoteToggle = createBlockTypeToggle({
typeName: "blockquote",
commandFn: toggleWrap,
});
// TODO
export const codeBlockToggle = createBlockTypeToggle({ typeName: "code_block" });
1 change: 1 addition & 0 deletions packages/context-editor/src/commands/marks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ export const createMarkToggle = (typeName: string) => {

export const strongToggle = createMarkToggle("strong");
export const emToggle = createMarkToggle("em");
export const codeToggle = createMarkToggle("code");
10 changes: 9 additions & 1 deletion packages/context-editor/src/components/MenuBar.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import type { ReactNode } from "react";

import React, { useState } from "react";
import React from "react";
import { usePluginViewContext } from "@prosemirror-adapter/react";
import { Quote } from "lucide-react";

import { Button } from "ui/button";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "ui/select";
import { cn } from "utils";

import type { CommandSpec } from "../commands/types";
import {
blockquoteToggle,
heading1Toggle,
heading2Toggle,
heading3Toggle,
Expand Down Expand Up @@ -37,6 +39,11 @@ const menuItems: MenuItem[] = [
icon: <span className="italic">I</span>,
command: emToggle,
},
{
key: "blockquote",
icon: <Quote />,
command: blockquoteToggle,
},
];

const paragraphTypeItems: MenuItem[] = [
Expand Down Expand Up @@ -90,6 +97,7 @@ const ParagraphDropdown = () => {
const { isActive } = item.command(view)(view.state);
return isActive;
})[0];

return (
<Select
value={activeType?.key}
Expand Down
6 changes: 4 additions & 2 deletions packages/context-editor/src/plugins/inputRules.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { MarkType } from "prosemirror-model";
import type { MarkType, NodeType } from "prosemirror-model";
import type { EditorState } from "prosemirror-state";

import { InputRule, inputRules } from "prosemirror-inputrules";
import { InputRule, inputRules, wrappingInputRule } from "prosemirror-inputrules";
import { Fragment, Schema } from "prosemirror-model";

import initialDoc from "../stories/initialDoc.json";
Expand Down Expand Up @@ -39,6 +39,7 @@ const applyMarkRule = (markType: MarkType, regex: RegExp) => {
}
);
};
const blockQuoteRule = (nodeType: NodeType) => wrappingInputRule(/^\s*>\s$/, nodeType);

export default (schema: Schema) => {
const rules = [
Expand All @@ -54,6 +55,7 @@ export default (schema: Schema) => {
// Prosemirror applies the first rule that matches
applyMarkRule(schema.marks.strong, boldRegex),
applyMarkRule(schema.marks.em, italicsRegex),
blockQuoteRule(schema.nodes.blockquote),
];
return inputRules({ rules });
};
31 changes: 31 additions & 0 deletions packages/context-editor/src/schemas/blockquote.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { DOMOutputSpec, MarkSpec, NodeSpec } from "prosemirror-model";

export default {
attrs: {
id: { default: null },
class: { default: null },
},
content: "block+",
group: "block",
selectable: false,
parseDOM: [
{
tag: "blockquote",
getAttrs: (node) => {
return {
id: (node as Element).getAttribute("id"),
};
},
},
],
toDOM: (node) => {
return [
"blockquote",
{
class: node.attrs.class,
...(node.attrs.id && { id: node.attrs.id }),
},
0,
] as DOMOutputSpec;
},
} satisfies NodeSpec;
18 changes: 18 additions & 0 deletions packages/context-editor/src/schemas/code.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { DOMOutputSpec, MarkSpec } from "prosemirror-model";

export default {
attrs: {
id: { default: null },
class: { default: null },
},
parseDOM: [{ tag: "code" }],
toDOM: (mark) => {
return [
"code",
{
class: mark.attrs.class,
...(mark.attrs.id && { id: mark.attrs.id }),
},
] as DOMOutputSpec;
},
} satisfies MarkSpec;
4 changes: 4 additions & 0 deletions packages/context-editor/src/schemas/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Schema } from "prosemirror-model";

import blockquote from "./blockquote";
import inlineCode from "./code";
import contextAtom from "./contextAtom";
import contextDoc from "./contextDoc";
// import { marks, nodes } from "prosemirror-schema-basic";
Expand All @@ -21,10 +23,12 @@ export const baseSchema = new Schema({
heading,
contextDoc,
contextAtom,
blockquote,
},
marks: {
strong,
em,
code: inlineCode,
},
topNode: "doc",
});
4 changes: 4 additions & 0 deletions packages/context-editor/src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,7 @@
overflow: scroll;
position: relative;
}
.ProseMirror blockquote {
padding-left: 1rem;
border-left: solid 4px rgba(181, 181, 181, 0.5);
}

0 comments on commit fc8e229

Please sign in to comment.