@blokhaus/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,191 @@
1
+ # @blokhaus/core
2
+
3
+ The **shadcn of rich text editors** — composable, block-based Notion-style editor components for Next.js, built on [Lexical](https://lexical.dev).
4
+
5
+ Zero abstraction. Full ownership. Every component is a composable React plugin you control.
6
+
7
+ ## Features
8
+
9
+ - **Block-based editing** — headings, paragraphs, lists, blockquotes, code blocks, callouts, toggles, tables, horizontal rules
10
+ - **Floating toolbar** — appears on text selection with bold, italic, underline, strikethrough, code, link, color, highlight, font family
11
+ - **Slash menu** — type `/` to insert any block type
12
+ - **Drag-and-drop** — Notion-style block reordering with overlay handles
13
+ - **Marquee block selection** — click-drag from margins to select multiple blocks
14
+ - **Image & video uploads** — optimistic loading UI with pluggable `UploadHandler`
15
+ - **Video embeds** — YouTube, Vimeo, Loom URL detection
16
+ - **AI streaming** — pluggable `AIProvider` with streaming preview, accept/discard flow, single undo entry
17
+ - **Mentions** — `@` and `#` triggers with async search and keyboard navigation
18
+ - **Emoji picker** — inline emoji insertion via `:` trigger
19
+ - **Code blocks** — with language selection and Shiki syntax highlighting
20
+ - **Callout blocks** — Notion-style colored callouts with emoji icons
21
+ - **Toggle blocks** — collapsible content sections
22
+ - **Tables** — with column resize, header rows, cell background colors, and action menus
23
+ - **Link editing** — inline link input with preview on hover
24
+ - **Color & highlight** — text color and background highlight with customizable palette
25
+ - **Font families** — configurable font picker
26
+ - **RTL/LTR direction** — per-block text direction control
27
+ - **Paste sanitization** — cleans HTML from Google Docs, Word, and web pages
28
+ - **Mobile support** — bottom-anchored toolbar on touch devices, drag handles disabled
29
+ - **Input rules** — Markdown shortcuts (`# `, `> `, `- `, `1. `, `` ``` ``, `---`, etc.)
30
+ - **Word count** — `useWordCount` hook for live word/character counts
31
+ - **Dark mode** — full CSS variable theming with light and dark tokens
32
+ - **Multi-editor** — multiple isolated editor instances on one page
33
+
34
+ ## Install
35
+
36
+ ```bash
37
+ npm install @blokhaus/core lexical react react-dom
38
+ # or
39
+ pnpm add @blokhaus/core lexical react react-dom
40
+ # or
41
+ bun add @blokhaus/core lexical react react-dom
42
+ ```
43
+
44
+ ## Quick Start
45
+
46
+ ```tsx
47
+ "use client";
48
+
49
+ import {
50
+ EditorRoot,
51
+ FloatingToolbar,
52
+ SlashMenu,
53
+ InputRulePlugin,
54
+ ListPlugin,
55
+ LinkPlugin,
56
+ PastePlugin,
57
+ OverlayPortal,
58
+ BlockSelectionPlugin,
59
+ } from "@blokhaus/core";
60
+ import "@blokhaus/core/styles";
61
+
62
+ export function Editor() {
63
+ return (
64
+ <EditorRoot namespace="my-editor" className="relative min-h-50 p-4">
65
+ <FloatingToolbar />
66
+ <SlashMenu />
67
+ <InputRulePlugin />
68
+ <ListPlugin />
69
+ <LinkPlugin />
70
+ <PastePlugin />
71
+ <OverlayPortal />
72
+ <BlockSelectionPlugin />
73
+ </EditorRoot>
74
+ );
75
+ }
76
+ ```
77
+
78
+ ## Theming
79
+
80
+ Blokhaus uses CSS custom properties for all colors. Import the default tokens and override any variable:
81
+
82
+ ```css
83
+ @import "@blokhaus/core/styles";
84
+
85
+ :root {
86
+ --blokhaus-accent: hsl(262 83% 58%);
87
+ --blokhaus-radius: 0.75rem;
88
+ }
89
+ ```
90
+
91
+ See [`src/styles/tokens.css`](./src/styles/tokens.css) for all available tokens.
92
+
93
+ ## Composable Architecture
94
+
95
+ Every feature is an independent plugin passed as a child of `<EditorRoot>`. Add only what you need:
96
+
97
+ ```tsx
98
+ <EditorRoot namespace="minimal">
99
+ {/* Just rich text — no toolbar, no slash menu, no drag handles */}
100
+ <InputRulePlugin />
101
+ </EditorRoot>
102
+ ```
103
+
104
+ ```tsx
105
+ <EditorRoot namespace="full">
106
+ <FloatingToolbar />
107
+ <SlashMenu />
108
+ <InputRulePlugin />
109
+ <ListPlugin />
110
+ <LinkPlugin />
111
+ <ImagePlugin uploadHandler={myUpload} />
112
+ <VideoPlugin uploadHandler={myUpload} />
113
+ <AIPlugin provider={myAIProvider} />
114
+ <MentionPlugin providers={[userMentionProvider]} />
115
+ <EmojiPickerPlugin />
116
+ <CalloutPlugin />
117
+ <TogglePlugin />
118
+ <TablePlugin />
119
+ <CodeBlockNode />
120
+ <ColorPlugin />
121
+ <PastePlugin />
122
+ <OverlayPortal />
123
+ <BlockSelectionPlugin />
124
+ <MobileToolbar />
125
+ </EditorRoot>
126
+ ```
127
+
128
+ ## Reading Editor State
129
+
130
+ ```tsx
131
+ import { useEditorState } from "@blokhaus/core";
132
+
133
+ function SaveButton() {
134
+ const { serializedState } = useEditorState({
135
+ debounceMs: 300,
136
+ onChange: (json) => console.log("State changed:", json),
137
+ });
138
+
139
+ return <button onClick={() => save(serializedState)}>Save</button>;
140
+ }
141
+ ```
142
+
143
+ ## Image & Video Uploads
144
+
145
+ Provide an `UploadHandler` — a function that takes a `File` and returns a URL:
146
+
147
+ ```tsx
148
+ const uploadHandler = async (file: File): Promise<string> => {
149
+ const form = new FormData();
150
+ form.append("file", file);
151
+ const res = await fetch("/api/upload", { method: "POST", body: form });
152
+ const { url } = await res.json();
153
+ return url;
154
+ };
155
+
156
+ <ImagePlugin uploadHandler={uploadHandler} />
157
+ <VideoPlugin uploadHandler={uploadHandler} />
158
+ ```
159
+
160
+ ## AI Integration
161
+
162
+ Implement the `AIProvider` interface to stream AI-generated content:
163
+
164
+ ```tsx
165
+ import type { AIProvider } from "@blokhaus/core";
166
+
167
+ const myProvider: AIProvider = {
168
+ generate: async ({ prompt, context }) => {
169
+ const res = await fetch("/api/ai", {
170
+ method: "POST",
171
+ body: JSON.stringify({ prompt, context }),
172
+ });
173
+ return res.body!; // ReadableStream<string>
174
+ },
175
+ };
176
+
177
+ <AIPlugin provider={myProvider} />
178
+ ```
179
+
180
+ ## Peer Dependencies
181
+
182
+ | Package | Version |
183
+ |---------|---------|
184
+ | `react` | >= 18 |
185
+ | `react-dom` | >= 18 |
186
+ | `lexical` | >= 0.40.0, < 1.0.0 |
187
+ | `next` | >= 14 |
188
+
189
+ ## License
190
+
191
+ MIT