From 325a85f1de618ec1dc9347aee19b6875b54e2dfa Mon Sep 17 00:00:00 2001 From: Matthew Lipski Date: Fri, 1 Dec 2023 15:42:26 +0100 Subject: [PATCH 1/2] Added playground for vanilla styles and added simple image block --- .../examples/react-custom-blocks/App.tsx | 53 ++++--- .../examples/react-custom-styles/App.tsx | 50 +----- .../examples/vanilla-custom-blocks/App.tsx | 63 ++++---- .../examples/vanilla-custom-blocks/style.css | 17 ++ .../examples/vanilla-custom-styles/App.tsx | 146 ++++++++++++++++++ 5 files changed, 235 insertions(+), 94 deletions(-) create mode 100644 examples/editor/examples/vanilla-custom-blocks/style.css create mode 100644 examples/editor/examples/vanilla-custom-styles/App.tsx diff --git a/examples/editor/examples/react-custom-blocks/App.tsx b/examples/editor/examples/react-custom-blocks/App.tsx index 43750998a0..16ed570114 100644 --- a/examples/editor/examples/react-custom-blocks/App.tsx +++ b/examples/editor/examples/react-custom-blocks/App.tsx @@ -5,6 +5,7 @@ import { createReactBlockSpec, useBlockNote, } from "@blocknote/react"; +import "../vanilla-custom-blocks/style.css"; type WindowWithProseMirror = Window & typeof globalThis & { ProseMirror: any }; @@ -48,14 +49,8 @@ export const alertBlock = createReactBlockSpec( { render: (props) => (
-
+
), } ); +const simpleImageBlock = createReactBlockSpec( + { + type: "simpleImage", + propSchema: { + src: { + default: + "https://www.pulsecarshalton.co.uk/wp-content/uploads/2016/08/jk-placeholder-image.jpg", + }, + }, + content: "none", + }, + { + render: (props) => ( + placeholder + ), + } +); + export const bracketsParagraphBlock = createReactBlockSpec( { type: "bracketsParagraph", @@ -88,19 +105,10 @@ export const bracketsParagraphBlock = createReactBlockSpec( }, { render: (props) => ( -
+
{"["}
{"{"} -
+
{"}"}
{"]"}
@@ -119,6 +127,7 @@ export function ReactCustomBlocks() { blockSpecs: { ...defaultBlockSpecs, alert: alertBlock, + simpleImage: simpleImageBlock, bracketsParagraph: bracketsParagraphBlock, }, initialContent: [ @@ -129,6 +138,12 @@ export function ReactCustomBlocks() { }, content: "Alert", }, + { + type: "simpleImage", + props: { + src: "https://t3.ftcdn.net/jpg/02/48/42/64/360_F_248426448_NVKLywWqArG2ADUxDq6QprtIzsF82dMF.jpg", + }, + }, { type: "bracketsParagraph", content: "Brackets Paragraph", diff --git a/examples/editor/examples/react-custom-styles/App.tsx b/examples/editor/examples/react-custom-styles/App.tsx index 6c82ca2bcf..90ccabcc85 100644 --- a/examples/editor/examples/react-custom-styles/App.tsx +++ b/examples/editor/examples/react-custom-styles/App.tsx @@ -1,21 +1,12 @@ +import { defaultStyleSpecs } from "@blocknote/core"; import "@blocknote/core/style.css"; import { BlockNoteView, - FormattingToolbarPositioner, - Toolbar, - ToolbarButton, createReactStyleSpec, - useActiveStyles, + FormattingToolbarPositioner, useBlockNote, } from "@blocknote/react"; - -import { - BlockNoteEditor, - DefaultBlockSchema, - DefaultInlineContentSchema, - StyleSchemaFromSpecs, - defaultStyleSpecs, -} from "@blocknote/core"; +import { CustomFormattingToolbar } from "../vanilla-custom-styles/App"; type WindowWithProseMirror = Window & typeof globalThis & { ProseMirror: any }; @@ -51,41 +42,6 @@ const customReactStyles = { fontSize, }; -type MyEditorType = BlockNoteEditor< - DefaultBlockSchema, - DefaultInlineContentSchema, - StyleSchemaFromSpecs ->; - -const CustomFormattingToolbar = (props: { editor: MyEditorType }) => { - const activeStyles = useActiveStyles(props.editor); - - return ( - - { - props.editor.toggleStyles({ - small: true, - }); - }} - isSelected={activeStyles.small}> - Small - - { - props.editor.toggleStyles({ - fontSize: "30px", - }); - }} - isSelected={!!activeStyles.fontSize}> - Font size - - - ); -}; - export function ReactStyles() { const editor = useBlockNote( { diff --git a/examples/editor/examples/vanilla-custom-blocks/App.tsx b/examples/editor/examples/vanilla-custom-blocks/App.tsx index 2bdfde7ce9..dadb8b9c67 100644 --- a/examples/editor/examples/vanilla-custom-blocks/App.tsx +++ b/examples/editor/examples/vanilla-custom-blocks/App.tsx @@ -5,6 +5,7 @@ import { } from "@blocknote/core"; import "@blocknote/core/style.css"; import { BlockNoteView, useBlockNote } from "@blocknote/react"; +import "./style.css"; type WindowWithProseMirror = Window & typeof globalThis & { ProseMirror: any }; @@ -48,9 +49,7 @@ const alertBlock = createBlockSpec( { render: (block, editor) => { const alert = document.createElement("div"); - Object.entries(alertStyles).forEach(([key, value]) => { - alert.style[key as any] = value; - }); + alert.className = "alert"; alert.style.backgroundColor = alertTypes[block.props.type].backgroundColor; @@ -110,16 +109,30 @@ const alertBlock = createBlockSpec( } ); -// TODO: use CSS? -const alertStyles = { - display: "flex", - justifyContent: "center", - alignItems: "center", - flexGrow: "1", - height: "48px", - padding: "4px", - maxWidth: "100%", -}; +const simpleImageBlock = createBlockSpec( + { + type: "simpleImage", + propSchema: { + src: { + default: + "https://www.pulsecarshalton.co.uk/wp-content/uploads/2016/08/jk-placeholder-image.jpg", + }, + }, + content: "none", + }, + { + render: (block) => { + const image = document.createElement("img"); + image.className = "simple-image"; + image.src = block.props.src; + image.alt = "placeholder"; + + return { + dom: image, + }; + }, + } +); const bracketsParagraphBlock = createBlockSpec( { @@ -132,9 +145,7 @@ const bracketsParagraphBlock = createBlockSpec( { render: () => { const bracketsParagraph = document.createElement("div"); - Object.entries(bracketsParagraphStyles).forEach(([key, value]) => { - bracketsParagraph.style[key as any] = value; - }); + bracketsParagraph.className = "brackets-paragraph"; const leftBracket = document.createElement("div"); leftBracket.contentEditable = "false"; @@ -146,7 +157,7 @@ const bracketsParagraphBlock = createBlockSpec( bracketsParagraph.appendChild(leftCurlyBracket); const inlineContent = document.createElement("div"); - inlineContent.style.flexGrow = "1"; + inlineContent.className = "inline-content"; bracketsParagraph.appendChild(inlineContent); @@ -167,17 +178,6 @@ const bracketsParagraphBlock = createBlockSpec( } ); -// TODO: use CSS -const bracketsParagraphStyles = { - display: "flex", - justifyContent: "center", - alignItems: "center", - flexGrow: "1", - height: "48px", - padding: "4px", - maxWidth: "100%", -}; - export function CustomBlocks() { const editor = useBlockNote({ domAttributes: { @@ -190,6 +190,7 @@ export function CustomBlocks() { ...defaultBlockSpecs, alert: alertBlock, bracketsParagraph: bracketsParagraphBlock, + simpleImage: simpleImageBlock, }, initialContent: [ { @@ -199,6 +200,12 @@ export function CustomBlocks() { }, content: ["Alert"], }, + { + type: "simpleImage", + props: { + src: "https://t3.ftcdn.net/jpg/02/48/42/64/360_F_248426448_NVKLywWqArG2ADUxDq6QprtIzsF82dMF.jpg", + }, + }, { type: "bracketsParagraph", content: "Brackets Paragraph", diff --git a/examples/editor/examples/vanilla-custom-blocks/style.css b/examples/editor/examples/vanilla-custom-blocks/style.css new file mode 100644 index 0000000000..38747f13bc --- /dev/null +++ b/examples/editor/examples/vanilla-custom-blocks/style.css @@ -0,0 +1,17 @@ +.alert, .brackets-paragraph { + display: flex; + justify-content: center; + align-items: center; + flex-grow: 1; + height: 48px; + padding: 4px; + max-width: 100%; +} + +.simple-image { + width: 100%; +} + +.inline-content { + flex-grow: 1; +} \ No newline at end of file diff --git a/examples/editor/examples/vanilla-custom-styles/App.tsx b/examples/editor/examples/vanilla-custom-styles/App.tsx new file mode 100644 index 0000000000..4c55f94e0f --- /dev/null +++ b/examples/editor/examples/vanilla-custom-styles/App.tsx @@ -0,0 +1,146 @@ +import { + BlockNoteEditor, + createStyleSpec, + DefaultBlockSchema, + DefaultInlineContentSchema, + defaultStyleSpecs, +} from "@blocknote/core"; +import "@blocknote/core/style.css"; +import { + BlockNoteView, + FormattingToolbarPositioner, + Toolbar, + ToolbarButton, + useActiveStyles, + useBlockNote, +} from "@blocknote/react"; + +type WindowWithProseMirror = Window & typeof globalThis & { ProseMirror: any }; + +const small = createStyleSpec( + { + type: "small", + propSchema: "boolean", + }, + { + render: () => { + const small = document.createElement("small"); + + return { + dom: small, + contentDOM: small, + }; + }, + } +); + +const fontSize = createStyleSpec( + { + type: "fontSize", + propSchema: "string", + }, + { + render: (value) => { + const span = document.createElement("span"); + span.style.fontSize = value; + + return { + dom: span, + contentDOM: span, + }; + }, + } +); + +type MyEditorType = BlockNoteEditor< + DefaultBlockSchema, + DefaultInlineContentSchema, + { + small: (typeof small)["config"]; + fontSize: (typeof fontSize)["config"]; + } +>; + +export const CustomFormattingToolbar = (props: { editor: MyEditorType }) => { + const activeStyles = useActiveStyles(props.editor); + + return ( + + { + props.editor.toggleStyles({ + small: true, + }); + }} + isSelected={activeStyles.small}> + Small + + { + props.editor.toggleStyles({ + fontSize: "30px", + }); + }} + isSelected={!!activeStyles.fontSize}> + Font size + + + ); +}; + +export function Styles() { + const editor = useBlockNote( + { + styleSpecs: { + ...defaultStyleSpecs, + small, + fontSize, + }, + onEditorContentChange: (editor) => { + console.log(editor.topLevelBlocks); + }, + domAttributes: { + editor: { + class: "editor", + "data-test": "editor", + }, + }, + initialContent: [ + { + type: "paragraph", + content: [ + { + type: "text", + text: "large text", + styles: { + fontSize: "30px", + }, + }, + { + type: "text", + text: "small text", + styles: { + small: true, + }, + }, + ], + }, + ], + }, + [] + ); + + // Give tests a way to get prosemirror instance + (window as WindowWithProseMirror).ProseMirror = editor?._tiptapEditor; + + return ( + + + + ); +} From ffe67a0d9c17bb7ca70e7021e14d9376764da45b Mon Sep 17 00:00:00 2001 From: Matthew Lipski Date: Mon, 4 Dec 2023 12:11:02 +0100 Subject: [PATCH 2/2] Fixed imports to make examples standalone --- examples/editor/examples/basic/App.tsx | 3 +- .../editor/examples/collaboration/App.tsx | 3 +- .../examples/react-custom-styles/App.tsx | 49 ++++++++++++++++++- .../examples/vanilla-custom-styles/App.tsx | 2 +- 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/examples/editor/examples/basic/App.tsx b/examples/editor/examples/basic/App.tsx index 6c3213b0dd..0c7ba3ccb4 100644 --- a/examples/editor/examples/basic/App.tsx +++ b/examples/editor/examples/basic/App.tsx @@ -1,8 +1,7 @@ +import { uploadToTmpFilesDotOrg_DEV_ONLY } from "@blocknote/core"; import "@blocknote/core/style.css"; import { BlockNoteView, useBlockNote } from "@blocknote/react"; -import { uploadToTmpFilesDotOrg_DEV_ONLY } from "@blocknote/core"; - type WindowWithProseMirror = Window & typeof globalThis & { ProseMirror: any }; export function App() { diff --git a/examples/editor/examples/collaboration/App.tsx b/examples/editor/examples/collaboration/App.tsx index 8bec4b84c9..083cec29ca 100644 --- a/examples/editor/examples/collaboration/App.tsx +++ b/examples/editor/examples/collaboration/App.tsx @@ -1,8 +1,7 @@ +import { uploadToTmpFilesDotOrg_DEV_ONLY } from "@blocknote/core"; import "@blocknote/core/style.css"; import { BlockNoteView, useBlockNote } from "@blocknote/react"; -import { uploadToTmpFilesDotOrg_DEV_ONLY } from "@blocknote/core"; - import YPartyKitProvider from "y-partykit/provider"; import * as Y from "yjs"; diff --git a/examples/editor/examples/react-custom-styles/App.tsx b/examples/editor/examples/react-custom-styles/App.tsx index 90ccabcc85..beee30f385 100644 --- a/examples/editor/examples/react-custom-styles/App.tsx +++ b/examples/editor/examples/react-custom-styles/App.tsx @@ -1,12 +1,19 @@ -import { defaultStyleSpecs } from "@blocknote/core"; +import { + BlockNoteEditor, + DefaultBlockSchema, + DefaultInlineContentSchema, + defaultStyleSpecs, +} from "@blocknote/core"; import "@blocknote/core/style.css"; import { BlockNoteView, createReactStyleSpec, FormattingToolbarPositioner, + Toolbar, + ToolbarButton, + useActiveStyles, useBlockNote, } from "@blocknote/react"; -import { CustomFormattingToolbar } from "../vanilla-custom-styles/App"; type WindowWithProseMirror = Window & typeof globalThis & { ProseMirror: any }; @@ -36,6 +43,44 @@ const fontSize = createReactStyleSpec( } ); +type MyEditorType = BlockNoteEditor< + DefaultBlockSchema, + DefaultInlineContentSchema, + { + small: (typeof small)["config"]; + fontSize: (typeof fontSize)["config"]; + } +>; + +const CustomFormattingToolbar = (props: { editor: MyEditorType }) => { + const activeStyles = useActiveStyles(props.editor); + + return ( + + { + props.editor.toggleStyles({ + small: true, + }); + }} + isSelected={activeStyles.small}> + Small + + { + props.editor.toggleStyles({ + fontSize: "30px", + }); + }} + isSelected={!!activeStyles.fontSize}> + Font size + + + ); +}; + const customReactStyles = { ...defaultStyleSpecs, small, diff --git a/examples/editor/examples/vanilla-custom-styles/App.tsx b/examples/editor/examples/vanilla-custom-styles/App.tsx index 4c55f94e0f..ce92919452 100644 --- a/examples/editor/examples/vanilla-custom-styles/App.tsx +++ b/examples/editor/examples/vanilla-custom-styles/App.tsx @@ -61,7 +61,7 @@ type MyEditorType = BlockNoteEditor< } >; -export const CustomFormattingToolbar = (props: { editor: MyEditorType }) => { +const CustomFormattingToolbar = (props: { editor: MyEditorType }) => { const activeStyles = useActiveStyles(props.editor); return (