@bladeberg/editor 0.2.0 → 0.2.2

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.npm.md ADDED
@@ -0,0 +1,208 @@
1
+ # @bladeberg/editor
2
+
3
+ **Gutenberg, standalone.** No WordPress. No Laravel. Just the block editor in your React app.
4
+
5
+ BladeBerg wraps [`@automattic/isolated-block-editor`](https://github.com/Automattic/isolated-block-editor) — the same pre-built browser bundle Automattic uses to run Gutenberg outside of wp-admin — and ships it as a lazy-loaded npm package. You get paragraphs, headings, images, columns, embeds, the whole core block library, without installing a single `@wordpress/*` package yourself.
6
+
7
+ > Using Laravel? See the full [BladeBerg docs](https://github.com/BladeBerg/bladeberg#readme) for the Composer package, Blade components, PHP rendering, and media API.
8
+
9
+ ---
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install @bladeberg/editor react react-dom
15
+ ```
16
+
17
+ That's it. The Gutenberg runtime is **bundled inside the package** — you won't hit WordPress dependency hell.
18
+
19
+ **Requirements:** React 18 or 19, a modern browser, and a bundler that supports ESM (`import`).
20
+
21
+ ---
22
+
23
+ ## Quick start
24
+
25
+ ```jsx
26
+ import { createEditor } from '@bladeberg/editor';
27
+ import '@bladeberg/editor/style.css';
28
+
29
+ const editor = await createEditor({
30
+ target: '#editor', // selector or DOM element
31
+ value: savedContent, // optional — existing block HTML
32
+ blockPrefix: 'bb', // prefix in stored content (default: bb)
33
+ onChange: (html) => {
34
+ draft = html; // live updates (optional)
35
+ },
36
+ });
37
+
38
+ // When the user saves:
39
+ await fetch('/api/posts/1', {
40
+ method: 'PUT',
41
+ headers: { 'Content-Type': 'application/json' },
42
+ body: JSON.stringify({ content: editor.getContent() }),
43
+ });
44
+
45
+ // On route change / unmount:
46
+ editor.destroy();
47
+ ```
48
+
49
+ `createEditor()` is async — it lazy-loads the Gutenberg runtime on first call (~2 MB, cached after that).
50
+
51
+ ---
52
+
53
+ ## What you get
54
+
55
+ | Feature | Details |
56
+ |---------|---------|
57
+ | **Full core blocks** | Paragraph, heading, list, image, quote, columns, embeds, etc. |
58
+ | **Portable HTML** | Content serializes to block comments: `<!-- bb:paragraph -->…` |
59
+ | **Branded prefix** | Default `bb:` instead of WordPress's `wp:` — configurable |
60
+ | **Right-click menu** | Block Options (Copy, Duplicate, Remove, …) restored |
61
+ | **Media upload** | Optional — wire to your own API (see below) |
62
+ | **Zero WordPress deps** | Runtime is pre-built and shipped in the tarball |
63
+
64
+ ---
65
+
66
+ ## API
67
+
68
+ ### `createEditor(options)`
69
+
70
+ | Option | Type | Default | Description |
71
+ |--------|------|---------|-------------|
72
+ | `target` | `string \| Element` | *(required)* | CSS selector or element. A `<textarea>` is mounted directly; any other element gets a hidden textarea appended. |
73
+ | `value` | `string` | `''` | Initial block HTML (your configured prefix). |
74
+ | `blockPrefix` | `string` | `'bb'` | Prefix written into block comments on save. |
75
+ | `settings` | `object` | `{}` | Forwarded to Gutenberg's `attachEditor()`. |
76
+ | `media` | `object` | — | `{ mode, apiUrl, csrfToken }` — see [Media](#media). |
77
+ | `branding` | `boolean` | `true` | Rebrand "WordPress" strings in the UI. |
78
+ | `contextMenu` | `boolean` | `true` | Restore right-click block menu. |
79
+ | `onChange` | `(html) => void` | — | Called when content changes (polled every 300 ms). |
80
+
81
+ **Returns** `Promise<EditorHandle>`:
82
+
83
+ ```js
84
+ editor.getContent() // current block HTML (prefixed)
85
+ editor.onChange(fn) // subscribe; returns unsubscribe fn
86
+ editor.destroy() // detach editor + stop listeners
87
+ editor.textarea // underlying textarea element
88
+ ```
89
+
90
+ ### `registerBlock(name, settings)`
91
+
92
+ ```js
93
+ import { registerBlock } from '@bladeberg/editor';
94
+
95
+ registerBlock('my-plugin/callout', { /* block settings */ });
96
+ ```
97
+
98
+ > **Note:** The current isolated-block-editor bundle (v2.30) does not expose `window.wp.blocks`, so custom React blocks are queued but not registered yet. Use server-rendered blocks with [BladeBerg's PHP package](https://github.com/BladeBerg/bladeberg) instead.
99
+
100
+ ---
101
+
102
+ ## Content format
103
+
104
+ Gutenberg saves blocks as HTML comments:
105
+
106
+ ```html
107
+ <!-- bb:paragraph --><p>Hello world</p><!-- /bb:paragraph -->
108
+ ```
109
+
110
+ The `bb:` prefix (configurable via `blockPrefix`) keeps your database free of WordPress branding. On load, BladeBerg converts it back to `wp:` internally so Gutenberg can parse it, then converts it back on save.
111
+
112
+ ---
113
+
114
+ ## Media (optional)
115
+
116
+ Wire the editor to your own upload API:
117
+
118
+ ```js
119
+ const editor = await createEditor({
120
+ target: '#editor',
121
+ media: {
122
+ mode: 'upload', // 'disabled' | 'select' | 'upload'
123
+ apiUrl: '/api/media', // your JSON media endpoints
124
+ csrfToken: getCsrfToken(), // optional
125
+ },
126
+ });
127
+ ```
128
+
129
+ If you're using [BladeBerg for Laravel](https://github.com/BladeBerg/bladeberg), the backend ships ready-made routes at `/bladeberg/media`.
130
+
131
+ ---
132
+
133
+ ## SSR / Next.js / Nuxt
134
+
135
+ The editor is **browser-only**. Import it from a client component:
136
+
137
+ ```jsx
138
+ 'use client';
139
+
140
+ import { useEffect, useRef } from 'react';
141
+
142
+ export default function PostEditor({ content }) {
143
+ const ref = useRef(null);
144
+
145
+ useEffect(() => {
146
+ let editor;
147
+ import('@bladeberg/editor').then(({ createEditor }) => {
148
+ createEditor({ target: ref.current, value: content }).then((e) => { editor = e; });
149
+ });
150
+ return () => editor?.destroy();
151
+ }, [content]);
152
+
153
+ return <div ref={ref} />;
154
+ }
155
+ ```
156
+
157
+ Don't forget `import '@bladeberg/editor/style.css'` somewhere in your client bundle.
158
+
159
+ ---
160
+
161
+ ## Rendering stored content
162
+
163
+ This npm package is **editor-only**. To turn block HTML into visitor-facing HTML you need a renderer:
164
+
165
+ - **[BladeBerg Laravel package](https://github.com/BladeBerg/bladeberg)** — `<x-bladeberg-render>`, `Bladeberg::render()`, or `POST /bladeberg/render`
166
+ - **Your own backend** — parse `<!-- bb:… -->` comments and render block HTML yourself
167
+ - **Return raw block HTML** to the frontend and render client-side
168
+
169
+ ---
170
+
171
+ ## How it works
172
+
173
+ ```
174
+ Your React app
175
+
176
+ ├─ import { createEditor } from '@bladeberg/editor'
177
+ ├─ import '@bladeberg/editor/style.css'
178
+
179
+
180
+ createEditor() lazy-loads isolated-block-editor.js (bundled in the package)
181
+
182
+
183
+ window.wp.attachEditor(textarea) ← full Gutenberg UI
184
+
185
+
186
+ editor.getContent() → "<!-- bb:paragraph -->…" → POST to your API
187
+ ```
188
+
189
+ No `@wordpress/block-editor`, no `@wordpress/data`, no dependency resolver nightmares. The hard part is already done.
190
+
191
+ ---
192
+
193
+ ## Development (maintainers)
194
+
195
+ ```bash
196
+ cd packages/bladeberg
197
+ npm install
198
+ npm run build:npm # → dist-npm/bladeberg.js + style.css + isolated-block-editor.js
199
+ npm pack # smoke-test the tarball locally
200
+ ```
201
+
202
+ Publish happens via GitHub Actions on `v*` tags. See [RELEASE.md](RELEASE.md).
203
+
204
+ ---
205
+
206
+ ## License
207
+
208
+ GPL-2.0-or-later — same as Gutenberg. See [LICENSE](LICENSE).