dragble-react-editor 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/LICENSE +21 -0
- package/README.md +533 -0
- package/dist/index.d.ts +116 -0
- package/dist/index.esm.js +304 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +310 -0
- package/dist/index.js.map +1 -0
- package/package.json +135 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dragble
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://dragble.com">
|
|
3
|
+
<img src="logo.png" alt="Dragble Email Editor - React Email Template Builder" width="300" />
|
|
4
|
+
</a>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/dragble-react-editor"><img src="https://img.shields.io/npm/v/dragble-react-editor.svg" alt="npm version" /></a>
|
|
9
|
+
<a href="https://github.com/Dragble/dragble-react-editor/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="license" /></a>
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
# dragble-react-editor
|
|
13
|
+
|
|
14
|
+
React component for building **email templates** with drag-and-drop. Embed a full-featured **email editor** into your React app — create responsive HTML emails, newsletters, transactional email templates, and email marketing campaigns visually without writing code.
|
|
15
|
+
|
|
16
|
+
[Dragble](https://dragble.com) is a modern **email builder** and **email template editor** that lets your users design professional emails with a visual drag-and-drop interface.
|
|
17
|
+
|
|
18
|
+
[Website](https://dragble.com) | [Documentation](https://docs.dragble.com) | [Dashboard](https://developers.dragble.com)
|
|
19
|
+
|
|
20
|
+
<p align="center">
|
|
21
|
+
<img src="editor_image.png" alt="Dragble React Email Editor - Drag and Drop Email Template Builder" width="700" />
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
- Drag-and-drop **email template builder** with 20+ content blocks
|
|
27
|
+
- Responsive **HTML email** output compatible with all major email clients
|
|
28
|
+
- **Newsletter editor** with merge tags, dynamic content, and display conditions
|
|
29
|
+
- Visual **email designer** — no HTML/CSS knowledge required for end users
|
|
30
|
+
- Export to HTML, JSON, image, PDF, or ZIP
|
|
31
|
+
- Built-in image editor, AI content generation, and collaboration tools
|
|
32
|
+
- Full TypeScript support
|
|
33
|
+
- Lightweight React wrapper — just a single component or hook
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# npm
|
|
39
|
+
npm install dragble-react-editor
|
|
40
|
+
|
|
41
|
+
# yarn
|
|
42
|
+
yarn add dragble-react-editor
|
|
43
|
+
|
|
44
|
+
# pnpm
|
|
45
|
+
pnpm add dragble-react-editor
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Editor Key
|
|
49
|
+
|
|
50
|
+
An `editorKey` is required to use the editor. You can get one by creating a project on the [Dragble Developer Dashboard](https://developers.dragble.com).
|
|
51
|
+
|
|
52
|
+
## Quick Start
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
import { useRef } from "react";
|
|
56
|
+
import { DragbleEditor, DragbleEditorRef, DesignJson } from "dragble-react-editor";
|
|
57
|
+
|
|
58
|
+
function EmailBuilder() {
|
|
59
|
+
const editorRef = useRef<DragbleEditorRef>(null);
|
|
60
|
+
|
|
61
|
+
const handleChange = async (data: { design: DesignJson; type: string }) => {
|
|
62
|
+
// Design JSON is available directly from the callback
|
|
63
|
+
const json = data.design;
|
|
64
|
+
console.log("Design JSON:", json);
|
|
65
|
+
|
|
66
|
+
// To get HTML, call exportHtml on the editor
|
|
67
|
+
const html = await editorRef.current?.editor?.exportHtml();
|
|
68
|
+
console.log("HTML:", html);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div style={{ height: "100vh" }}>
|
|
73
|
+
<DragbleEditor
|
|
74
|
+
ref={editorRef}
|
|
75
|
+
editorKey="your-editor-key"
|
|
76
|
+
editorMode="email"
|
|
77
|
+
minHeight="600px"
|
|
78
|
+
onReady={(editor) => console.log("Editor ready!")}
|
|
79
|
+
onChange={handleChange}
|
|
80
|
+
onError={(error) => console.error("Editor error:", error)}
|
|
81
|
+
/>
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Complete Example
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
import { useRef, useState, useCallback } from "react";
|
|
91
|
+
import {
|
|
92
|
+
DragbleEditor,
|
|
93
|
+
DragbleEditorRef,
|
|
94
|
+
DesignJson,
|
|
95
|
+
} from "dragble-react-editor";
|
|
96
|
+
|
|
97
|
+
function AdvancedEmailBuilder() {
|
|
98
|
+
const editorRef = useRef<DragbleEditorRef>(null);
|
|
99
|
+
const [isDirty, setIsDirty] = useState(false);
|
|
100
|
+
|
|
101
|
+
const handleReady = useCallback((editor) => {
|
|
102
|
+
// Set merge tags (must pass a MergeTagsConfig object)
|
|
103
|
+
editor.setMergeTags({
|
|
104
|
+
customMergeTags: [
|
|
105
|
+
{ name: "First Name", value: "{{first_name}}" },
|
|
106
|
+
{ name: "Last Name", value: "{{last_name}}" },
|
|
107
|
+
{ name: "Company", value: "{{company}}" },
|
|
108
|
+
],
|
|
109
|
+
excludeDefaults: false,
|
|
110
|
+
sort: true,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Set custom fonts
|
|
114
|
+
editor.setFonts({
|
|
115
|
+
showDefaultFonts: true,
|
|
116
|
+
customFonts: [{ label: "Brand Font", value: "BrandFont, sans-serif" }],
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Load saved design if available
|
|
120
|
+
const savedDesign = localStorage.getItem("email-design");
|
|
121
|
+
if (savedDesign) {
|
|
122
|
+
editor.loadDesign(JSON.parse(savedDesign));
|
|
123
|
+
}
|
|
124
|
+
}, []);
|
|
125
|
+
|
|
126
|
+
const handleChange = useCallback(
|
|
127
|
+
(data: { design: DesignJson; type: string }) => {
|
|
128
|
+
setIsDirty(true);
|
|
129
|
+
localStorage.setItem("email-design", JSON.stringify(data.design));
|
|
130
|
+
},
|
|
131
|
+
[],
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const handleExportHtml = async () => {
|
|
135
|
+
const editor = editorRef.current?.editor;
|
|
136
|
+
if (!editor) return;
|
|
137
|
+
|
|
138
|
+
const html = await editor.exportHtml();
|
|
139
|
+
const blob = new Blob([html], { type: "text/html" });
|
|
140
|
+
const url = URL.createObjectURL(blob);
|
|
141
|
+
const a = document.createElement("a");
|
|
142
|
+
a.href = url;
|
|
143
|
+
a.download = "email.html";
|
|
144
|
+
a.click();
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const handleExportImage = async () => {
|
|
148
|
+
const editor = editorRef.current?.editor;
|
|
149
|
+
if (!editor) return;
|
|
150
|
+
|
|
151
|
+
const data = await editor.exportImage();
|
|
152
|
+
window.open(data.url, "_blank");
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
<div style={{ height: "100vh", display: "flex", flexDirection: "column" }}>
|
|
157
|
+
<div
|
|
158
|
+
style={{
|
|
159
|
+
padding: 12,
|
|
160
|
+
borderBottom: "1px solid #ddd",
|
|
161
|
+
display: "flex",
|
|
162
|
+
gap: 8,
|
|
163
|
+
}}
|
|
164
|
+
>
|
|
165
|
+
<button onClick={() => editorRef.current?.editor?.undo()}>Undo</button>
|
|
166
|
+
<button onClick={() => editorRef.current?.editor?.redo()}>Redo</button>
|
|
167
|
+
<button
|
|
168
|
+
onClick={() => editorRef.current?.editor?.showPreview("desktop")}
|
|
169
|
+
>
|
|
170
|
+
Preview
|
|
171
|
+
</button>
|
|
172
|
+
<button onClick={handleExportHtml}>Export HTML</button>
|
|
173
|
+
<button onClick={handleExportImage}>Export Image</button>
|
|
174
|
+
{isDirty && <span style={{ color: "orange" }}>Unsaved changes</span>}
|
|
175
|
+
</div>
|
|
176
|
+
|
|
177
|
+
<DragbleEditor
|
|
178
|
+
ref={editorRef}
|
|
179
|
+
editorKey="your-editor-key"
|
|
180
|
+
editorMode="email"
|
|
181
|
+
height="100%"
|
|
182
|
+
designMode="live"
|
|
183
|
+
options={{
|
|
184
|
+
appearance: { theme: "light" },
|
|
185
|
+
features: {
|
|
186
|
+
preview: true,
|
|
187
|
+
undoRedo: true,
|
|
188
|
+
imageEditor: true,
|
|
189
|
+
},
|
|
190
|
+
}}
|
|
191
|
+
onReady={handleReady}
|
|
192
|
+
onChange={handleChange}
|
|
193
|
+
onError={(error) => console.error(error.message)}
|
|
194
|
+
/>
|
|
195
|
+
</div>
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export default AdvancedEmailBuilder;
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Props
|
|
203
|
+
|
|
204
|
+
| Prop | Type | Required | Default | Description |
|
|
205
|
+
| --------------- | --------------------------------------------------------------------------- | -------- | ----------- | ---------------------------------------------------------- |
|
|
206
|
+
| `editorKey` | `string` | Yes | — | Editor key for authentication |
|
|
207
|
+
| `design` | `DesignJson \| ModuleData \| null` | No | `undefined` | Initial design to load |
|
|
208
|
+
| `editorMode` | `EditorMode` | No | — | `"email"` \| `"web"` \| `"popup"` |
|
|
209
|
+
| `contentType` | `"module"` | No | — | Single-row module editor mode |
|
|
210
|
+
| `options` | `EditorOptions` | No | `{}` | All editor configuration |
|
|
211
|
+
| `popup` | `PopupConfig` | No | — | Popup config (only when `editorMode` is `"popup"`) |
|
|
212
|
+
| `collaboration` | `boolean \| CollaborationFeaturesConfig` | No | — | Collaboration features |
|
|
213
|
+
| `user` | `UserInfo` | No | — | User info for session/collaboration |
|
|
214
|
+
| `designMode` | `"edit" \| "live"` | No | `"live"` | Template permissions mode |
|
|
215
|
+
| `height` | `string \| number` | No | — | Editor height |
|
|
216
|
+
| `minHeight` | `string \| number` | No | `"600px"` | Minimum editor height |
|
|
217
|
+
| `callbacks` | `Omit<DragbleCallbacks, "onReady" \| "onLoad" \| "onChange" \| "onError">` | No | — | SDK callbacks (excluding those handled by dedicated props) |
|
|
218
|
+
| `className` | `string` | No | — | CSS class for the outer container |
|
|
219
|
+
| `style` | `React.CSSProperties` | No | — | Inline styles for the outer container |
|
|
220
|
+
|
|
221
|
+
| `onReady` | `(editor: DragbleSDK) => void` | No | — | Called when the editor is ready |
|
|
222
|
+
| `onLoad` | `() => void` | No | — | Called when a design is loaded |
|
|
223
|
+
| `onChange` | `(data: { design: DesignJson; type: string }) => void` | No | — | Called when the design changes |
|
|
224
|
+
| `onError` | `(error: Error) => void` | No | — | Called on error |
|
|
225
|
+
| `onComment` | `(action: CommentAction) => void` | No | — | Called on comment events |
|
|
226
|
+
|
|
227
|
+
## Ref
|
|
228
|
+
|
|
229
|
+
Use a ref to access the SDK instance:
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
const editorRef = useRef<DragbleEditorRef>(null);
|
|
233
|
+
|
|
234
|
+
// DragbleEditorRef shape:
|
|
235
|
+
// {
|
|
236
|
+
// editor: DragbleSDK | null;
|
|
237
|
+
// isReady: () => boolean;
|
|
238
|
+
// }
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Hook API
|
|
242
|
+
|
|
243
|
+
The `useDragbleEditor` hook provides a convenient way to access the editor:
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
import { DragbleEditor, useDragbleEditor } from "dragble-react-editor";
|
|
247
|
+
|
|
248
|
+
function MyEditor() {
|
|
249
|
+
const { ref, editor, isReady } = useDragbleEditor();
|
|
250
|
+
|
|
251
|
+
return (
|
|
252
|
+
<div>
|
|
253
|
+
<button
|
|
254
|
+
onClick={async () => {
|
|
255
|
+
const html = await editor?.exportHtml();
|
|
256
|
+
console.log(html);
|
|
257
|
+
}}
|
|
258
|
+
disabled={!isReady}
|
|
259
|
+
>
|
|
260
|
+
Export
|
|
261
|
+
</button>
|
|
262
|
+
<DragbleEditor ref={ref} editorKey="your-editor-key" />
|
|
263
|
+
</div>
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**Returns:** `{ ref, editor, isReady }` — `ref` is passed to the component, `editor` is the SDK instance (or `null`), and `isReady` is a boolean.
|
|
269
|
+
|
|
270
|
+
## SDK Methods Reference
|
|
271
|
+
|
|
272
|
+
Access the SDK via `editorRef.current?.editor` or the `editor` value from `useDragbleEditor()`. All export and getter methods return Promises.
|
|
273
|
+
|
|
274
|
+
### Design
|
|
275
|
+
|
|
276
|
+
```tsx
|
|
277
|
+
editor.loadDesign(design, options?); // void
|
|
278
|
+
const result = await editor.loadDesignAsync(design, options?);
|
|
279
|
+
// => { success, validRowsCount, invalidRowsCount, errors? }
|
|
280
|
+
editor.loadBlank(options?); // void
|
|
281
|
+
const { html, json } = await editor.getDesign(); // Promise
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Export
|
|
285
|
+
|
|
286
|
+
All export methods are **Promise-based**. There are no callback overloads.
|
|
287
|
+
|
|
288
|
+
```tsx
|
|
289
|
+
const html = await editor.exportHtml(options?); // Promise<string>
|
|
290
|
+
const json = await editor.exportJson(); // Promise<DesignJson>
|
|
291
|
+
const text = await editor.exportPlainText(); // Promise<string>
|
|
292
|
+
const imageData = await editor.exportImage(options?); // Promise<ExportImageData>
|
|
293
|
+
const pdfData = await editor.exportPdf(options?); // Promise<ExportPdfData>
|
|
294
|
+
const zipData = await editor.exportZip(options?); // Promise<ExportZipData>
|
|
295
|
+
const values = await editor.getPopupValues(); // Promise<PopupValues | null>
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Merge Tags
|
|
299
|
+
|
|
300
|
+
`setMergeTags` accepts a `MergeTagsConfig` object, not a plain array.
|
|
301
|
+
|
|
302
|
+
```tsx
|
|
303
|
+
editor.setMergeTags({
|
|
304
|
+
customMergeTags: [
|
|
305
|
+
{ name: "First Name", value: "{{first_name}}" },
|
|
306
|
+
{ name: "Company", value: "{{company}}" },
|
|
307
|
+
],
|
|
308
|
+
excludeDefaults: false,
|
|
309
|
+
sort: true,
|
|
310
|
+
});
|
|
311
|
+
const tags = await editor.getMergeTags(); // Promise<(MergeTag | MergeTagGroup)[]>
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Special Links
|
|
315
|
+
|
|
316
|
+
`setSpecialLinks` accepts a `SpecialLinksConfig` object.
|
|
317
|
+
|
|
318
|
+
```tsx
|
|
319
|
+
editor.setSpecialLinks({
|
|
320
|
+
customSpecialLinks: [{ name: "Unsubscribe", href: "{{unsubscribe_url}}" }],
|
|
321
|
+
excludeDefaults: false,
|
|
322
|
+
});
|
|
323
|
+
const links = await editor.getSpecialLinks(); // Promise<(SpecialLink | SpecialLinkGroup)[]>
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Modules
|
|
327
|
+
|
|
328
|
+
```tsx
|
|
329
|
+
editor.setModules(modules); // void
|
|
330
|
+
editor.setModulesLoading(loading); // void
|
|
331
|
+
const modules = await editor.getModules(); // Promise<Module[]>
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Fonts
|
|
335
|
+
|
|
336
|
+
```tsx
|
|
337
|
+
editor.setFonts(config); // void
|
|
338
|
+
const fonts = await editor.getFonts(); // Promise<FontsConfig>
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Body Values
|
|
342
|
+
|
|
343
|
+
```tsx
|
|
344
|
+
editor.setBodyValues({
|
|
345
|
+
backgroundColor: "#f5f5f5",
|
|
346
|
+
contentWidth: "600px",
|
|
347
|
+
});
|
|
348
|
+
const values = await editor.getBodyValues(); // Promise<SetBodyValuesOptions>
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### Editor Configuration
|
|
352
|
+
|
|
353
|
+
```tsx
|
|
354
|
+
editor.setOptions(options); // void — Partial<EditorOptions>
|
|
355
|
+
editor.setToolsConfig(toolsConfig); // void
|
|
356
|
+
editor.setEditorMode(mode); // void
|
|
357
|
+
editor.setEditorConfig(config); // void
|
|
358
|
+
const config = await editor.getEditorConfig(); // Promise<EditorBehaviorConfig>
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Locale, Language & Text Direction
|
|
362
|
+
|
|
363
|
+
```tsx
|
|
364
|
+
editor.setLocale(locale, translations?); // void
|
|
365
|
+
editor.setLanguage(language); // void
|
|
366
|
+
const lang = await editor.getLanguage(); // Promise<Language | null>
|
|
367
|
+
editor.setTextDirection(direction); // void — 'ltr' | 'rtl'
|
|
368
|
+
const dir = await editor.getTextDirection(); // Promise<TextDirection>
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Appearance
|
|
372
|
+
|
|
373
|
+
```tsx
|
|
374
|
+
editor.setAppearance(appearance); // void
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Undo / Redo / Save
|
|
378
|
+
|
|
379
|
+
```tsx
|
|
380
|
+
editor.undo(); // void
|
|
381
|
+
editor.redo(); // void
|
|
382
|
+
const canUndo = await editor.canUndo(); // Promise<boolean>
|
|
383
|
+
const canRedo = await editor.canRedo(); // Promise<boolean>
|
|
384
|
+
editor.save(); // void
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Preview
|
|
388
|
+
|
|
389
|
+
```tsx
|
|
390
|
+
editor.showPreview(device?); // void — 'desktop' | 'tablet' | 'mobile'
|
|
391
|
+
editor.hidePreview(); // void
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Custom Tools
|
|
395
|
+
|
|
396
|
+
```tsx
|
|
397
|
+
await editor.registerTool(config); // Promise<void>
|
|
398
|
+
await editor.unregisterTool(toolId); // Promise<void>
|
|
399
|
+
const tools = await editor.getTools(); // Promise<Array<{ id, label, baseToolType }>>
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Custom Widgets
|
|
403
|
+
|
|
404
|
+
```tsx
|
|
405
|
+
await editor.createWidget(config); // Promise<void>
|
|
406
|
+
await editor.removeWidget(widgetName); // Promise<void>
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### Collaboration & Comments
|
|
410
|
+
|
|
411
|
+
```tsx
|
|
412
|
+
editor.showComment(commentId); // void
|
|
413
|
+
editor.openCommentPanel(rowId); // void
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### Tabs & Branding
|
|
417
|
+
|
|
418
|
+
```tsx
|
|
419
|
+
editor.updateTabs(tabs); // void
|
|
420
|
+
editor.setBrandingColors(config); // void
|
|
421
|
+
editor.registerColumns(cells); // void
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### Display Conditions
|
|
425
|
+
|
|
426
|
+
```tsx
|
|
427
|
+
editor.setDisplayConditions(config); // void
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Audit
|
|
431
|
+
|
|
432
|
+
```tsx
|
|
433
|
+
const result = await editor.audit(options?); // Promise<AuditResult>
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Asset Management
|
|
437
|
+
|
|
438
|
+
```tsx
|
|
439
|
+
const { success, url, error } = await editor.uploadImage(file, options?);
|
|
440
|
+
const { assets, total } = await editor.listAssets(options?);
|
|
441
|
+
const { success, error } = await editor.deleteAsset(assetId);
|
|
442
|
+
const folders = await editor.listAssetFolders(parentId?);
|
|
443
|
+
const folder = await editor.createAssetFolder(name, parentId?);
|
|
444
|
+
const info = await editor.getStorageInfo();
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### Status & Lifecycle
|
|
448
|
+
|
|
449
|
+
```tsx
|
|
450
|
+
editor.isReady(); // boolean
|
|
451
|
+
editor.destroy(); // void
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
## Events
|
|
455
|
+
|
|
456
|
+
Subscribe to editor events using `addEventListener`:
|
|
457
|
+
|
|
458
|
+
```tsx
|
|
459
|
+
const unsubscribe = editor.addEventListener("design:updated", (data) => {
|
|
460
|
+
console.log("Design changed:", data);
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
// Or remove manually
|
|
464
|
+
editor.removeEventListener("design:updated", callback);
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### Available Events
|
|
468
|
+
|
|
469
|
+
| Event | Description |
|
|
470
|
+
| -------------------------- | --------------------------- |
|
|
471
|
+
| `editor:ready` | Editor initialized |
|
|
472
|
+
| `design:loaded` | Design loaded |
|
|
473
|
+
| `design:updated` | Design changed |
|
|
474
|
+
| `design:saved` | Design saved |
|
|
475
|
+
| `row:selected` | Row selected |
|
|
476
|
+
| `row:unselected` | Row unselected |
|
|
477
|
+
| `column:selected` | Column selected |
|
|
478
|
+
| `column:unselected` | Column unselected |
|
|
479
|
+
| `content:selected` | Content block selected |
|
|
480
|
+
| `content:unselected` | Content block unselected |
|
|
481
|
+
| `content:modified` | Content block modified |
|
|
482
|
+
| `content:added` | Content block added |
|
|
483
|
+
| `content:deleted` | Content block deleted |
|
|
484
|
+
| `preview:shown` | Preview opened |
|
|
485
|
+
| `preview:hidden` | Preview closed |
|
|
486
|
+
| `image:uploaded` | Image uploaded successfully |
|
|
487
|
+
| `image:error` | Image upload error |
|
|
488
|
+
| `export:html` | HTML exported |
|
|
489
|
+
| `export:plainText` | Plain text exported |
|
|
490
|
+
| `export:image` | Image exported |
|
|
491
|
+
| `save` | Save triggered |
|
|
492
|
+
| `save:success` | Save succeeded |
|
|
493
|
+
| `save:error` | Save failed |
|
|
494
|
+
| `template:requested` | Template requested |
|
|
495
|
+
| `element:selected` | Element selected |
|
|
496
|
+
| `element:deselected` | Element deselected |
|
|
497
|
+
| `export` | Export triggered |
|
|
498
|
+
| `displayCondition:applied` | Display condition applied |
|
|
499
|
+
| `displayCondition:removed` | Display condition removed |
|
|
500
|
+
| `displayCondition:updated` | Display condition updated |
|
|
501
|
+
|
|
502
|
+
## TypeScript
|
|
503
|
+
|
|
504
|
+
All SDK types are re-exported from the package:
|
|
505
|
+
|
|
506
|
+
```tsx
|
|
507
|
+
import type {
|
|
508
|
+
DragbleEditorRef,
|
|
509
|
+
DragbleEditorProps,
|
|
510
|
+
DesignJson,
|
|
511
|
+
EditorOptions,
|
|
512
|
+
MergeTag,
|
|
513
|
+
MergeTagGroup,
|
|
514
|
+
MergeTagsConfig,
|
|
515
|
+
SpecialLink,
|
|
516
|
+
SpecialLinkGroup,
|
|
517
|
+
SpecialLinksConfig,
|
|
518
|
+
FontsConfig,
|
|
519
|
+
EditorMode,
|
|
520
|
+
PopupConfig,
|
|
521
|
+
UserInfo,
|
|
522
|
+
CollaborationFeaturesConfig,
|
|
523
|
+
CommentAction,
|
|
524
|
+
} from "dragble-react-editor";
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
## Contributing
|
|
528
|
+
|
|
529
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines on how to contribute to this project.
|
|
530
|
+
|
|
531
|
+
## License
|
|
532
|
+
|
|
533
|
+
[MIT](./LICENSE)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { DragbleSDK, DesignJson, ModuleData, EditorMode, EditorOptions, PopupConfig, CollaborationFeaturesConfig, UserInfo, DragbleCallbacks, CommentAction } from 'dragble-types';
|
|
3
|
+
export * from 'dragble-types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @dragble/react-editor
|
|
7
|
+
* React wrapper for the Dragble Editor SDK
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
declare global {
|
|
11
|
+
interface Window {
|
|
12
|
+
dragble?: DragbleSDK;
|
|
13
|
+
createEditor?: () => DragbleSDK;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
interface DragbleEditorRef {
|
|
17
|
+
editor: DragbleSDK | null;
|
|
18
|
+
isReady: () => boolean;
|
|
19
|
+
}
|
|
20
|
+
interface DragbleEditorProps {
|
|
21
|
+
editorKey: string;
|
|
22
|
+
design?: DesignJson | ModuleData | null;
|
|
23
|
+
editorMode?: EditorMode;
|
|
24
|
+
/**
|
|
25
|
+
* Content type for module editing mode.
|
|
26
|
+
* When set to "module", the editor is locked to a single row.
|
|
27
|
+
*/
|
|
28
|
+
contentType?: "module";
|
|
29
|
+
/**
|
|
30
|
+
* All editor configuration (appearance, tools, features, AI, storage, etc.).
|
|
31
|
+
* These are placed under `options` in the SDK's DragbleConfig.
|
|
32
|
+
*/
|
|
33
|
+
options?: EditorOptions;
|
|
34
|
+
/** Popup builder configuration (only used when editorMode is 'popup') */
|
|
35
|
+
popup?: PopupConfig;
|
|
36
|
+
/**
|
|
37
|
+
* Team collaboration features (commenting, reviewer role, etc.)
|
|
38
|
+
* Can be a simple boolean or detailed configuration object.
|
|
39
|
+
*
|
|
40
|
+
* @example Simple boolean
|
|
41
|
+
* ```tsx
|
|
42
|
+
* <DragbleEditor collaboration={true} />
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @example Reviewer role with mentions
|
|
46
|
+
* ```tsx
|
|
47
|
+
* <DragbleEditor
|
|
48
|
+
* collaboration={{
|
|
49
|
+
* enabled: true,
|
|
50
|
+
* role: 'reviewer',
|
|
51
|
+
* commenting: {
|
|
52
|
+
* mentions: true,
|
|
53
|
+
* getMentions: async (search) => {
|
|
54
|
+
* const res = await fetch(`/api/team?q=${search}`);
|
|
55
|
+
* return await res.json();
|
|
56
|
+
* }
|
|
57
|
+
* },
|
|
58
|
+
* }}
|
|
59
|
+
* onComment={(action) => console.log(action)}
|
|
60
|
+
* />
|
|
61
|
+
* ```
|
|
62
|
+
* @default false
|
|
63
|
+
*/
|
|
64
|
+
collaboration?: boolean | CollaborationFeaturesConfig;
|
|
65
|
+
/** User information for session identity and collaboration */
|
|
66
|
+
user?: UserInfo;
|
|
67
|
+
/**
|
|
68
|
+
* Design mode for template permissions.
|
|
69
|
+
* - 'edit': Admin mode - shows "Row Actions" for setting row permissions
|
|
70
|
+
* - 'live': End-user mode - enforces row permissions (selectable, draggable, locked, etc.)
|
|
71
|
+
* @default 'live'
|
|
72
|
+
*/
|
|
73
|
+
designMode?: "edit" | "live";
|
|
74
|
+
height?: string | number;
|
|
75
|
+
/**
|
|
76
|
+
* Additional callbacks for the SDK.
|
|
77
|
+
* These are placed under `callbacks` in the SDK's DragbleConfig.
|
|
78
|
+
* Note: onReady, onLoad, onChange, onError are handled via dedicated props.
|
|
79
|
+
*/
|
|
80
|
+
callbacks?: Omit<DragbleCallbacks, "onReady" | "onLoad" | "onChange" | "onError">;
|
|
81
|
+
className?: string;
|
|
82
|
+
style?: React.CSSProperties;
|
|
83
|
+
minHeight?: string | number;
|
|
84
|
+
/**
|
|
85
|
+
* Custom SDK URL for loading the Dragble SDK script.
|
|
86
|
+
* @default "https://sdk.dragble.com/latest/dragble-sdk.min.js"
|
|
87
|
+
*/
|
|
88
|
+
sdkUrl?: string;
|
|
89
|
+
/**
|
|
90
|
+
* SDK version to load from the Dragble CDN.
|
|
91
|
+
* @default "latest"
|
|
92
|
+
*/
|
|
93
|
+
sdkVersion?: string;
|
|
94
|
+
/** Editor version forwarded to the SDK init config. */
|
|
95
|
+
editorVersion?: string;
|
|
96
|
+
/** Editor URL forwarded to the SDK init config. */
|
|
97
|
+
editorUrl?: string;
|
|
98
|
+
onReady?: (editor: DragbleSDK) => void;
|
|
99
|
+
onLoad?: () => void;
|
|
100
|
+
onChange?: (data: {
|
|
101
|
+
design: DesignJson;
|
|
102
|
+
type: string;
|
|
103
|
+
}) => void;
|
|
104
|
+
onError?: (error: Error) => void;
|
|
105
|
+
/** Callback invoked when a comment event occurs (create, edit, delete, resolve, reopen) */
|
|
106
|
+
onComment?: (action: CommentAction) => void;
|
|
107
|
+
}
|
|
108
|
+
declare const DragbleEditor: React.ForwardRefExoticComponent<DragbleEditorProps & React.RefAttributes<DragbleEditorRef>>;
|
|
109
|
+
declare function useDragbleEditor(): {
|
|
110
|
+
ref: React.RefObject<DragbleEditorRef>;
|
|
111
|
+
editor: DragbleSDK | null;
|
|
112
|
+
isReady: boolean;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export { DragbleEditor, DragbleEditor as default, useDragbleEditor };
|
|
116
|
+
export type { DragbleEditorProps, DragbleEditorRef };
|