@emabuild/core 0.0.2 → 0.0.4
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 +410 -0
- package/dist/dnd/drag-manager.d.ts +13 -14
- package/dist/dnd/drag-manager.d.ts.map +1 -1
- package/dist/dnd/drop-indicator.d.ts +24 -0
- package/dist/dnd/drop-indicator.d.ts.map +1 -0
- package/dist/dnd/shadow-dom-utils.d.ts +29 -0
- package/dist/dnd/shadow-dom-utils.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/{mail-editor-CoB2C5CT.js → mail-editor-D0FbEUZu.js} +677 -870
- package/dist/mail-editor-D0FbEUZu.js.map +1 -0
- package/dist/mail-editor.d.ts +3 -3
- package/dist/mail-editor.d.ts.map +1 -1
- package/dist/mail-editor.js +1 -1
- package/dist/properties/property-panel.d.ts +4 -9
- package/dist/properties/property-panel.d.ts.map +1 -1
- package/dist/properties/widgets/alignment-widget.d.ts +4 -0
- package/dist/properties/widgets/alignment-widget.d.ts.map +1 -0
- package/dist/properties/widgets/color-picker-widget.d.ts +4 -0
- package/dist/properties/widgets/color-picker-widget.d.ts.map +1 -0
- package/dist/properties/widgets/dropdown-widget.d.ts +4 -0
- package/dist/properties/widgets/dropdown-widget.d.ts.map +1 -0
- package/dist/properties/widgets/index.d.ts +8 -0
- package/dist/properties/widgets/index.d.ts.map +1 -0
- package/dist/properties/widgets/padding-widget.d.ts +4 -0
- package/dist/properties/widgets/padding-widget.d.ts.map +1 -0
- package/dist/properties/widgets/text-input-widget.d.ts +4 -0
- package/dist/properties/widgets/text-input-widget.d.ts.map +1 -0
- package/dist/properties/widgets/textarea-widget.d.ts +4 -0
- package/dist/properties/widgets/textarea-widget.d.ts.map +1 -0
- package/dist/properties/widgets/toggle-widget.d.ts +4 -0
- package/dist/properties/widgets/toggle-widget.d.ts.map +1 -0
- package/dist/sidebar/body-settings.d.ts +15 -0
- package/dist/sidebar/body-settings.d.ts.map +1 -0
- package/dist/sidebar/editor-sidebar.d.ts +0 -3
- package/dist/sidebar/editor-sidebar.d.ts.map +1 -1
- package/dist/state/design-factory.d.ts +9 -0
- package/dist/state/design-factory.d.ts.map +1 -0
- package/dist/state/design-lookup.d.ts +14 -0
- package/dist/state/design-lookup.d.ts.map +1 -0
- package/dist/state/editor-store.d.ts +27 -10
- package/dist/state/editor-store.d.ts.map +1 -1
- package/dist/state/history-manager.d.ts +20 -0
- package/dist/state/history-manager.d.ts.map +1 -0
- package/dist/tools/built-in/button-tool.d.ts.map +1 -1
- package/dist/tools/built-in/divider-tool.d.ts.map +1 -1
- package/dist/tools/built-in/form-tool.d.ts.map +1 -1
- package/dist/tools/built-in/heading-tool.d.ts.map +1 -1
- package/dist/tools/built-in/html-tool.d.ts.map +1 -1
- package/dist/tools/built-in/image-tool.d.ts.map +1 -1
- package/dist/tools/built-in/menu-tool.d.ts.map +1 -1
- package/dist/tools/built-in/paragraph-tool.d.ts.map +1 -1
- package/dist/tools/built-in/social-tool.d.ts.map +1 -1
- package/dist/tools/built-in/table-tool.d.ts.map +1 -1
- package/dist/tools/built-in/text-tool.d.ts.map +1 -1
- package/dist/tools/built-in/timer-tool.d.ts.map +1 -1
- package/dist/tools/built-in/video-tool.d.ts.map +1 -1
- package/dist/tools/helpers/email-html.d.ts +55 -0
- package/dist/tools/helpers/email-html.d.ts.map +1 -0
- package/dist/tools/helpers/index.d.ts +5 -0
- package/dist/tools/helpers/index.d.ts.map +1 -0
- package/dist/tools/helpers/types.d.ts +36 -0
- package/dist/tools/helpers/types.d.ts.map +1 -0
- package/dist/tools/helpers/value-extractor.d.ts +31 -0
- package/dist/tools/helpers/value-extractor.d.ts.map +1 -0
- package/dist/utils/event-emitter.d.ts +32 -4
- package/dist/utils/event-emitter.d.ts.map +1 -1
- package/dist/utils/id-generator.d.ts +17 -3
- package/dist/utils/id-generator.d.ts.map +1 -1
- package/package.json +16 -4
- package/dist/mail-editor-CoB2C5CT.js.map +0 -1
- package/dist/utils/deep-clone.d.ts +0 -2
- package/dist/utils/deep-clone.d.ts.map +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
# @emabuild — Drag & Drop Email Editor
|
|
2
|
+
|
|
3
|
+
A fully embeddable drag-and-drop email editor Web Component. Cross-client email HTML export, and 13 built-in content blocks.
|
|
4
|
+
|
|
5
|
+
Built with [Lit 3](https://lit.dev/) — works in Angular, React, Vue, or plain HTML.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @emabuild/core lit
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<mail-editor id="editor" style="height:100vh;"></mail-editor>
|
|
15
|
+
|
|
16
|
+
<script type="module">
|
|
17
|
+
import '@emabuild/core/mail-editor';
|
|
18
|
+
|
|
19
|
+
const editor = document.getElementById('editor');
|
|
20
|
+
|
|
21
|
+
editor.addEventListener('editor:ready', () => {
|
|
22
|
+
console.log('Editor is ready');
|
|
23
|
+
});
|
|
24
|
+
</script>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Packages
|
|
28
|
+
|
|
29
|
+
| Package | Description | Size |
|
|
30
|
+
|---------|-------------|------|
|
|
31
|
+
| [`@emabuild/core`](https://www.npmjs.com/package/@emabuild/core) | `<mail-editor>` Web Component | ~17KB gzip |
|
|
32
|
+
| [`@emabuild/email-renderer`](https://www.npmjs.com/package/@emabuild/email-renderer) | Standalone HTML export engine (works server-side) | ~3KB gzip |
|
|
33
|
+
| [`@emabuild/types`](https://www.npmjs.com/package/@emabuild/types) | TypeScript type definitions | types only |
|
|
34
|
+
|
|
35
|
+
## Framework Integration
|
|
36
|
+
|
|
37
|
+
### Angular
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install @emabuild/core lit
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
// app.module.ts
|
|
45
|
+
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
|
46
|
+
|
|
47
|
+
@NgModule({
|
|
48
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
49
|
+
})
|
|
50
|
+
export class AppModule {}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
// app.component.ts
|
|
55
|
+
import '@emabuild/core/mail-editor';
|
|
56
|
+
|
|
57
|
+
@Component({
|
|
58
|
+
template: `<mail-editor #editor style="height:100vh;"></mail-editor>
|
|
59
|
+
<button (click)="exportHtml()">Export</button>`,
|
|
60
|
+
})
|
|
61
|
+
export class AppComponent {
|
|
62
|
+
@ViewChild('editor') editor!: ElementRef;
|
|
63
|
+
|
|
64
|
+
exportHtml() {
|
|
65
|
+
this.editor.nativeElement.exportHtml((result) => {
|
|
66
|
+
console.log(result.html);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### React
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import '@emabuild/core/mail-editor';
|
|
76
|
+
import { useRef, useEffect } from 'react';
|
|
77
|
+
|
|
78
|
+
export function EmailEditor() {
|
|
79
|
+
const editorRef = useRef<any>(null);
|
|
80
|
+
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
const el = editorRef.current;
|
|
83
|
+
el?.addEventListener('editor:ready', () => {
|
|
84
|
+
el.loadDesign(myDesign);
|
|
85
|
+
});
|
|
86
|
+
}, []);
|
|
87
|
+
|
|
88
|
+
const handleExport = () => {
|
|
89
|
+
editorRef.current?.exportHtml((result) => {
|
|
90
|
+
console.log(result.html);
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<div style={{ height: '100vh' }}>
|
|
96
|
+
<mail-editor ref={editorRef} />
|
|
97
|
+
<button onClick={handleExport}>Export HTML</button>
|
|
98
|
+
</div>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Vue
|
|
104
|
+
|
|
105
|
+
```vue
|
|
106
|
+
<template>
|
|
107
|
+
<mail-editor ref="editor" style="height: 100vh" />
|
|
108
|
+
<button @click="exportHtml">Export</button>
|
|
109
|
+
</template>
|
|
110
|
+
|
|
111
|
+
<script setup>
|
|
112
|
+
import '@emabuild/core/mail-editor';
|
|
113
|
+
import { ref, onMounted } from 'vue';
|
|
114
|
+
|
|
115
|
+
const editor = ref(null);
|
|
116
|
+
|
|
117
|
+
onMounted(() => {
|
|
118
|
+
editor.value.addEventListener('editor:ready', () => {
|
|
119
|
+
editor.value.loadDesign(myDesign);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
function exportHtml() {
|
|
124
|
+
editor.value.exportHtml((result) => {
|
|
125
|
+
console.log(result.html);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
</script>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## API Reference
|
|
132
|
+
|
|
133
|
+
### Methods
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
// Load a design JSON
|
|
137
|
+
editor.loadDesign(design: EmailDesign): void;
|
|
138
|
+
|
|
139
|
+
// Save the current design as JSON
|
|
140
|
+
editor.saveDesign(callback: (design: EmailDesign) => void): void;
|
|
141
|
+
|
|
142
|
+
// Export email-ready HTML
|
|
143
|
+
editor.exportHtml(callback: (result: ExportResult) => void, options?: ExportOptions): void;
|
|
144
|
+
|
|
145
|
+
// Promise-based export
|
|
146
|
+
const result = await editor.exportHtmlAsync(options?: ExportOptions);
|
|
147
|
+
|
|
148
|
+
// Undo / Redo
|
|
149
|
+
editor.undo(): void;
|
|
150
|
+
editor.redo(): void;
|
|
151
|
+
|
|
152
|
+
// Register a custom tool
|
|
153
|
+
editor.registerTool(definition: ToolDefinition): void;
|
|
154
|
+
|
|
155
|
+
// Register a callback (e.g. for image upload)
|
|
156
|
+
editor.registerCallback(type: string, callback: Function): void;
|
|
157
|
+
|
|
158
|
+
// Update body-level settings
|
|
159
|
+
editor.setBodyValues(values: Partial<BodyValues>): void;
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Events
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
editor.addEventListener('editor:ready', () => {
|
|
166
|
+
// Editor is fully initialized
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
editor.addEventListener('design:loaded', (e) => {
|
|
170
|
+
// A design was loaded via loadDesign()
|
|
171
|
+
console.log(e.detail.design);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
editor.addEventListener('design:updated', (e) => {
|
|
175
|
+
// User made a change
|
|
176
|
+
console.log(e.detail.type); // 'content_updated' | 'row_added' | ...
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Export Result
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
editor.exportHtml((result) => {
|
|
184
|
+
result.design; // EmailDesign JSON — save this for future editing
|
|
185
|
+
result.html; // Complete HTML document (<!DOCTYPE> to </html>)
|
|
186
|
+
result.chunks; // { body, css, fonts[], js }
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Export Options
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
editor.exportHtml(callback, {
|
|
194
|
+
minify: true, // Minify HTML output
|
|
195
|
+
inlineStyles: true, // Inline CSS into style attributes
|
|
196
|
+
cleanup: true, // Remove unused CSS classes
|
|
197
|
+
mergeTags: { // Replace merge tags with values
|
|
198
|
+
first_name: 'John',
|
|
199
|
+
company: 'Acme',
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Built-in Content Blocks
|
|
205
|
+
|
|
206
|
+
| Block | Description | Email Safe |
|
|
207
|
+
|-------|-------------|:----------:|
|
|
208
|
+
| Text | Rich text with formatting | Yes |
|
|
209
|
+
| Heading | H1-H4 with size/weight/color | Yes |
|
|
210
|
+
| Paragraph | Block text with line-height | Yes |
|
|
211
|
+
| Image | Responsive image with link | Yes |
|
|
212
|
+
| Button | CTA button (VML Outlook fallback) | Yes |
|
|
213
|
+
| Divider | Horizontal line | Yes |
|
|
214
|
+
| HTML | Raw HTML injection | Yes |
|
|
215
|
+
| Social | Social media icon links | Yes |
|
|
216
|
+
| Menu | Horizontal navigation | Yes |
|
|
217
|
+
| Video | YouTube/Vimeo thumbnail + play | Yes |
|
|
218
|
+
| Timer | Countdown display | Yes |
|
|
219
|
+
| Table | Data table with headers | Yes |
|
|
220
|
+
| Form | Input form (web mode only) | Web only |
|
|
221
|
+
|
|
222
|
+
## Layout Presets
|
|
223
|
+
|
|
224
|
+
Drag or click to add rows with predefined column layouts:
|
|
225
|
+
|
|
226
|
+
- `100%` — single column
|
|
227
|
+
- `50 / 50` — two equal columns
|
|
228
|
+
- `33 / 33 / 33` — three equal columns
|
|
229
|
+
- `66 / 33` — two-thirds + one-third
|
|
230
|
+
- `33 / 66` — one-third + two-thirds
|
|
231
|
+
- `25 / 25 / 25 / 25` — four equal columns
|
|
232
|
+
|
|
233
|
+
## Custom Tools
|
|
234
|
+
|
|
235
|
+
Register custom content blocks with their own properties and renderers:
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
import { html } from 'lit';
|
|
239
|
+
|
|
240
|
+
editor.registerTool({
|
|
241
|
+
name: 'product_card',
|
|
242
|
+
label: 'Product Card',
|
|
243
|
+
icon: '<svg>...</svg>',
|
|
244
|
+
supportedDisplayModes: ['email'],
|
|
245
|
+
options: {
|
|
246
|
+
product: {
|
|
247
|
+
title: 'Product',
|
|
248
|
+
options: {
|
|
249
|
+
name: { label: 'Name', defaultValue: 'Product', widget: 'text' },
|
|
250
|
+
price: { label: 'Price', defaultValue: '$0.00', widget: 'text' },
|
|
251
|
+
image: { label: 'Image URL', defaultValue: '', widget: 'text' },
|
|
252
|
+
bgColor: { label: 'Background', defaultValue: '#ffffff', widget: 'color_picker' },
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
defaultValues: {
|
|
257
|
+
name: 'Product', price: '$0.00', image: '', bgColor: '#ffffff',
|
|
258
|
+
},
|
|
259
|
+
renderer: {
|
|
260
|
+
renderEditor(values) {
|
|
261
|
+
return html`
|
|
262
|
+
<div style="background:${values.bgColor};padding:16px;text-align:center;">
|
|
263
|
+
<img src="${values.image}" style="max-width:100%;border-radius:8px;" />
|
|
264
|
+
<h3 style="margin:12px 0 4px;">${values.name}</h3>
|
|
265
|
+
<p style="color:#3b82f6;font-weight:bold;">${values.price}</p>
|
|
266
|
+
</div>
|
|
267
|
+
`;
|
|
268
|
+
},
|
|
269
|
+
renderHtml(values, ctx) {
|
|
270
|
+
return `<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0">
|
|
271
|
+
<tr><td style="background-color:${values.bgColor};padding:16px;text-align:center;">
|
|
272
|
+
<img src="${values.image}" width="${ctx.columnWidth}" style="max-width:100%;" />
|
|
273
|
+
<h3 style="margin:12px 0 4px;">${values.name}</h3>
|
|
274
|
+
<p style="color:#3b82f6;font-weight:bold;">${values.price}</p>
|
|
275
|
+
</td></tr>
|
|
276
|
+
</table>`;
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Design JSON Structure
|
|
283
|
+
|
|
284
|
+
Designs are stored as structured JSON. The format is interoperable with other email editor tools.
|
|
285
|
+
|
|
286
|
+
```json
|
|
287
|
+
{
|
|
288
|
+
"counters": { "u_row": 1, "u_column": 1, "u_content_text": 1 },
|
|
289
|
+
"body": {
|
|
290
|
+
"id": "u_body",
|
|
291
|
+
"rows": [
|
|
292
|
+
{
|
|
293
|
+
"id": "u_row_1",
|
|
294
|
+
"cells": [1],
|
|
295
|
+
"columns": [
|
|
296
|
+
{
|
|
297
|
+
"id": "u_column_1",
|
|
298
|
+
"contents": [
|
|
299
|
+
{
|
|
300
|
+
"id": "u_content_text_1",
|
|
301
|
+
"type": "text",
|
|
302
|
+
"values": {
|
|
303
|
+
"text": "<p>Hello World</p>",
|
|
304
|
+
"containerPadding": "10px",
|
|
305
|
+
"_meta": { "htmlID": "u_content_text_1", "htmlClassNames": "u_content_text" }
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
],
|
|
309
|
+
"values": { "backgroundColor": "", "padding": "0px", "_meta": { "htmlID": "u_column_1", "htmlClassNames": "u_column" } }
|
|
310
|
+
}
|
|
311
|
+
],
|
|
312
|
+
"values": { "backgroundColor": "", "columnsBackgroundColor": "#ffffff", "padding": "0px", "_meta": { "htmlID": "u_row_1", "htmlClassNames": "u_row" } }
|
|
313
|
+
}
|
|
314
|
+
],
|
|
315
|
+
"headers": [],
|
|
316
|
+
"footers": [],
|
|
317
|
+
"values": {
|
|
318
|
+
"backgroundColor": "#e7e7e7",
|
|
319
|
+
"contentWidth": "600px",
|
|
320
|
+
"fontFamily": { "label": "Arial", "value": "arial,helvetica,sans-serif" },
|
|
321
|
+
"textColor": "#000000",
|
|
322
|
+
"preheaderText": "",
|
|
323
|
+
"_meta": { "htmlID": "u_body", "htmlClassNames": "u_body" }
|
|
324
|
+
}
|
|
325
|
+
},
|
|
326
|
+
"schemaVersion": 16
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## Server-Side Rendering
|
|
331
|
+
|
|
332
|
+
Use `@emabuild/email-renderer` to generate HTML from design JSON on the server (Node.js):
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
import { renderDesignToHtml } from '@emabuild/email-renderer';
|
|
336
|
+
|
|
337
|
+
const toolRenderers = new Map();
|
|
338
|
+
// Register tool HTML renderers...
|
|
339
|
+
|
|
340
|
+
const result = renderDesignToHtml(designJson, toolRenderers, {
|
|
341
|
+
minify: true,
|
|
342
|
+
mergeTags: { first_name: 'John' },
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
console.log(result.html); // Complete email HTML
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## Email Client Support
|
|
349
|
+
|
|
350
|
+
Exported HTML uses fluid hybrid design with MSO conditional comments for maximum compatibility:
|
|
351
|
+
|
|
352
|
+
- Gmail (Web, iOS, Android)
|
|
353
|
+
- Outlook (2016, 2019, 365, Outlook.com)
|
|
354
|
+
- Apple Mail (macOS, iOS)
|
|
355
|
+
- Yahoo Mail
|
|
356
|
+
- Thunderbird
|
|
357
|
+
- Samsung Mail
|
|
358
|
+
|
|
359
|
+
Key techniques used:
|
|
360
|
+
- Table-based layout with `role="presentation"`
|
|
361
|
+
- MSO ghost tables (`<!--[if mso]>`) for Outlook column rendering
|
|
362
|
+
- VML roundrect for Outlook button border-radius
|
|
363
|
+
- Responsive CSS with `@media` queries
|
|
364
|
+
- Fluid hybrid columns (`display:inline-block` + `max-width`)
|
|
365
|
+
- Dark mode support (`prefers-color-scheme`)
|
|
366
|
+
- Preheader text with invisible padding fill
|
|
367
|
+
|
|
368
|
+
## Keyboard Shortcuts
|
|
369
|
+
|
|
370
|
+
| Shortcut | Action |
|
|
371
|
+
|----------|--------|
|
|
372
|
+
| `Ctrl/Cmd + Z` | Undo |
|
|
373
|
+
| `Ctrl/Cmd + Y` | Redo |
|
|
374
|
+
| `Ctrl/Cmd + Shift + Z` | Redo |
|
|
375
|
+
| `Delete` / `Backspace` | Delete selected element |
|
|
376
|
+
| `Escape` | Deselect |
|
|
377
|
+
|
|
378
|
+
## Property Widgets
|
|
379
|
+
|
|
380
|
+
Available widget types for tool property definitions:
|
|
381
|
+
|
|
382
|
+
| Widget | Type | Description |
|
|
383
|
+
|--------|------|-------------|
|
|
384
|
+
| `text` | `string` | Single-line text input |
|
|
385
|
+
| `rich_text` | `string` | Multi-line textarea (HTML) |
|
|
386
|
+
| `color_picker` | `string` | Color swatch + hex input |
|
|
387
|
+
| `toggle` | `boolean` | Checkbox toggle |
|
|
388
|
+
| `dropdown` | `string` | Select dropdown (requires `widgetParams.options`) |
|
|
389
|
+
| `alignment` | `string` | Left/center/right visual picker |
|
|
390
|
+
| `padding` | `string` | 4-side padding editor (CSS shorthand) |
|
|
391
|
+
|
|
392
|
+
## Development
|
|
393
|
+
|
|
394
|
+
```bash
|
|
395
|
+
# Install dependencies
|
|
396
|
+
pnpm install
|
|
397
|
+
|
|
398
|
+
# Start the demo app
|
|
399
|
+
pnpm --filter @emabuild/demo dev
|
|
400
|
+
|
|
401
|
+
# Build all packages
|
|
402
|
+
pnpm build
|
|
403
|
+
|
|
404
|
+
# Publish to npm
|
|
405
|
+
pnpm -r publish --access public
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
## License
|
|
409
|
+
|
|
410
|
+
MIT
|
|
@@ -5,26 +5,25 @@ export declare class DragManager {
|
|
|
5
5
|
private toolRegistry;
|
|
6
6
|
private root;
|
|
7
7
|
private currentDrop;
|
|
8
|
-
private
|
|
8
|
+
private contentIndicator;
|
|
9
9
|
private rowIndicator;
|
|
10
10
|
constructor(store: EditorStore, toolRegistry: ToolRegistry, root: ShadowRoot);
|
|
11
|
+
/** Attach all drag event listeners to the shadow root */
|
|
11
12
|
attach(): void;
|
|
12
|
-
|
|
13
|
+
/** Remove all event listeners and clean up indicators */
|
|
13
14
|
detach(): void;
|
|
14
|
-
private
|
|
15
|
-
private
|
|
16
|
-
private
|
|
17
|
-
private
|
|
18
|
-
private
|
|
19
|
-
private
|
|
20
|
-
private
|
|
15
|
+
private onDragOver;
|
|
16
|
+
private onDrop;
|
|
17
|
+
private onDragEnd;
|
|
18
|
+
private onDragLeave;
|
|
19
|
+
private handleLayoutDrop;
|
|
20
|
+
private handleToolDrop;
|
|
21
|
+
private handleContentDrop;
|
|
22
|
+
private findRowDropTarget;
|
|
23
|
+
private findContentDropTarget;
|
|
21
24
|
private showContentIndicator;
|
|
22
25
|
private showRowIndicator;
|
|
23
|
-
private
|
|
24
|
-
private hideRowIndicator;
|
|
26
|
+
private hideAllIndicators;
|
|
25
27
|
private reset;
|
|
26
|
-
private queryShadowAll;
|
|
27
|
-
private walkShadowDom;
|
|
28
|
-
private findContentElement;
|
|
29
28
|
}
|
|
30
29
|
//# sourceMappingURL=drag-manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drag-manager.d.ts","sourceRoot":"","sources":["../../src/dnd/drag-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"drag-manager.d.ts","sourceRoot":"","sources":["../../src/dnd/drag-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAe9D,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,YAAY,CAA4B;gBAEpC,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU;IAM5E,yDAAyD;IACzD,MAAM,IAAI,IAAI;IASd,yDAAyD;IACzD,MAAM,IAAI,IAAI;IAWd,OAAO,CAAC,UAAU,CAoBhB;IAEF,OAAO,CAAC,MAAM,CAqBZ;IAEF,OAAO,CAAC,SAAS,CAGf;IAEF,OAAO,CAAC,WAAW,CAMjB;IAIF,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,cAAc;IAiBtB,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,iBAAiB;IAqBzB,OAAO,CAAC,qBAAqB;IAgD7B,OAAO,CAAC,oBAAoB;IAc5B,OAAO,CAAC,gBAAgB;IAcxB,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,KAAK;CAId"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module drop-indicator
|
|
3
|
+
*
|
|
4
|
+
* Reusable drop indicator creation and positioning.
|
|
5
|
+
* Used by DragManager for both content-level (blue) and row-level (purple) indicators.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Create a floating drop indicator element.
|
|
9
|
+
* @param color - CSS color for the indicator line
|
|
10
|
+
* @returns An absolutely-positioned HTMLElement (hidden by default)
|
|
11
|
+
*/
|
|
12
|
+
export declare function createDropIndicator(color: string): HTMLElement;
|
|
13
|
+
/**
|
|
14
|
+
* Position an indicator at a specific Y offset within a container.
|
|
15
|
+
* @param indicator - The indicator element
|
|
16
|
+
* @param container - The shadow root or element to append the indicator to
|
|
17
|
+
* @param items - The list of elements to position between
|
|
18
|
+
* @param index - The insertion index (0 = before first, items.length = after last)
|
|
19
|
+
* @param insetX - Horizontal inset from edges (e.g. "4px" for content, "0" for rows)
|
|
20
|
+
*/
|
|
21
|
+
export declare function positionIndicator(indicator: HTMLElement, container: ShadowRoot | HTMLElement, items: HTMLElement[], index: number, insetX?: string): void;
|
|
22
|
+
/** Hide a drop indicator */
|
|
23
|
+
export declare function hideIndicator(indicator: HTMLElement | null): void;
|
|
24
|
+
//# sourceMappingURL=drop-indicator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drop-indicator.d.ts","sourceRoot":"","sources":["../../src/dnd/drop-indicator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAe9D;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,WAAW,EACtB,SAAS,EAAE,UAAU,GAAG,WAAW,EACnC,KAAK,EAAE,WAAW,EAAE,EACpB,KAAK,EAAE,MAAM,EACb,MAAM,SAAQ,GACb,IAAI,CA2BN;AAED,4BAA4B;AAC5B,wBAAgB,aAAa,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAEjE"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module shadow-dom-utils
|
|
3
|
+
*
|
|
4
|
+
* Utilities for traversing nested shadow DOM trees.
|
|
5
|
+
* Required because the editor uses Lit Web Components with shadow DOM,
|
|
6
|
+
* and standard `querySelectorAll` doesn't cross shadow boundaries.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Recursively walk all elements across shadow DOM boundaries.
|
|
10
|
+
* @param root - Starting point (ShadowRoot or HTMLElement)
|
|
11
|
+
* @param callback - Called for each element encountered
|
|
12
|
+
*/
|
|
13
|
+
export declare function walkShadowDom(root: ShadowRoot | HTMLElement, callback: (el: HTMLElement) => void): void;
|
|
14
|
+
/**
|
|
15
|
+
* Query all elements matching a selector across shadow DOM boundaries.
|
|
16
|
+
* @param root - Starting point
|
|
17
|
+
* @param selector - CSS selector to match
|
|
18
|
+
* @returns Array of matching elements
|
|
19
|
+
*/
|
|
20
|
+
export declare function queryShadowAll<T extends HTMLElement>(root: ShadowRoot | HTMLElement, selector: string): T[];
|
|
21
|
+
/**
|
|
22
|
+
* Walk up the DOM tree (including shadow DOM boundaries) to find
|
|
23
|
+
* an ancestor with a specific `data-*` attribute.
|
|
24
|
+
* @param el - Starting element
|
|
25
|
+
* @param dataKey - The dataset key to look for (e.g. "contentId" for data-content-id)
|
|
26
|
+
* @returns The matching ancestor element, or null
|
|
27
|
+
*/
|
|
28
|
+
export declare function findAncestorWithData(el: HTMLElement | null, dataKey: string): HTMLElement | null;
|
|
29
|
+
//# sourceMappingURL=shadow-dom-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shadow-dom-utils.d.ts","sourceRoot":"","sources":["../../src/dnd/shadow-dom-utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,IAAI,GAAG,IAAI,CAQvG;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,EAAE,UAAU,GAAG,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,EAAE,CAM3G;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,WAAW,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAYhG"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ export { MailEditorElement } from './mail-editor.js';
|
|
|
2
2
|
export { EditorStore } from './state/editor-store.js';
|
|
3
3
|
export { ToolRegistry } from './tools/tool-registry.js';
|
|
4
4
|
export type { LitToolDefinition } from './tools/tool-registry.js';
|
|
5
|
-
export type {
|
|
5
|
+
export type { EmailDesign, DesignBody, DesignRow, DesignColumn, DesignContent, MailEditorConfig, ExportResult, ExportOptions, ToolDefinition, ToolPropertyGroup, ToolProperty, } from '@emabuild/types';
|
|
6
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,YAAY,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGlE,YAAY,EACV,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,YAAY,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGlE,YAAY,EACV,WAAW,EACX,UAAU,EACV,SAAS,EACT,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,YAAY,GACb,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED