authorly-editor 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/LICENSE +21 -0
- package/README.md +544 -0
- package/dist/blocks/accordion.d.ts +11 -0
- package/dist/blocks/callout.d.ts +11 -0
- package/dist/blocks/code.d.ts +84 -0
- package/dist/blocks/divider.d.ts +7 -0
- package/dist/blocks/heading.d.ts +9 -0
- package/dist/blocks/image.d.ts +28 -0
- package/dist/blocks/index.d.ts +31 -0
- package/dist/blocks/list.d.ts +25 -0
- package/dist/blocks/paragraph.d.ts +3 -0
- package/dist/blocks/quote.d.ts +11 -0
- package/dist/blocks/table.d.ts +34 -0
- package/dist/blocks/video.d.ts +11 -0
- package/dist/components/BlockMenu.d.ts +4 -0
- package/dist/components/BlockWrapper.d.ts +18 -0
- package/dist/components/Editor.d.ts +13 -0
- package/dist/components/Renderer.d.ts +34 -0
- package/dist/components/TableOfContents.d.ts +59 -0
- package/dist/components/Toolbar.d.ts +4 -0
- package/dist/components/index.d.ts +9 -0
- package/dist/core/block-registry.d.ts +60 -0
- package/dist/core/commands.d.ts +123 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/core/selection.d.ts +88 -0
- package/dist/core/types.d.ts +325 -0
- package/dist/drag/drag-handle.d.ts +31 -0
- package/dist/icons/index.d.ts +12 -0
- package/dist/index.cjs.js +877 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.esm.js +5321 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/paste/sanitize.d.ts +40 -0
- package/dist/style.css +1 -0
- package/dist/utils/helpers.d.ts +149 -0
- package/dist/utils/index.d.ts +4 -0
- package/package.json +73 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core Types for Content Blocks Editor
|
|
3
|
+
* Pure HTML output, DOM-first architecture
|
|
4
|
+
*/
|
|
5
|
+
export type BlockType = 'paragraph' | 'heading' | 'bulletList' | 'numberedList' | 'checkList' | 'quote' | 'code' | 'image' | 'video' | 'divider' | 'callout' | 'accordion' | 'table';
|
|
6
|
+
export type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
|
7
|
+
export type InlineFormat = 'bold' | 'italic' | 'underline' | 'strikethrough' | 'code' | 'link' | 'textColor' | 'highlight';
|
|
8
|
+
export type CalloutType = 'info' | 'warning' | 'error' | 'success' | 'note';
|
|
9
|
+
export interface BlockDefinition {
|
|
10
|
+
/** Unique name for the block */
|
|
11
|
+
name: BlockType;
|
|
12
|
+
/** HTML tag this block renders to */
|
|
13
|
+
tag: string;
|
|
14
|
+
/** Whether the content is editable */
|
|
15
|
+
editable: boolean;
|
|
16
|
+
/** Allowed child types */
|
|
17
|
+
allowedChildren: ('text' | 'inline' | 'block')[];
|
|
18
|
+
/** Default CSS class */
|
|
19
|
+
className?: string;
|
|
20
|
+
/** Icon name for UI */
|
|
21
|
+
icon?: string;
|
|
22
|
+
/** Display label */
|
|
23
|
+
label: string;
|
|
24
|
+
/** Keyboard shortcut */
|
|
25
|
+
shortcut?: string;
|
|
26
|
+
/** Create the DOM element */
|
|
27
|
+
create: (data?: any) => HTMLElement;
|
|
28
|
+
/** Get block data from element */
|
|
29
|
+
getData: (element: HTMLElement) => any;
|
|
30
|
+
/** Update element with new data */
|
|
31
|
+
update: (element: HTMLElement, data: any) => void;
|
|
32
|
+
}
|
|
33
|
+
export interface BaseBlockData {
|
|
34
|
+
id: string;
|
|
35
|
+
type: BlockType;
|
|
36
|
+
className?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface ParagraphData extends BaseBlockData {
|
|
39
|
+
type: 'paragraph';
|
|
40
|
+
content: string;
|
|
41
|
+
align?: 'left' | 'center' | 'right' | 'justify';
|
|
42
|
+
}
|
|
43
|
+
export interface HeadingData extends BaseBlockData {
|
|
44
|
+
type: 'heading';
|
|
45
|
+
level: HeadingLevel;
|
|
46
|
+
content: string;
|
|
47
|
+
align?: 'left' | 'center' | 'right';
|
|
48
|
+
}
|
|
49
|
+
export interface ListData extends BaseBlockData {
|
|
50
|
+
type: 'bulletList' | 'numberedList' | 'checkList';
|
|
51
|
+
items: ListItem[];
|
|
52
|
+
}
|
|
53
|
+
export interface ListItem {
|
|
54
|
+
id: string;
|
|
55
|
+
content: string;
|
|
56
|
+
checked?: boolean;
|
|
57
|
+
children?: ListItem[];
|
|
58
|
+
}
|
|
59
|
+
export interface QuoteData extends BaseBlockData {
|
|
60
|
+
type: 'quote';
|
|
61
|
+
content: string;
|
|
62
|
+
citation?: string;
|
|
63
|
+
}
|
|
64
|
+
export interface CodeData extends BaseBlockData {
|
|
65
|
+
type: 'code';
|
|
66
|
+
content: string;
|
|
67
|
+
language?: string;
|
|
68
|
+
}
|
|
69
|
+
export interface ImageData extends BaseBlockData {
|
|
70
|
+
type: 'image';
|
|
71
|
+
src: string;
|
|
72
|
+
alt?: string;
|
|
73
|
+
caption?: string;
|
|
74
|
+
width?: number | string;
|
|
75
|
+
height?: number | string;
|
|
76
|
+
align?: 'left' | 'center' | 'right';
|
|
77
|
+
}
|
|
78
|
+
export interface VideoData extends BaseBlockData {
|
|
79
|
+
type: 'video';
|
|
80
|
+
src: string;
|
|
81
|
+
poster?: string;
|
|
82
|
+
caption?: string;
|
|
83
|
+
width?: number | string;
|
|
84
|
+
height?: number | string;
|
|
85
|
+
}
|
|
86
|
+
export interface DividerData extends BaseBlockData {
|
|
87
|
+
type: 'divider';
|
|
88
|
+
style?: 'solid' | 'dashed' | 'dotted';
|
|
89
|
+
}
|
|
90
|
+
export interface CalloutData extends BaseBlockData {
|
|
91
|
+
type: 'callout';
|
|
92
|
+
calloutType: CalloutType;
|
|
93
|
+
title?: string;
|
|
94
|
+
content: string;
|
|
95
|
+
}
|
|
96
|
+
export interface AccordionData extends BaseBlockData {
|
|
97
|
+
type: 'accordion';
|
|
98
|
+
title: string;
|
|
99
|
+
content: string;
|
|
100
|
+
open?: boolean;
|
|
101
|
+
}
|
|
102
|
+
export interface TableData extends BaseBlockData {
|
|
103
|
+
type: 'table';
|
|
104
|
+
rows: TableRow[];
|
|
105
|
+
hasHeader?: boolean;
|
|
106
|
+
}
|
|
107
|
+
export interface TableRow {
|
|
108
|
+
cells: TableCell[];
|
|
109
|
+
}
|
|
110
|
+
export interface TableCell {
|
|
111
|
+
content: string;
|
|
112
|
+
align?: 'left' | 'center' | 'right';
|
|
113
|
+
colSpan?: number;
|
|
114
|
+
rowSpan?: number;
|
|
115
|
+
}
|
|
116
|
+
export type BlockData = ParagraphData | HeadingData | ListData | QuoteData | CodeData | ImageData | VideoData | DividerData | CalloutData | AccordionData | TableData;
|
|
117
|
+
export interface EditorConfig {
|
|
118
|
+
/** Container element or selector */
|
|
119
|
+
container?: HTMLElement | string;
|
|
120
|
+
/** Initial HTML content */
|
|
121
|
+
initialContent?: string;
|
|
122
|
+
/** Enabled block types */
|
|
123
|
+
blocks?: BlockType[];
|
|
124
|
+
/** Enabled inline formats */
|
|
125
|
+
inlineFormats?: InlineFormat[];
|
|
126
|
+
/** Placeholder text */
|
|
127
|
+
placeholder?: string;
|
|
128
|
+
/** Enable autosave */
|
|
129
|
+
autosave?: boolean;
|
|
130
|
+
/** Autosave interval in ms */
|
|
131
|
+
autosaveInterval?: number;
|
|
132
|
+
/** Max undo history */
|
|
133
|
+
maxHistory?: number;
|
|
134
|
+
/** CSS class prefix */
|
|
135
|
+
classPrefix?: string;
|
|
136
|
+
/** Enable spell check */
|
|
137
|
+
spellCheck?: boolean;
|
|
138
|
+
/** Read-only mode */
|
|
139
|
+
readOnly?: boolean;
|
|
140
|
+
/** Custom class mappings */
|
|
141
|
+
classMap?: Partial<Record<BlockType, string>>;
|
|
142
|
+
/** Callbacks */
|
|
143
|
+
onChange?: (html: string) => void;
|
|
144
|
+
onSave?: (html: string) => void;
|
|
145
|
+
onFocus?: () => void;
|
|
146
|
+
onBlur?: () => void;
|
|
147
|
+
onBlockAdd?: (block: HTMLElement) => void;
|
|
148
|
+
onBlockRemove?: (block: HTMLElement) => void;
|
|
149
|
+
onBlockMove?: (block: HTMLElement, fromIndex: number, toIndex: number) => void;
|
|
150
|
+
}
|
|
151
|
+
export interface EditorState {
|
|
152
|
+
/** All block elements */
|
|
153
|
+
blocks: HTMLElement[];
|
|
154
|
+
/** Currently focused block */
|
|
155
|
+
activeBlock: HTMLElement | null;
|
|
156
|
+
/** Current selection */
|
|
157
|
+
selection: Selection | null;
|
|
158
|
+
/** Undo stack */
|
|
159
|
+
undoStack: string[];
|
|
160
|
+
/** Redo stack */
|
|
161
|
+
redoStack: string[];
|
|
162
|
+
/** Current word count */
|
|
163
|
+
wordCount: number;
|
|
164
|
+
/** Current character count */
|
|
165
|
+
charCount: number;
|
|
166
|
+
/** Is content modified */
|
|
167
|
+
isDirty: boolean;
|
|
168
|
+
}
|
|
169
|
+
export type CommandName = 'insertBlock' | 'deleteBlock' | 'moveBlockUp' | 'moveBlockDown' | 'duplicateBlock' | 'transformBlock' | 'toggleFormat' | 'setAlignment' | 'indent' | 'outdent' | 'undo' | 'redo' | 'selectAll' | 'insertLink' | 'insertImage';
|
|
170
|
+
export interface Command {
|
|
171
|
+
name: CommandName;
|
|
172
|
+
execute: (editor: EditorInstance, ...args: unknown[]) => void;
|
|
173
|
+
canExecute?: (editor: EditorInstance) => boolean;
|
|
174
|
+
shortcut?: string;
|
|
175
|
+
}
|
|
176
|
+
export interface EditorInstance {
|
|
177
|
+
/** Root container element */
|
|
178
|
+
container: HTMLElement;
|
|
179
|
+
/** Editor config */
|
|
180
|
+
config: EditorConfig;
|
|
181
|
+
/** Current state */
|
|
182
|
+
state: EditorState;
|
|
183
|
+
/** Selection version for tracking changes (used for toolbar updates) */
|
|
184
|
+
selectionVersion?: number;
|
|
185
|
+
/** Get HTML output */
|
|
186
|
+
getHTML: () => string;
|
|
187
|
+
/** Set HTML content */
|
|
188
|
+
setHTML: (html: string) => void;
|
|
189
|
+
/** Get plain text */
|
|
190
|
+
getText: () => string;
|
|
191
|
+
/** Insert a block */
|
|
192
|
+
insertBlock: (type: BlockType, data?: Partial<BlockData>, position?: number) => HTMLElement | null;
|
|
193
|
+
/** Delete a block */
|
|
194
|
+
deleteBlock: (block: HTMLElement) => void;
|
|
195
|
+
/** Move a block */
|
|
196
|
+
moveBlock: (block: HTMLElement, direction: 'up' | 'down') => void;
|
|
197
|
+
/** Transform block type */
|
|
198
|
+
transformBlock: (block: HTMLElement, newType: BlockType, data?: Record<string, any>) => HTMLElement;
|
|
199
|
+
/** Apply inline format */
|
|
200
|
+
toggleFormat: (format: InlineFormat) => void;
|
|
201
|
+
/** Check if format is active */
|
|
202
|
+
isFormatActive: (format: InlineFormat) => boolean;
|
|
203
|
+
/** Undo last action */
|
|
204
|
+
undo: () => void;
|
|
205
|
+
/** Redo last undone action */
|
|
206
|
+
redo: () => void;
|
|
207
|
+
/** Focus the editor */
|
|
208
|
+
focus: () => void;
|
|
209
|
+
/** Blur the editor */
|
|
210
|
+
blur: () => void;
|
|
211
|
+
/** Destroy the editor */
|
|
212
|
+
destroy: () => void;
|
|
213
|
+
/** Register a custom block */
|
|
214
|
+
registerBlock: (definition: BlockDefinition) => void;
|
|
215
|
+
/** Register a command */
|
|
216
|
+
registerCommand: (command: Command) => void;
|
|
217
|
+
/** Execute a command */
|
|
218
|
+
executeCommand: (name: CommandName, ...args: unknown[]) => void;
|
|
219
|
+
}
|
|
220
|
+
export interface EditorEvents {
|
|
221
|
+
change: {
|
|
222
|
+
html: string;
|
|
223
|
+
};
|
|
224
|
+
focus: {
|
|
225
|
+
block: HTMLElement | null;
|
|
226
|
+
};
|
|
227
|
+
blur: {
|
|
228
|
+
block: HTMLElement | null;
|
|
229
|
+
};
|
|
230
|
+
blockAdd: {
|
|
231
|
+
block: HTMLElement;
|
|
232
|
+
index: number;
|
|
233
|
+
};
|
|
234
|
+
blockRemove: {
|
|
235
|
+
block: HTMLElement;
|
|
236
|
+
index: number;
|
|
237
|
+
};
|
|
238
|
+
blockMove: {
|
|
239
|
+
block: HTMLElement;
|
|
240
|
+
fromIndex: number;
|
|
241
|
+
toIndex: number;
|
|
242
|
+
};
|
|
243
|
+
selectionChange: {
|
|
244
|
+
selection: Selection | null;
|
|
245
|
+
};
|
|
246
|
+
input: {
|
|
247
|
+
block: HTMLElement;
|
|
248
|
+
};
|
|
249
|
+
paste: {
|
|
250
|
+
data: DataTransfer;
|
|
251
|
+
block: HTMLElement;
|
|
252
|
+
};
|
|
253
|
+
keydown: {
|
|
254
|
+
event: KeyboardEvent;
|
|
255
|
+
block: HTMLElement;
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
export interface Point {
|
|
259
|
+
x: number;
|
|
260
|
+
y: number;
|
|
261
|
+
}
|
|
262
|
+
export interface Rect {
|
|
263
|
+
top: number;
|
|
264
|
+
left: number;
|
|
265
|
+
width: number;
|
|
266
|
+
height: number;
|
|
267
|
+
bottom: number;
|
|
268
|
+
right: number;
|
|
269
|
+
}
|
|
270
|
+
export interface DragState {
|
|
271
|
+
isDragging: boolean;
|
|
272
|
+
draggedBlock: HTMLElement | null;
|
|
273
|
+
dropTarget: HTMLElement | null;
|
|
274
|
+
dropPosition: 'before' | 'after' | null;
|
|
275
|
+
}
|
|
276
|
+
export interface ContentBlocksEditorProps {
|
|
277
|
+
/** Initial HTML content */
|
|
278
|
+
initialContent?: string;
|
|
279
|
+
/** Enabled blocks */
|
|
280
|
+
blocks?: BlockType[];
|
|
281
|
+
/** Enabled inline formats */
|
|
282
|
+
inlineFormats?: InlineFormat[];
|
|
283
|
+
/** Placeholder text */
|
|
284
|
+
placeholder?: string;
|
|
285
|
+
/** Read-only mode */
|
|
286
|
+
readOnly?: boolean;
|
|
287
|
+
/** CSS class prefix */
|
|
288
|
+
classPrefix?: string;
|
|
289
|
+
/** Custom class name for container */
|
|
290
|
+
className?: string;
|
|
291
|
+
/** Custom styles */
|
|
292
|
+
style?: React.CSSProperties;
|
|
293
|
+
/** Show toolbar */
|
|
294
|
+
showToolbar?: boolean;
|
|
295
|
+
/** Toolbar position */
|
|
296
|
+
toolbarPosition?: 'top' | 'bottom' | 'floating';
|
|
297
|
+
/** Enable dark mode */
|
|
298
|
+
darkMode?: boolean;
|
|
299
|
+
/** Autofocus on mount */
|
|
300
|
+
autoFocus?: boolean;
|
|
301
|
+
/** Spell check */
|
|
302
|
+
spellCheck?: boolean;
|
|
303
|
+
/** Content change callback */
|
|
304
|
+
onChange?: (html: string) => void;
|
|
305
|
+
/** Save callback */
|
|
306
|
+
onSave?: (html: string) => void;
|
|
307
|
+
/** Focus callback */
|
|
308
|
+
onFocus?: () => void;
|
|
309
|
+
/** Blur callback */
|
|
310
|
+
onBlur?: () => void;
|
|
311
|
+
/** Editor ready callback */
|
|
312
|
+
onReady?: (editor: EditorInstance) => void;
|
|
313
|
+
}
|
|
314
|
+
export interface ToolbarProps {
|
|
315
|
+
editor: EditorInstance;
|
|
316
|
+
className?: string;
|
|
317
|
+
position?: 'top' | 'bottom' | 'floating';
|
|
318
|
+
darkMode?: boolean;
|
|
319
|
+
}
|
|
320
|
+
export interface BlockMenuProps {
|
|
321
|
+
editor: EditorInstance;
|
|
322
|
+
position: Point;
|
|
323
|
+
onSelect: (type: BlockType, data?: Record<string, any>) => void;
|
|
324
|
+
onClose: () => void;
|
|
325
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drag & Drop - Block reordering functionality
|
|
3
|
+
*/
|
|
4
|
+
export interface DragState {
|
|
5
|
+
isDragging: boolean;
|
|
6
|
+
draggedElement: HTMLElement | null;
|
|
7
|
+
placeholder: HTMLElement | null;
|
|
8
|
+
startY: number;
|
|
9
|
+
currentY: number;
|
|
10
|
+
scrollInterval: number | null;
|
|
11
|
+
}
|
|
12
|
+
export interface DragDropOptions {
|
|
13
|
+
container: HTMLElement;
|
|
14
|
+
handleSelector?: string;
|
|
15
|
+
onDragStart?: (element: HTMLElement) => void;
|
|
16
|
+
onDragMove?: (element: HTMLElement, targetElement: HTMLElement | null, position: 'before' | 'after') => void;
|
|
17
|
+
onDragEnd?: (element: HTMLElement, newIndex: number) => void;
|
|
18
|
+
onDragCancel?: () => void;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Initialize drag and drop for blocks
|
|
22
|
+
*/
|
|
23
|
+
export declare function initDragDrop(options: DragDropOptions): () => void;
|
|
24
|
+
/**
|
|
25
|
+
* Create a drag handle element
|
|
26
|
+
*/
|
|
27
|
+
export declare function createDragHandle(): HTMLElement;
|
|
28
|
+
/**
|
|
29
|
+
* Check if drag and drop is supported
|
|
30
|
+
*/
|
|
31
|
+
export declare function isDragDropSupported(): boolean;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Type, Heading1, Heading2, Heading3, List, ListOrdered, Quote, Code, Image, Minus, ChevronDown, Table, Bold, Italic, Underline, Link, AlignLeft, AlignCenter, AlignRight, Undo, Redo, Trash2, Plus, GripVertical, MoreHorizontal, X, Check, Settings, Download, LucideIcon } from 'lucide-react';
|
|
2
|
+
|
|
3
|
+
export type IconName = 'paragraph' | 'heading1' | 'heading2' | 'heading3' | 'heading4' | 'heading5' | 'heading6' | 'list' | 'listOrdered' | 'checkList' | 'quote' | 'code' | 'image' | 'video' | 'divider' | 'callout' | 'accordion' | 'table' | 'bold' | 'italic' | 'underline' | 'strikethrough' | 'link' | 'unlink' | 'highlight' | 'textColor' | 'alignLeft' | 'alignCenter' | 'alignRight' | 'alignJustify' | 'undo' | 'redo' | 'copy' | 'cut' | 'paste' | 'delete' | 'plus' | 'drag' | 'more' | 'chevronUp' | 'chevronDown' | 'moveUp' | 'moveDown' | 'maximize' | 'close' | 'check' | 'search' | 'settings' | 'sun' | 'moon' | 'document' | 'codeFile' | 'download' | 'upload' | 'externalLink' | 'info' | 'warning' | 'error' | 'success' | 'file' | 'indent' | 'outdent' | 'clear' | 'columns' | 'rows' | 'eraser';
|
|
4
|
+
/**
|
|
5
|
+
* Icon map - maps icon names to Lucide components
|
|
6
|
+
*/
|
|
7
|
+
export declare const iconMap: Record<IconName, LucideIcon>;
|
|
8
|
+
/**
|
|
9
|
+
* Get icon component by name
|
|
10
|
+
*/
|
|
11
|
+
export declare function getIcon(name: IconName): LucideIcon;
|
|
12
|
+
export { Type, Heading1, Heading2, Heading3, Bold, Italic, Underline, Link, Code, List, ListOrdered, Quote, Image, Table, Minus, Plus, GripVertical, Undo, Redo, AlignLeft, AlignCenter, AlignRight, Trash2, Settings, Download, ChevronDown, X, Check, MoreHorizontal, };
|