@noseberry/nbd-editor 1.0.0 → 1.0.1

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 CHANGED
@@ -1,6 +1,64 @@
1
1
  # @noseberry/nbd-editor
2
2
 
3
- A framework-agnostic, Gutenberg-style block editor by **Noseberry Private Limited**. Works with vanilla JavaScript, React, and Next.js out of the box.
3
+ > We'd love to hear from you! If you run into any bugs, have feature requests, or just want to share how you're using NBD Editor, please [open an issue](https://github.com/Noseberry-Private-Limited/NBD-editor/issues). Your feedback helps us make NBD Editor better for everyone.
4
+
5
+ A powerful, framework-agnostic block editor built by **Noseberry Private Limited**. Inspired by WordPress Gutenberg, NBD Editor gives you a clean, modern content editing experience with drag-and-drop blocks, rich text formatting, media uploads, and a slash command menu — all in a single lightweight package with **zero production dependencies**.
6
+
7
+ Works seamlessly with **vanilla JavaScript**, **React**, and **Next.js**.
8
+
9
+ ### Why NBD Editor?
10
+
11
+ - **Drop-in ready** — one import, one line of code, and you have a full block editor
12
+ - **Framework agnostic** — works with any frontend stack; optional React wrapper included
13
+ - **20+ block types** — paragraphs, headings, images, video, audio, tables, columns, code, embeds, and more
14
+ - **Rich editing** — inline formatting toolbar, slash commands (`/`), drag-and-drop reordering, undo/redo
15
+ - **Media support** — upload images, video, audio, and files with drag-and-drop or file picker
16
+ - **Simple data model** — `getData()` returns `{ content: '<p>...</p>' }` — just store one HTML string
17
+ - **TypeScript support** — full type definitions included for autocomplete and type safety
18
+ - **Lightweight** — ~89 KB minified JS + ~25 KB CSS, zero runtime dependencies
19
+
20
+ ### How It Works
21
+
22
+ ```
23
+ Install → Import → Mount → Done
24
+
25
+ 1. npm install @noseberry/nbd-editor
26
+ 2. import { NBDEditor } from '@noseberry/nbd-editor'
27
+ 3. new NBDEditor('#editor', { onSave: (data) => save(data) })
28
+ ```
29
+
30
+ The editor manages its own state internally. You interact with it through callbacks (`onChange`, `onSave`) or imperatively via the API (`getData()`, `setData()`, `toHTML()`). In React, use the `ReactNBDEditor` component with or without a ref.
31
+
32
+ ### Usage Flow
33
+
34
+ ```
35
+ ┌─────────────────────────────────────────────────────┐
36
+ │ Your App │
37
+ │ │
38
+ │ ┌─────────────┐ ┌──────────────────────┐ │
39
+ │ │ Initialize │───────▶│ NBD Editor │ │
40
+ │ │ with config │ │ │ │
41
+ │ └─────────────┘ │ ┌──────────────────┐ │ │
42
+ │ │ │ User writes │ │ │
43
+ │ ┌─────────────┐ │ │ content using │ │ │
44
+ │ │ onChange() │◀───────│ │ blocks, toolbar, │ │ │
45
+ │ │ callback │ │ │ slash commands │ │ │
46
+ │ └─────────────┘ │ └──────────────────┘ │ │
47
+ │ │ │ │
48
+ │ ┌─────────────┐ │ ┌──────────────────┐ │ │
49
+ │ │ onSave() │◀───────│ │ Ctrl+S or │ │ │
50
+ │ │ callback │ │ │ save() API call │ │ │
51
+ │ └──────┬──────┘ │ └──────────────────┘ │ │
52
+ │ │ └──────────────────────┘ │
53
+ │ ▼ │
54
+ │ ┌─────────────┐ │
55
+ │ │ Store in │ data = { content: '<p>...</p>' }│
56
+ │ │ database │ │
57
+ │ └─────────────┘ │
58
+ │ │
59
+ │ To restore: editor.setData({ content: savedHTML })│
60
+ └─────────────────────────────────────────────────────┘
61
+ ```
4
62
 
5
63
  ---
6
64
 
@@ -28,31 +86,12 @@ A framework-agnostic, Gutenberg-style block editor by **Noseberry Private Limite
28
86
 
29
87
  ## Installation
30
88
 
31
- This is a **private** repository. You need GitHub access to install it.
32
-
33
- **SSH (recommended):**
34
-
35
89
  ```bash
36
- npm install git+ssh://git@github.com/Noseberry-Private-Limited/NBD-editor.git
90
+ npm install @noseberry/nbd-editor
37
91
  # or
38
- yarn add git+ssh://git@github.com/Noseberry-Private-Limited/NBD-editor.git
92
+ yarn add @noseberry/nbd-editor
39
93
  # or
40
- pnpm add git+ssh://git@github.com/Noseberry-Private-Limited/NBD-editor.git
41
- ```
42
-
43
- > Requires an SSH key linked to your GitHub account.
44
-
45
- **HTTPS with personal access token:**
46
-
47
- ```bash
48
- npm install git+https://<YOUR_GITHUB_TOKEN>@github.com/Noseberry-Private-Limited/NBD-editor.git
49
- ```
50
-
51
- **Pin a specific branch or tag:**
52
-
53
- ```bash
54
- npm install git+ssh://git@github.com/Noseberry-Private-Limited/NBD-editor.git#main
55
- npm install git+ssh://git@github.com/Noseberry-Private-Limited/NBD-editor.git#v1.0.0
94
+ pnpm add @noseberry/nbd-editor
56
95
  ```
57
96
 
58
97
  **Important — always import the CSS:**
@@ -0,0 +1,223 @@
1
+ // Type definitions for @noseberry/nbd-editor
2
+ // Noseberry Private Limited
3
+
4
+ import * as React from 'react';
5
+
6
+ /* ===== EventEmitter ===== */
7
+
8
+ export class EventEmitter {
9
+ on(event: string, fn: (...args: any[]) => void): () => void;
10
+ off(event: string, fn: (...args: any[]) => void): void;
11
+ emit(event: string, ...args: any[]): void;
12
+ once(event: string, fn: (...args: any[]) => void): void;
13
+ }
14
+
15
+ /* ===== Editor Data ===== */
16
+
17
+ export interface EditorData {
18
+ content: string;
19
+ }
20
+
21
+ export interface Block {
22
+ id: string;
23
+ type: string;
24
+ content: string;
25
+ attrs: Record<string, any>;
26
+ }
27
+
28
+ export interface UploadResult {
29
+ url: string;
30
+ id?: string;
31
+ }
32
+
33
+ /* ===== NBDEditor Options ===== */
34
+
35
+ export interface NBDEditorOptions {
36
+ /** Site name displayed in the header. Default: `'My Site'` */
37
+ siteName?: string;
38
+ /** Author name displayed in the editor. Default: `'Admin'` */
39
+ authorName?: string;
40
+ /** Initial HTML content to load. */
41
+ content?: string | null;
42
+ /** Placeholder text for empty blocks. Default: `'Start writing...'` */
43
+ placeholder?: string;
44
+ /** Show/hide the bottom status bar. Default: `true` */
45
+ showStatusBar?: boolean;
46
+ /** Show/hide the right settings panel. Default: `false` */
47
+ showSettingsPanel?: boolean;
48
+ /** Show/hide header action buttons. Default: `false` */
49
+ showHeaderActions?: boolean;
50
+ /** Auto-save interval in milliseconds. Set `0` to disable. Default: `30000` */
51
+ autoSaveInterval?: number;
52
+ /** Custom file upload handler. Return `{ url, id? }`. */
53
+ uploadHandler?: ((file: File) => Promise<UploadResult>) | null;
54
+ /** Max upload file size in bytes. Default: `10485760` (10 MB) */
55
+ maxFileSize?: number;
56
+ /** Controls video/audio source chooser. Return `'url'` or `'upload'`. */
57
+ onChooseMediaSource?: ((type: 'video' | 'audio') => 'url' | 'upload') | null;
58
+ /** Called on every content change. */
59
+ onChange?: ((data: EditorData) => void) | null;
60
+ /** Called when save is triggered. */
61
+ onSave?: ((data: EditorData) => void) | null;
62
+ /** Called when publish is triggered. */
63
+ onPublish?: ((data: EditorData) => void) | null;
64
+ }
65
+
66
+ /* ===== NBDEditor ===== */
67
+
68
+ export class NBDEditor extends EventEmitter {
69
+ constructor(selector: string | HTMLElement, options?: NBDEditorOptions);
70
+
71
+ /** Get the full editor content. */
72
+ getData(): EditorData;
73
+ /** Set editor content. Accepts `{ content: '...' }` or a plain string. */
74
+ setData(data: EditorData | string): void;
75
+ /** Export all blocks as a merged HTML string. */
76
+ toHTML(): string;
77
+ /** Trigger save — fires `onSave` callback and `'save'` event. */
78
+ save(): void;
79
+ /** Trigger publish — fires `onPublish` callback and `'publish'` event. */
80
+ publish(): void;
81
+ /** Undo the last action. Returns `true` if undo was performed. */
82
+ undo(opts?: { preferNative?: boolean }): boolean;
83
+ /** Redo the last undone action. Returns `true` if redo was performed. */
84
+ redo(opts?: { preferNative?: boolean }): boolean;
85
+ /** Tear down the editor and clean up listeners. */
86
+ destroy(): void;
87
+ /** Get the current title value. */
88
+ getTitle(): string;
89
+ /** Set the title. */
90
+ setTitle(title: string): void;
91
+ /** Select a block by its ID. */
92
+ selectBlock(id: string): void;
93
+ /** Select and focus a block. */
94
+ focusBlock(id: string): void;
95
+ /** Insert a new block after the selected block. */
96
+ insertBlockAtSelection(type: string, data?: Partial<Block>): Block;
97
+ /** Append a new block at the end. */
98
+ insertBlockAtEnd(type: string, data?: Partial<Block>): Block;
99
+ /** Toggle a block between visual and raw HTML mode. */
100
+ toggleBlockHtmlMode(blockId?: string): void;
101
+ /** Open the HTML editor modal for a block. */
102
+ openBlockHtmlEditor(blockId?: string): void;
103
+ }
104
+
105
+ /* ===== ReactNBDEditor ===== */
106
+
107
+ export interface ReactNBDEditorProps extends NBDEditorOptions {
108
+ /** CSS class for the wrapper div. */
109
+ className?: string;
110
+ /** Inline styles for the wrapper div. */
111
+ style?: React.CSSProperties;
112
+ /** Called once the editor instance is initialized. */
113
+ onReady?: (editor: NBDEditor) => void;
114
+ }
115
+
116
+ export interface ReactNBDEditorRef {
117
+ /** Returns the underlying NBDEditor instance. */
118
+ getInstance(): NBDEditor | null;
119
+ /** Returns `{ content: '<p>...</p>' }`. */
120
+ getData(): EditorData | undefined;
121
+ /** Sets content — accepts `{ content: '...' }`. */
122
+ setData(data: EditorData): void;
123
+ /** Returns the raw HTML string. */
124
+ toHTML(): string | undefined;
125
+ /** Triggers save (fires `onSave` callback). */
126
+ save(): void;
127
+ /** Triggers publish (fires `onPublish` callback). */
128
+ publish(): void;
129
+ /** Undo last action. */
130
+ undo(opts?: { preferNative?: boolean }): void;
131
+ /** Redo last undone action. */
132
+ redo(opts?: { preferNative?: boolean }): void;
133
+ /** Destroys the editor instance and cleans up. */
134
+ destroy(): void;
135
+ }
136
+
137
+ export const ReactNBDEditor: React.ForwardRefExoticComponent<
138
+ ReactNBDEditorProps & React.RefAttributes<ReactNBDEditorRef>
139
+ > | null;
140
+
141
+ /* ===== BlockManager ===== */
142
+
143
+ export class BlockManager extends EventEmitter {
144
+ blocks: Block[];
145
+ addBlock(type: string, data?: Partial<Block>, afterId?: string | null): Block;
146
+ removeBlock(id: string): Block | undefined;
147
+ updateBlock(id: string, patch: Partial<Block>): void;
148
+ changeBlockType(id: string, newType: string): void;
149
+ moveBlock(id: string, direction: number): void;
150
+ duplicateBlock(id: string): Block | undefined;
151
+ getBlock(id: string): Block | null;
152
+ getIndex(id: string): number;
153
+ getPrevBlock(id: string): Block | null;
154
+ getNextBlock(id: string): Block | null;
155
+ toJSON(): Block[];
156
+ fromJSON(data: Block[]): void;
157
+ toHTML(): string;
158
+ blockToHTML(block: Block): string;
159
+ saveSnapshot(): void;
160
+ undo(): boolean;
161
+ redo(): boolean;
162
+ getWordCount(): number;
163
+ getCharCount(): number;
164
+ }
165
+
166
+ /* ===== MediaUploader ===== */
167
+
168
+ export interface MediaUploaderOptions {
169
+ uploadHandler?: ((file: File) => Promise<UploadResult>) | null;
170
+ maxFileSize?: number;
171
+ allowedImageTypes?: string[];
172
+ allowedVideoTypes?: string[];
173
+ allowedAudioTypes?: string[];
174
+ }
175
+
176
+ export interface ProcessedFile {
177
+ localUrl?: string;
178
+ remoteUrl?: string;
179
+ file: File;
180
+ id?: string;
181
+ error?: string;
182
+ }
183
+
184
+ export class MediaUploader extends EventEmitter {
185
+ constructor(options?: MediaUploaderOptions);
186
+ openFilePicker(accept?: string, multiple?: boolean): Promise<File[]>;
187
+ processFile(file: File): Promise<ProcessedFile>;
188
+ processFiles(files: File[]): Promise<ProcessedFile[]>;
189
+ handlePaste(clipboardData: DataTransfer): Promise<ProcessedFile[] | null>;
190
+ handleDrop(dataTransfer: DataTransfer): Promise<ProcessedFile[] | null>;
191
+ getMediaType(file: File): 'image' | 'video' | 'audio' | 'file';
192
+ }
193
+
194
+ /* ===== DragDrop ===== */
195
+
196
+ export class DragDrop extends EventEmitter {
197
+ constructor(container: HTMLElement);
198
+ enable(): void;
199
+ disable(): void;
200
+ initDrag(handleEl: HTMLElement, wrapperEl: HTMLElement, blockId: string): void;
201
+ }
202
+
203
+ /* ===== Block Registry ===== */
204
+
205
+ export interface BlockTypeDefinition {
206
+ label: string;
207
+ description: string;
208
+ icon: string;
209
+ category: string;
210
+ hasContent: boolean;
211
+ contentTag?: string;
212
+ placeholder?: string;
213
+ className?: string;
214
+ isMedia?: boolean;
215
+ }
216
+
217
+ export const BLOCK_TYPES: Record<string, BlockTypeDefinition>;
218
+
219
+ export const CATEGORIES: Array<{ id: string; label: string }>;
220
+
221
+ export function getBlocksByCategory(catId: string): Array<{ type: string } & BlockTypeDefinition>;
222
+
223
+ export function searchBlocks(query: string): Array<{ type: string } & BlockTypeDefinition>;
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@noseberry/nbd-editor",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Nbd Editor: a framework-agnostic rich content editor by Noseberry Private Limited.",
5
5
  "main": "dist/nbd-editor.cjs.js",
6
6
  "module": "dist/nbd-editor.esm.js",
7
7
  "browser": "dist/nbd-editor.umd.js",
8
+ "types": "dist/nbd-editor.d.ts",
8
9
  "style": "dist/nbd-editor.css",
9
10
  "exports": {
10
11
  ".": {
12
+ "types": "./dist/nbd-editor.d.ts",
11
13
  "import": "./dist/nbd-editor.esm.js",
12
14
  "require": "./dist/nbd-editor.cjs.js",
13
15
  "default": "./dist/nbd-editor.cjs.js"