Skip to content

Vanilla example #78

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jan 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 0 additions & 32 deletions examples/editor/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,3 @@ root.render(
<App />
</React.StrictMode>
);

// TODO: Separate non-React example using code below.
// import { mountBlockNoteEditor } from "@blocknote/core";
// import "@blocknote/core/style.css";
// import {
// ReactBubbleMenuFactory,
// ReactHyperlinkMenuFactory,
// ReactSuggestionsMenuFactory,
// } from "@blocknote/react";
// import styles from "./App.module.css";
// import "./index.css";
//
// mountBlockNoteEditor(
// {
// bubbleMenuFactory: ReactBubbleMenuFactory,
// hyperlinkMenuFactory: ReactHyperlinkMenuFactory,
// suggestionsMenuFactory: ReactSuggestionsMenuFactory,
// },
// {
// element: document.getElementById("root")!,
// onUpdate: ({ editor }) => {
// console.log(editor.getJSON());
// (window as any).ProseMirror = editor; // Give tests a way to get editor instance
// },
// editorProps: {
// attributes: {
// class: styles.editor,
// "data-test": "editor",
// },
// },
// }
// );
24 changes: 24 additions & 0 deletions examples/vanilla/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
3 changes: 3 additions & 0 deletions examples/vanilla/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Vanilla editor example

This is an example client application that consumes @blocknote/core.
13 changes: 13 additions & 0 deletions examples/vanilla/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<!-- <link rel="icon" type="image/svg+xml" href="/src/favicon.svg" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BlockNote demo vanilla js</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
30 changes: 30 additions & 0 deletions examples/vanilla/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "@blocknote/example-vanilla",
"private": true,
"version": "0.1.2",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"lint": "eslint src --max-warnings 0"
},
"dependencies": {
"@blocknote/core": "^0.1.2"
},
"devDependencies": {
"eslint": "^8.10.0",
"eslint-config-react-app": "^7.0.0",
"typescript": "^4.5.4",
"vite": "^3.0.5",
"vite-plugin-eslint": "^1.7.0"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
],
"rules": {
"curly": 1
}
}
}
10 changes: 10 additions & 0 deletions examples/vanilla/src/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
html,
body,
#root {
height: 100%;
}

.editor {
padding: 0 calc((100% - 731px) / 2);
height: 100%;
}
31 changes: 31 additions & 0 deletions examples/vanilla/src/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { BlockNoteEditor } from "@blocknote/core";
import "./index.css";
import { blockMenuFactory } from "./ui/blockMenuFactory";
import { bubbleMenuFactory } from "./ui/bubbleMenuFactory";
import { hyperlinkMenuFactory } from "./ui/hyperlinkMenuFactory";
import { suggestionsMenuFactory } from "./ui/suggestionsMenuFactory";

const editor = new BlockNoteEditor({
element: document.getElementById("root")!,
uiFactories: {
// Create an example bubble menu which just consists of a bold toggle
bubbleMenuFactory,
// Create an example menu for hyperlinks
hyperlinkMenuFactory,
// Create an example menu for the /-menu
suggestionsMenuFactory,
// Create an example menu for when a block is hovered
blockMenuFactory,
},
onUpdate: ({ editor }) => {
console.log(editor.getJSON());
(window as any).ProseMirror = editor; // Give tests a way to get editor instance
},
editorProps: {
attributes: {
class: "editor",
},
},
});

console.log("editor created", editor);
49 changes: 49 additions & 0 deletions examples/vanilla/src/ui/blockMenuFactory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { BlockMenuFactory } from "@blocknote/core";
import { createButton } from "./util";

/**
* This menu is drawn next to a block, when it's hovered over
* It renders a drag handle and + button to create a new block
*/
export const blockMenuFactory: BlockMenuFactory = (props) => {
const container = document.createElement("div");
container.style.background = "gray";
container.style.position = "absolute";
container.style.padding = "10px";
container.style.opacity = "0.8";
const addBtn = createButton("+", () => {
props.addBlock();
});
container.appendChild(addBtn);

const dragBtn = createButton("::", () => {
// TODO: render a submenu with a delete option that calls "props.deleteBlock"
});

dragBtn.addEventListener("dragstart", props.blockDragStart);
dragBtn.addEventListener("dragend", props.blockDragEnd);
container.style.display = "none";
container.appendChild(dragBtn);

document.body.appendChild(container);

return {
element: container,
show: (params) => {
container.style.display = "block";
console.log("show blockmenu", params);
container.style.top = params.blockBoundingBox.y + "px";
container.style.left =
params.blockBoundingBox.x - container.offsetWidth + "px";
},
hide: () => {
container.style.display = "none";
},
update: (params) => {
console.log("update blockmenu", params);
container.style.top = params.blockBoundingBox.y + "px";
container.style.left =
params.blockBoundingBox.x - container.offsetWidth + "px";
},
};
};
47 changes: 47 additions & 0 deletions examples/vanilla/src/ui/bubbleMenuFactory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { BubbleMenuFactory } from "@blocknote/core";
import { createButton } from "./util";

/**
* This menu is drawn when a piece of text is selected. We can use it to change formatting options
* such as bold, italic, indentation, etc.
*/
export const bubbleMenuFactory: BubbleMenuFactory = (props) => {
const container = document.createElement("div");
container.style.background = "gray";
container.style.position = "absolute";
container.style.padding = "10px";
container.style.opacity = "0.8";
const boldBtn = createButton("set bold", () => {
props.toggleBold();
});
container.appendChild(boldBtn);

const linkBtn = createButton("set link", () => {
props.setHyperlink("https://www.google.com");
});

container.appendChild(boldBtn);
container.appendChild(linkBtn);
container.style.display = "none";
document.body.appendChild(container);

return {
element: container,
show: (params) => {
container.style.display = "block";
console.log("show bubble", params);
boldBtn.text = params.boldIsActive ? "unset bold" : "set bold";
container.style.top = params.selectionBoundingBox.y + "px";
container.style.left = params.selectionBoundingBox.x + "px";
},
hide: () => {
container.style.display = "none";
},
update: (params) => {
console.log("update bubble", params);
boldBtn.text = params.boldIsActive ? "unset bold" : "set bold";
container.style.top = params.selectionBoundingBox.y + "px";
container.style.left = params.selectionBoundingBox.x + "px";
},
};
};
48 changes: 48 additions & 0 deletions examples/vanilla/src/ui/hyperlinkMenuFactory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { HyperlinkMenuFactory } from "@blocknote/core";
import { createButton } from "./util";

/**
* This menu is drawn when the cursor is moved to a hyperlink (using the keyboard),
* or when the mouse is hovering over a hyperlink
*/
export const hyperlinkMenuFactory: HyperlinkMenuFactory = (props) => {
const container = document.createElement("div");
container.style.background = "gray";
container.style.position = "absolute";
container.style.padding = "10px";
container.style.opacity = "0.8";

const editBtn = createButton("edit", () => {
const newUrl = prompt("new url") || props.url;
props.editHyperlink(newUrl, props.text);
});
container.appendChild(editBtn);

const removeBtn = createButton("remove", () => {
props.deleteHyperlink();
});

container.appendChild(editBtn);
container.appendChild(removeBtn);
container.style.display = "none";
document.body.appendChild(container);

return {
element: container,
show: (params) => {
container.style.display = "block";
console.log("show", params);

container.style.top = params.boundingBox.y + "px";
container.style.left = params.boundingBox.x + "px";
},
hide: () => {
container.style.display = "none";
},
update: (params) => {
console.log("update", params);
container.style.top = params.boundingBox.y + "px";
container.style.left = params.boundingBox.x + "px";
},
};
};
59 changes: 59 additions & 0 deletions examples/vanilla/src/ui/suggestionsMenuFactory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { SuggestionItem, SuggestionsMenuFactory } from "@blocknote/core";
import { createButton } from "./util";

/**
* This menu is drawn when the cursor is moved to a hyperlink (using the keyboard),
* or when the mouse is hovering over a hyperlink
*/
export const suggestionsMenuFactory: SuggestionsMenuFactory<SuggestionItem> = (
props
) => {
const container = document.createElement("div");
container.style.background = "gray";
container.style.position = "absolute";
container.style.padding = "10px";
container.style.opacity = "0.8";
container.style.display = "none";
document.body.appendChild(container);

function updateItems(
items: SuggestionItem[],
onClick: (item: SuggestionItem) => void,
selected: number
) {
container.innerHTML = "";
const domItems = items.map((val, i) => {
const element = createButton(val.name, () => {
onClick(val);
});
element.style.display = "block";
if (selected === i) {
element.style.fontWeight = "bold";
}
return element;
});
container.append(...domItems);
return domItems;
}

return {
element: container,
show: (params) => {
updateItems(params.items, params.itemCallback, params.selectedItemIndex);
container.style.display = "block";
console.log("show", params);

container.style.top = params.queryStartBoundingBox.y + "px";
container.style.left = params.queryStartBoundingBox.x + "px";
},
hide: () => {
container.style.display = "none";
},
update: (params) => {
console.log("update", params);
updateItems(params.items, params.itemCallback, params.selectedItemIndex);
container.style.top = params.queryStartBoundingBox.y + "px";
container.style.left = params.queryStartBoundingBox.x + "px";
},
};
};
11 changes: 11 additions & 0 deletions examples/vanilla/src/ui/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export function createButton(text: string, onClick: () => void) {
const element = document.createElement("a");
element.href = "#";
element.text = text;
element.style.margin = "10px";
element.addEventListener("click", (e) => {
onClick();
e.preventDefault();
});
return element;
}
1 change: 1 addition & 0 deletions examples/vanilla/src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
Loading