@overlap/rte 0.1.2 → 0.1.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/src/styles.css DELETED
@@ -1,638 +0,0 @@
1
- /* CSS Variables für Theme-Support */
2
- :root {
3
- /* Colors */
4
- --rte-border-color: #e5e7eb;
5
- --rte-border-radius: 8px;
6
- --rte-toolbar-bg: #f9fafb;
7
- --rte-button-hover-bg: #f3f4f6;
8
- --rte-button-active-bg: #e5e7eb;
9
- --rte-content-bg: #ffffff;
10
- --rte-text-color: #111827;
11
- --rte-text-secondary: #6b7280;
12
- --rte-primary-color: #3b82f6;
13
- --rte-primary-hover: #2563eb;
14
-
15
- /* Spacing */
16
- --rte-padding-xs: 4px;
17
- --rte-padding-sm: 6px;
18
- --rte-padding-md: 8px;
19
- --rte-padding-lg: 12px;
20
- --rte-padding-xl: 16px;
21
- --rte-padding-2xl: 20px;
22
-
23
- /* Shadows */
24
- --rte-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
25
- --rte-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
26
- --rte-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
27
- --rte-shadow-popover: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
28
-
29
- /* Typography */
30
- --rte-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
31
- --rte-line-height: 1.6;
32
- }
33
-
34
- /* Container */
35
- .rte-container {
36
- display: flex;
37
- flex-direction: column;
38
- border: 1px solid var(--rte-border-color);
39
- border-radius: var(--rte-border-radius);
40
- background: var(--rte-content-bg);
41
- font-family: var(--rte-font-family);
42
- box-shadow: var(--rte-shadow-sm);
43
- }
44
-
45
- /* Toolbar */
46
- .rte-toolbar {
47
- display: flex;
48
- justify-content: space-between;
49
- align-items: center;
50
- gap: var(--rte-padding-md);
51
- padding: var(--rte-padding-md);
52
- background: var(--rte-toolbar-bg);
53
- border-bottom: 1px solid var(--rte-border-color);
54
- border-top-left-radius: var(--rte-border-radius);
55
- border-top-right-radius: var(--rte-border-radius);
56
- }
57
-
58
- /* Sticky Toolbar */
59
- .rte-toolbar-sticky {
60
- position: sticky;
61
- top: 0;
62
- z-index: 10;
63
- box-shadow: var(--rte-shadow-sm);
64
- transition: box-shadow 0.2s ease;
65
- }
66
-
67
- .rte-toolbar-left {
68
- display: flex;
69
- gap: var(--rte-padding-xs);
70
- flex-wrap: wrap;
71
- align-items: center;
72
- flex: 1;
73
- }
74
-
75
- .rte-toolbar-right {
76
- display: flex;
77
- gap: var(--rte-padding-xs);
78
- align-items: center;
79
- flex-shrink: 0;
80
- }
81
-
82
- /* Toolbar Divider */
83
- .rte-toolbar-divider {
84
- width: 1px;
85
- height: 24px;
86
- background: var(--rte-border-color);
87
- margin: 0 var(--rte-padding-sm);
88
- flex-shrink: 0;
89
- }
90
-
91
- /* Toolbar Buttons - Ghost/Subtle Style */
92
- .rte-toolbar-button {
93
- display: flex;
94
- align-items: center;
95
- justify-content: center;
96
- min-width: 32px;
97
- height: 32px;
98
- padding: 0 var(--rte-padding-md);
99
- border: none;
100
- background: transparent;
101
- border-radius: 6px;
102
- cursor: pointer;
103
- color: var(--rte-text-color);
104
- transition: all 0.15s ease;
105
- font-size: 14px;
106
- }
107
-
108
- .rte-toolbar-button:hover:not(:disabled) {
109
- background: var(--rte-button-hover-bg);
110
- color: var(--rte-text-color);
111
- }
112
-
113
- .rte-toolbar-button:active:not(:disabled) {
114
- background: var(--rte-button-active-bg);
115
- transform: scale(0.98);
116
- }
117
-
118
- .rte-toolbar-button:disabled {
119
- opacity: 0.4;
120
- cursor: not-allowed;
121
- }
122
-
123
- .rte-toolbar-button-active {
124
- background: var(--rte-button-active-bg);
125
- color: var(--rte-primary-color);
126
- }
127
-
128
- .rte-toolbar-button-active:hover:not(:disabled) {
129
- background: var(--rte-button-hover-bg);
130
- color: var(--rte-primary-hover);
131
- }
132
-
133
- /* Editor Content Area */
134
- .rte-editor {
135
- min-height: 200px;
136
- padding: var(--rte-padding-2xl);
137
- outline: none;
138
- line-height: var(--rte-line-height);
139
- color: var(--rte-text-color);
140
- overflow-y: auto;
141
- background: var(--rte-content-bg);
142
- border-bottom-left-radius: var(--rte-border-radius);
143
- border-bottom-right-radius: var(--rte-border-radius);
144
- }
145
-
146
- .rte-editor:focus {
147
- outline: none;
148
- }
149
-
150
- .rte-editor:empty:before {
151
- content: attr(data-placeholder);
152
- color: var(--rte-text-secondary);
153
- pointer-events: none;
154
- }
155
-
156
- /* Typography in Editor */
157
- .rte-editor p {
158
- margin: 0 0 var(--rte-padding-lg) 0;
159
- }
160
-
161
- .rte-editor p:last-child {
162
- margin-bottom: 0;
163
- }
164
-
165
- .rte-editor h1 {
166
- font-size: 2em;
167
- font-weight: 700;
168
- margin: 0 0 var(--rte-padding-lg) 0;
169
- line-height: 1.2;
170
- }
171
-
172
- .rte-editor h2 {
173
- font-size: 1.5em;
174
- font-weight: 600;
175
- margin: 0 0 var(--rte-padding-lg) 0;
176
- line-height: 1.3;
177
- }
178
-
179
- .rte-editor h3 {
180
- font-size: 1.25em;
181
- font-weight: 600;
182
- margin: 0 0 var(--rte-padding-lg) 0;
183
- line-height: 1.4;
184
- }
185
-
186
- .rte-editor h4 {
187
- font-size: 1.1em;
188
- font-weight: 600;
189
- margin: 0 0 var(--rte-padding-lg) 0;
190
- line-height: 1.4;
191
- }
192
-
193
- .rte-editor h5 {
194
- font-size: 1em;
195
- font-weight: 600;
196
- margin: 0 0 var(--rte-padding-lg) 0;
197
- line-height: 1.5;
198
- }
199
-
200
- .rte-editor h6 {
201
- font-size: 0.9em;
202
- font-weight: 600;
203
- margin: 0 0 var(--rte-padding-lg) 0;
204
- line-height: 1.5;
205
- }
206
-
207
- .rte-editor blockquote {
208
- margin: 0 0 var(--rte-padding-lg) 0;
209
- padding: var(--rte-padding-lg) var(--rte-padding-xl);
210
- border-left: 3px solid var(--rte-border-color);
211
- background: var(--rte-toolbar-bg);
212
- color: var(--rte-text-secondary);
213
- border-radius: 0 var(--rte-border-radius) var(--rte-border-radius) 0;
214
- }
215
-
216
- .rte-editor ul,
217
- .rte-editor ol {
218
- margin: 0 0 var(--rte-padding-lg) 0;
219
- padding-left: var(--rte-padding-2xl);
220
- }
221
-
222
- .rte-editor li {
223
- margin: var(--rte-padding-sm) 0;
224
- }
225
-
226
- .rte-editor a {
227
- color: var(--rte-primary-color);
228
- text-decoration: underline;
229
- text-underline-offset: 2px;
230
- transition: color 0.15s ease;
231
- }
232
-
233
- .rte-editor a:hover {
234
- color: var(--rte-primary-hover);
235
- }
236
-
237
- .rte-editor strong,
238
- .rte-editor b {
239
- font-weight: 600;
240
- }
241
-
242
- .rte-editor em,
243
- .rte-editor i {
244
- font-style: italic;
245
- }
246
-
247
- .rte-editor u {
248
- text-decoration: underline;
249
- text-underline-offset: 2px;
250
- }
251
-
252
- /* Dropdown Styles */
253
- .rte-dropdown {
254
- position: relative;
255
- display: inline-block;
256
- }
257
-
258
- .rte-dropdown-button {
259
- min-width: 32px;
260
- width: auto;
261
- padding: 0 var(--rte-padding-md);
262
- }
263
-
264
- .rte-dropdown-button-has-value {
265
- padding: 0 var(--rte-padding-lg);
266
- }
267
-
268
- .rte-dropdown-value {
269
- margin-left: var(--rte-padding-sm);
270
- font-size: 12px;
271
- font-weight: 500;
272
- color: var(--rte-text-color);
273
- }
274
-
275
- /* Dropdown Menu - Modern Popover */
276
- .rte-dropdown-menu {
277
- position: absolute;
278
- top: calc(100% + 4px);
279
- left: 0;
280
- background: var(--rte-content-bg);
281
- border: 1px solid var(--rte-border-color);
282
- border-radius: var(--rte-border-radius);
283
- box-shadow: var(--rte-shadow-popover);
284
- z-index: 1000;
285
- min-width: 180px;
286
- max-height: 320px;
287
- overflow-y: auto;
288
- padding: var(--rte-padding-sm);
289
- margin-top: var(--rte-padding-xs);
290
- }
291
-
292
- .rte-dropdown-item {
293
- display: flex;
294
- align-items: center;
295
- gap: var(--rte-padding-md);
296
- width: 100%;
297
- padding: var(--rte-padding-md) var(--rte-padding-lg);
298
- border: none;
299
- background: transparent;
300
- text-align: left;
301
- cursor: pointer;
302
- color: var(--rte-text-color);
303
- font-size: 14px;
304
- border-radius: 6px;
305
- transition: all 0.15s ease;
306
- font-family: var(--rte-font-family);
307
- position: relative;
308
- }
309
-
310
- .rte-dropdown-item:hover {
311
- background: var(--rte-button-hover-bg);
312
- }
313
-
314
- .rte-dropdown-item-active {
315
- background: var(--rte-button-hover-bg);
316
- color: var(--rte-text-color);
317
- font-weight: 500;
318
- }
319
-
320
- .rte-dropdown-item-active::before {
321
- content: '';
322
- position: absolute;
323
- left: 0;
324
- top: 0;
325
- bottom: 0;
326
- width: 3px;
327
- background: var(--rte-primary-color);
328
- border-radius: 0 2px 2px 0;
329
- }
330
-
331
- .rte-dropdown-item-active .rte-dropdown-heading-preview,
332
- .rte-dropdown-item-active > span:last-child {
333
- color: var(--rte-primary-color);
334
- font-weight: 600;
335
- }
336
-
337
- .rte-dropdown-color-preview.active {
338
- border: 2px solid var(--rte-primary-color);
339
- box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
340
- }
341
-
342
- /* Color Preview in Dropdown */
343
- .rte-dropdown-color-preview {
344
- display: inline-block;
345
- width: 20px;
346
- height: 20px;
347
- border-radius: 4px;
348
- border: 1px solid var(--rte-border-color);
349
- flex-shrink: 0;
350
- box-shadow: var(--rte-shadow-sm);
351
- }
352
-
353
- /* Font Size Preview in Dropdown */
354
- .rte-dropdown-fontsize-preview {
355
- display: inline-block;
356
- min-width: 40px;
357
- text-align: right;
358
- font-weight: 500;
359
- color: var(--rte-text-secondary);
360
- }
361
-
362
- /* Heading Preview in Dropdown */
363
- .rte-dropdown-heading-preview {
364
- display: inline-flex;
365
- align-items: center;
366
- min-width: 60px;
367
- font-weight: 600;
368
- color: var(--rte-text-color);
369
- font-size: 14px;
370
- line-height: 1.2;
371
- }
372
-
373
- .rte-dropdown-heading-preview.h1 {
374
- font-size: 18px;
375
- font-weight: 700;
376
- }
377
-
378
- .rte-dropdown-heading-preview.h2 {
379
- font-size: 16px;
380
- font-weight: 600;
381
- }
382
-
383
- .rte-dropdown-heading-preview.h3 {
384
- font-size: 15px;
385
- font-weight: 600;
386
- }
387
-
388
- .rte-dropdown-heading-preview.h4 {
389
- font-size: 14px;
390
- font-weight: 600;
391
- }
392
-
393
- .rte-dropdown-heading-preview.h5 {
394
- font-size: 13px;
395
- font-weight: 600;
396
- }
397
-
398
- .rte-dropdown-heading-preview.h6 {
399
- font-size: 12px;
400
- font-weight: 600;
401
- }
402
-
403
- .rte-dropdown-heading-preview.p {
404
- font-size: 14px;
405
- font-weight: 400;
406
- }
407
-
408
- /* Image Styles in Editor */
409
- .rte-editor img {
410
- max-width: 100%;
411
- height: auto;
412
- display: block;
413
- margin: var(--rte-padding-xl) 0;
414
- border-radius: var(--rte-border-radius);
415
- box-shadow: var(--rte-shadow-sm);
416
- }
417
-
418
- .rte-editor img[data-uploading="true"] {
419
- opacity: 0.6;
420
- position: relative;
421
- }
422
-
423
- .rte-editor img[data-uploading="true"]::after {
424
- content: '';
425
- position: absolute;
426
- top: 50%;
427
- left: 50%;
428
- transform: translate(-50%, -50%);
429
- width: 24px;
430
- height: 24px;
431
- border: 2px solid var(--rte-primary-color);
432
- border-top-color: transparent;
433
- border-radius: 50%;
434
- animation: spin 0.8s linear infinite;
435
- }
436
-
437
- @keyframes spin {
438
- to {
439
- transform: translate(-50%, -50%) rotate(360deg);
440
- }
441
- }
442
-
443
- /* Image Modal */
444
- .rte-image-modal-overlay {
445
- position: fixed;
446
- top: 0;
447
- left: 0;
448
- right: 0;
449
- bottom: 0;
450
- background: rgba(0, 0, 0, 0.5);
451
- display: flex;
452
- align-items: center;
453
- justify-content: center;
454
- z-index: 10000;
455
- padding: var(--rte-padding-xl);
456
- }
457
-
458
- .rte-image-modal {
459
- background: var(--rte-content-bg);
460
- border-radius: var(--rte-border-radius);
461
- box-shadow: var(--rte-shadow-lg);
462
- width: 100%;
463
- max-width: 500px;
464
- max-height: 90vh;
465
- overflow-y: auto;
466
- display: flex;
467
- flex-direction: column;
468
- }
469
-
470
- .rte-image-modal-header {
471
- display: flex;
472
- align-items: center;
473
- justify-content: space-between;
474
- padding: var(--rte-padding-xl);
475
- border-bottom: 1px solid var(--rte-border-color);
476
- }
477
-
478
- .rte-image-modal-header h3 {
479
- margin: 0;
480
- font-size: 18px;
481
- font-weight: 600;
482
- color: var(--rte-text-color);
483
- }
484
-
485
- .rte-image-modal-close {
486
- display: flex;
487
- align-items: center;
488
- justify-content: center;
489
- width: 32px;
490
- height: 32px;
491
- border: none;
492
- background: transparent;
493
- border-radius: 6px;
494
- cursor: pointer;
495
- color: var(--rte-text-secondary);
496
- transition: all 0.15s ease;
497
- }
498
-
499
- .rte-image-modal-close:hover {
500
- background: var(--rte-button-hover-bg);
501
- color: var(--rte-text-color);
502
- }
503
-
504
- .rte-image-modal-content {
505
- padding: var(--rte-padding-xl);
506
- display: flex;
507
- flex-direction: column;
508
- gap: var(--rte-padding-xl);
509
- }
510
-
511
- .rte-image-upload-section {
512
- display: flex;
513
- flex-direction: column;
514
- gap: var(--rte-padding-md);
515
- }
516
-
517
- .rte-image-upload-label {
518
- display: block;
519
- cursor: pointer;
520
- }
521
-
522
- .rte-image-upload-button {
523
- display: flex;
524
- align-items: center;
525
- justify-content: center;
526
- gap: var(--rte-padding-md);
527
- padding: var(--rte-padding-xl);
528
- border: 2px dashed var(--rte-border-color);
529
- border-radius: var(--rte-border-radius);
530
- background: var(--rte-toolbar-bg);
531
- color: var(--rte-text-color);
532
- transition: all 0.15s ease;
533
- font-size: 14px;
534
- font-weight: 500;
535
- }
536
-
537
- .rte-image-upload-button:hover {
538
- border-color: var(--rte-primary-color);
539
- background: var(--rte-button-hover-bg);
540
- }
541
-
542
- .rte-image-url-section,
543
- .rte-image-alt-section {
544
- display: flex;
545
- flex-direction: column;
546
- gap: var(--rte-padding-sm);
547
- }
548
-
549
- .rte-image-url-section label,
550
- .rte-image-alt-section label {
551
- font-size: 14px;
552
- font-weight: 500;
553
- color: var(--rte-text-color);
554
- }
555
-
556
- .rte-image-url-input,
557
- .rte-image-alt-input {
558
- width: 100%;
559
- padding: var(--rte-padding-md) var(--rte-padding-lg);
560
- border: 1px solid var(--rte-border-color);
561
- border-radius: 6px;
562
- font-size: 14px;
563
- font-family: var(--rte-font-family);
564
- color: var(--rte-text-color);
565
- background: var(--rte-content-bg);
566
- transition: all 0.15s ease;
567
- }
568
-
569
- .rte-image-url-input:focus,
570
- .rte-image-alt-input:focus {
571
- outline: none;
572
- border-color: var(--rte-primary-color);
573
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
574
- }
575
-
576
- .rte-image-preview {
577
- display: flex;
578
- justify-content: center;
579
- padding: var(--rte-padding-lg);
580
- background: var(--rte-toolbar-bg);
581
- border-radius: var(--rte-border-radius);
582
- }
583
-
584
- .rte-image-preview img {
585
- max-width: 100%;
586
- max-height: 200px;
587
- border-radius: var(--rte-border-radius);
588
- box-shadow: var(--rte-shadow-sm);
589
- }
590
-
591
- .rte-image-modal-footer {
592
- display: flex;
593
- align-items: center;
594
- justify-content: flex-end;
595
- gap: var(--rte-padding-md);
596
- padding: var(--rte-padding-xl);
597
- border-top: 1px solid var(--rte-border-color);
598
- }
599
-
600
- .rte-image-modal-cancel,
601
- .rte-image-modal-insert {
602
- padding: var(--rte-padding-md) var(--rte-padding-xl);
603
- border: none;
604
- border-radius: 6px;
605
- font-size: 14px;
606
- font-weight: 500;
607
- cursor: pointer;
608
- transition: all 0.15s ease;
609
- font-family: var(--rte-font-family);
610
- }
611
-
612
- .rte-image-modal-cancel {
613
- background: transparent;
614
- color: var(--rte-text-secondary);
615
- }
616
-
617
- .rte-image-modal-cancel:hover {
618
- background: var(--rte-button-hover-bg);
619
- color: var(--rte-text-color);
620
- }
621
-
622
- .rte-image-modal-insert {
623
- background: var(--rte-primary-color);
624
- color: white;
625
- }
626
-
627
- .rte-image-modal-insert:hover:not(:disabled) {
628
- background: var(--rte-primary-hover);
629
- }
630
-
631
- .rte-image-modal-insert:disabled {
632
- opacity: 0.5;
633
- cursor: not-allowed;
634
- }
635
-
636
- .rte-spin {
637
- animation: spin 0.8s linear infinite;
638
- }
package/src/types.ts DELETED
@@ -1,95 +0,0 @@
1
- export interface EditorNode {
2
- type: string;
3
- children?: EditorNode[];
4
- text?: string;
5
- attributes?: Record<string, string>;
6
- }
7
-
8
- export interface EditorContent {
9
- blocks: EditorNode[];
10
- }
11
-
12
- export interface Plugin {
13
- name: string;
14
- type: 'inline' | 'block' | 'command';
15
- command?: string;
16
- renderButton?: (props: ButtonProps & { [key: string]: any }) => React.ReactElement;
17
- execute?: (editor: EditorAPI, value?: string) => void;
18
- isActive?: (editor: EditorAPI) => boolean;
19
- canExecute?: (editor: EditorAPI) => boolean;
20
- // State Reflection: Gibt den aktuellen Wert zurück (z.B. "22" für fontSize, "#ff0000" für color, "h1" für heading)
21
- getCurrentValue?: (editor: EditorAPI) => string | undefined;
22
- }
23
-
24
- export interface ButtonProps {
25
- isActive: boolean;
26
- onClick: () => void;
27
- disabled?: boolean;
28
- icon?: string;
29
- label?: string;
30
- }
31
-
32
- export interface EditorAPI {
33
- executeCommand: (command: string, value?: string) => boolean;
34
- getSelection: () => Selection | null;
35
- getContent: () => EditorContent;
36
- setContent: (content: EditorContent) => void;
37
- insertBlock: (type: string, attributes?: Record<string, string>) => void;
38
- insertInline: (type: string, attributes?: Record<string, string>) => void;
39
- undo: () => void;
40
- redo: () => void;
41
- canUndo: () => boolean;
42
- canRedo: () => boolean;
43
- // HTML Import & Export
44
- importHtml: (htmlString: string) => EditorContent;
45
- exportHtml: () => string;
46
- // Clear Formatting
47
- clearFormatting: () => void;
48
- clearTextColor: () => void;
49
- clearBackgroundColor: () => void;
50
- clearFontSize: () => void;
51
- clearLinks: () => void;
52
- // List Indent
53
- indentListItem: () => void;
54
- outdentListItem: () => void;
55
- }
56
-
57
- export interface CustomRenderer {
58
- renderNode?: (node: EditorNode, children: React.ReactNode) => React.ReactElement | null;
59
- renderMark?: (mark: string, attributes: Record<string, string>, children: React.ReactNode) => React.ReactElement | null;
60
- }
61
-
62
- export interface EditorProps {
63
- initialContent?: EditorContent;
64
- onChange?: (content: EditorContent) => void;
65
- plugins?: Plugin[];
66
- placeholder?: string;
67
- className?: string;
68
- toolbarClassName?: string;
69
- editorClassName?: string;
70
- // Link System
71
- customLinkComponent?: React.ComponentType<{ href: string; children: React.ReactNode; [key: string]: any }>;
72
- // Font Size System
73
- fontSizes?: number[];
74
- // Color System
75
- colors?: string[];
76
- // Headings System
77
- headings?: string[];
78
- customHeadingRenderer?: (level: string, children: React.ReactNode) => React.ReactElement;
79
- // Custom Renderer
80
- customRenderer?: CustomRenderer;
81
- // Editor API Callback
82
- onEditorAPIReady?: (api: EditorAPI) => void;
83
- // Theme Configuration
84
- theme?: {
85
- borderColor?: string;
86
- borderRadius?: number;
87
- toolbarBg?: string;
88
- buttonHoverBg?: string;
89
- contentBg?: string;
90
- primaryColor?: string;
91
- };
92
- // Image Upload
93
- onImageUpload?: (file: File) => Promise<string>;
94
- }
95
-