overtype 1.1.8 → 1.2.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/README.md +66 -6
- package/dist/overtype.cjs +3676 -0
- package/dist/overtype.cjs.map +7 -0
- package/dist/overtype.esm.js +576 -24
- package/dist/overtype.esm.js.map +2 -2
- package/dist/overtype.js +576 -25
- package/dist/overtype.js.map +2 -2
- package/dist/overtype.min.js +341 -40
- package/package.json +17 -3
- package/src/overtype.js +53 -2
- package/src/parser.js +176 -7
- package/src/styles.js +314 -14
- package/src/toolbar.js +140 -4
package/src/styles.js
CHANGED
|
@@ -41,11 +41,44 @@ export function generateStyles(options = {}) {
|
|
|
41
41
|
|
|
42
42
|
return `
|
|
43
43
|
/* OverType Editor Styles */
|
|
44
|
+
|
|
45
|
+
/* Middle-ground CSS Reset - Prevent parent styles from leaking in */
|
|
46
|
+
.overtype-container * {
|
|
47
|
+
/* Box model - these commonly leak */
|
|
48
|
+
margin: 0 !important;
|
|
49
|
+
padding: 0 !important;
|
|
50
|
+
border: 0 !important;
|
|
51
|
+
|
|
52
|
+
/* Layout - these can break our layout */
|
|
53
|
+
/* Don't reset position - it breaks dropdowns */
|
|
54
|
+
float: none !important;
|
|
55
|
+
clear: none !important;
|
|
56
|
+
|
|
57
|
+
/* Typography - only reset decorative aspects */
|
|
58
|
+
text-decoration: none !important;
|
|
59
|
+
text-transform: none !important;
|
|
60
|
+
letter-spacing: normal !important;
|
|
61
|
+
|
|
62
|
+
/* Visual effects that can interfere */
|
|
63
|
+
box-shadow: none !important;
|
|
64
|
+
text-shadow: none !important;
|
|
65
|
+
|
|
66
|
+
/* Ensure box-sizing is consistent */
|
|
67
|
+
box-sizing: border-box !important;
|
|
68
|
+
|
|
69
|
+
/* Keep inheritance for these */
|
|
70
|
+
/* font-family, color, line-height, font-size - inherit */
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Container base styles after reset */
|
|
44
74
|
.overtype-container {
|
|
45
75
|
display: grid !important;
|
|
46
76
|
grid-template-rows: auto 1fr auto !important;
|
|
47
77
|
width: 100% !important;
|
|
48
78
|
height: 100% !important;
|
|
79
|
+
position: relative !important; /* Override reset - needed for absolute children */
|
|
80
|
+
overflow: visible !important; /* Allow dropdown to overflow container */
|
|
81
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
|
|
49
82
|
${themeVars ? `
|
|
50
83
|
/* Theme Variables */
|
|
51
84
|
${themeVars}` : ''}
|
|
@@ -64,20 +97,21 @@ export function generateStyles(options = {}) {
|
|
|
64
97
|
}
|
|
65
98
|
|
|
66
99
|
.overtype-wrapper {
|
|
67
|
-
position: relative !important;
|
|
100
|
+
position: relative !important; /* Override reset - needed for absolute children */
|
|
68
101
|
width: 100% !important;
|
|
69
102
|
height: 100% !important; /* Take full height of grid cell */
|
|
70
103
|
min-height: 60px !important; /* Minimum usable height */
|
|
71
104
|
overflow: hidden !important;
|
|
72
105
|
background: var(--bg-secondary, #ffffff) !important;
|
|
73
106
|
grid-row: 2 !important; /* Always second row in grid */
|
|
107
|
+
z-index: 1; /* Below toolbar and dropdown */
|
|
74
108
|
}
|
|
75
109
|
|
|
76
110
|
/* Critical alignment styles - must be identical for both layers */
|
|
77
111
|
.overtype-wrapper .overtype-input,
|
|
78
112
|
.overtype-wrapper .overtype-preview {
|
|
79
113
|
/* Positioning - must be identical */
|
|
80
|
-
position: absolute !important;
|
|
114
|
+
position: absolute !important; /* Override reset - required for overlay */
|
|
81
115
|
top: 0 !important;
|
|
82
116
|
left: 0 !important;
|
|
83
117
|
width: 100% !important;
|
|
@@ -144,7 +178,7 @@ export function generateStyles(options = {}) {
|
|
|
144
178
|
/* Overflow */
|
|
145
179
|
overflow-y: auto !important;
|
|
146
180
|
overflow-x: auto !important;
|
|
147
|
-
overscroll-behavior
|
|
181
|
+
/* overscroll-behavior removed to allow scroll-through to parent */
|
|
148
182
|
scrollbar-width: auto !important;
|
|
149
183
|
scrollbar-gutter: auto !important;
|
|
150
184
|
|
|
@@ -232,6 +266,45 @@ export function generateStyles(options = {}) {
|
|
|
232
266
|
color: var(--h3, #3d8a51) !important;
|
|
233
267
|
}
|
|
234
268
|
|
|
269
|
+
/* Semantic headers - flatten in edit mode */
|
|
270
|
+
.overtype-wrapper .overtype-preview h1,
|
|
271
|
+
.overtype-wrapper .overtype-preview h2,
|
|
272
|
+
.overtype-wrapper .overtype-preview h3 {
|
|
273
|
+
font-size: inherit !important;
|
|
274
|
+
font-weight: bold !important;
|
|
275
|
+
margin: 0 !important;
|
|
276
|
+
padding: 0 !important;
|
|
277
|
+
display: inline !important;
|
|
278
|
+
line-height: inherit !important;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/* Header colors for semantic headers */
|
|
282
|
+
.overtype-wrapper .overtype-preview h1 {
|
|
283
|
+
color: var(--h1, #f95738) !important;
|
|
284
|
+
}
|
|
285
|
+
.overtype-wrapper .overtype-preview h2 {
|
|
286
|
+
color: var(--h2, #ee964b) !important;
|
|
287
|
+
}
|
|
288
|
+
.overtype-wrapper .overtype-preview h3 {
|
|
289
|
+
color: var(--h3, #3d8a51) !important;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/* Lists - remove styling in edit mode */
|
|
293
|
+
.overtype-wrapper .overtype-preview ul,
|
|
294
|
+
.overtype-wrapper .overtype-preview ol {
|
|
295
|
+
list-style: none !important;
|
|
296
|
+
margin: 0 !important;
|
|
297
|
+
padding: 0 !important;
|
|
298
|
+
display: block !important; /* Lists need to be block for line breaks */
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.overtype-wrapper .overtype-preview li {
|
|
302
|
+
display: block !important; /* Each item on its own line */
|
|
303
|
+
margin: 0 !important;
|
|
304
|
+
padding: 0 !important;
|
|
305
|
+
/* Don't set list-style here - let ul/ol control it */
|
|
306
|
+
}
|
|
307
|
+
|
|
235
308
|
/* Bold text */
|
|
236
309
|
.overtype-wrapper .overtype-preview strong {
|
|
237
310
|
color: var(--strong, #ee964b) !important;
|
|
@@ -258,17 +331,23 @@ export function generateStyles(options = {}) {
|
|
|
258
331
|
font-weight: normal !important;
|
|
259
332
|
}
|
|
260
333
|
|
|
261
|
-
/* Code blocks */
|
|
334
|
+
/* Code blocks - consolidated pre blocks */
|
|
262
335
|
.overtype-wrapper .overtype-preview pre {
|
|
263
|
-
background: #1e1e1e !important;
|
|
264
336
|
padding: 0 !important;
|
|
265
337
|
margin: 0 !important;
|
|
266
338
|
border-radius: 4px !important;
|
|
267
339
|
overflow-x: auto !important;
|
|
268
340
|
}
|
|
341
|
+
|
|
342
|
+
/* Code block styling in normal mode - yellow background */
|
|
343
|
+
.overtype-wrapper .overtype-preview pre.code-block {
|
|
344
|
+
background: var(--code-bg, rgba(244, 211, 94, 0.4)) !important;
|
|
345
|
+
}
|
|
269
346
|
|
|
347
|
+
/* Code inside pre blocks - remove background */
|
|
270
348
|
.overtype-wrapper .overtype-preview pre code {
|
|
271
|
-
background:
|
|
349
|
+
background: transparent !important;
|
|
350
|
+
color: var(--code, #0d3b66) !important;
|
|
272
351
|
}
|
|
273
352
|
|
|
274
353
|
/* Blockquotes */
|
|
@@ -299,11 +378,6 @@ export function generateStyles(options = {}) {
|
|
|
299
378
|
padding: 0 !important;
|
|
300
379
|
}
|
|
301
380
|
|
|
302
|
-
.overtype-wrapper .overtype-preview li {
|
|
303
|
-
margin: 0 !important;
|
|
304
|
-
padding: 0 !important;
|
|
305
|
-
list-style: none !important;
|
|
306
|
-
}
|
|
307
381
|
|
|
308
382
|
/* Horizontal rules */
|
|
309
383
|
.overtype-wrapper .overtype-preview hr {
|
|
@@ -402,13 +476,31 @@ export function generateStyles(options = {}) {
|
|
|
402
476
|
display: flex;
|
|
403
477
|
align-items: center;
|
|
404
478
|
gap: 4px;
|
|
405
|
-
padding: 8px;
|
|
406
|
-
background: var(--toolbar-bg, var(--bg-primary, #f8f9fa));
|
|
407
|
-
overflow-x: auto;
|
|
479
|
+
padding: 8px !important; /* Override reset */
|
|
480
|
+
background: var(--toolbar-bg, var(--bg-primary, #f8f9fa)) !important; /* Override reset */
|
|
481
|
+
overflow-x: auto !important; /* Allow horizontal scrolling */
|
|
482
|
+
overflow-y: hidden !important; /* Hide vertical overflow */
|
|
408
483
|
-webkit-overflow-scrolling: touch;
|
|
409
484
|
flex-shrink: 0;
|
|
410
485
|
height: auto !important;
|
|
411
486
|
grid-row: 1 !important; /* Always first row in grid */
|
|
487
|
+
position: relative !important; /* Override reset */
|
|
488
|
+
z-index: 100; /* Ensure toolbar is above wrapper */
|
|
489
|
+
scrollbar-width: thin; /* Thin scrollbar on Firefox */
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/* Thin scrollbar styling */
|
|
493
|
+
.overtype-toolbar::-webkit-scrollbar {
|
|
494
|
+
height: 4px;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
.overtype-toolbar::-webkit-scrollbar-track {
|
|
498
|
+
background: transparent;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
.overtype-toolbar::-webkit-scrollbar-thumb {
|
|
502
|
+
background: rgba(0, 0, 0, 0.2);
|
|
503
|
+
border-radius: 2px;
|
|
412
504
|
}
|
|
413
505
|
|
|
414
506
|
.overtype-toolbar-button {
|
|
@@ -498,6 +590,214 @@ export function generateStyles(options = {}) {
|
|
|
498
590
|
color: transparent !important;
|
|
499
591
|
}
|
|
500
592
|
|
|
593
|
+
/* Dropdown menu styles */
|
|
594
|
+
.overtype-toolbar-button {
|
|
595
|
+
position: relative !important; /* Override reset - needed for dropdown */
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
.overtype-toolbar-button.dropdown-active {
|
|
599
|
+
background: var(--toolbar-active, var(--hover-bg, #f0f0f0));
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
.overtype-dropdown-menu {
|
|
603
|
+
position: fixed !important; /* Fixed positioning relative to viewport */
|
|
604
|
+
background: var(--bg-secondary, white) !important; /* Override reset */
|
|
605
|
+
border: 1px solid var(--border, #e0e0e0) !important; /* Override reset */
|
|
606
|
+
border-radius: 6px;
|
|
607
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.1) !important; /* Override reset */
|
|
608
|
+
z-index: 10000; /* Very high z-index to ensure visibility */
|
|
609
|
+
min-width: 150px;
|
|
610
|
+
padding: 4px 0 !important; /* Override reset */
|
|
611
|
+
/* Position will be set via JavaScript based on button position */
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
.overtype-dropdown-item {
|
|
615
|
+
display: flex;
|
|
616
|
+
align-items: center;
|
|
617
|
+
width: 100%;
|
|
618
|
+
padding: 8px 12px;
|
|
619
|
+
border: none;
|
|
620
|
+
background: none;
|
|
621
|
+
text-align: left;
|
|
622
|
+
cursor: pointer;
|
|
623
|
+
font-size: 14px;
|
|
624
|
+
color: var(--text, #333);
|
|
625
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
.overtype-dropdown-item:hover {
|
|
629
|
+
background: var(--hover-bg, #f0f0f0);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
.overtype-dropdown-item.active {
|
|
633
|
+
font-weight: 600;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
.overtype-dropdown-check {
|
|
637
|
+
width: 16px;
|
|
638
|
+
margin-right: 8px;
|
|
639
|
+
color: var(--h1, #007bff);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/* Preview mode styles */
|
|
643
|
+
.overtype-container.preview-mode .overtype-input {
|
|
644
|
+
display: none !important;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
.overtype-container.preview-mode .overtype-preview {
|
|
648
|
+
pointer-events: auto !important;
|
|
649
|
+
user-select: text !important;
|
|
650
|
+
cursor: text !important;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/* Hide syntax markers in preview mode */
|
|
654
|
+
.overtype-container.preview-mode .syntax-marker {
|
|
655
|
+
display: none !important;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/* Hide URL part of links in preview mode - extra specificity */
|
|
659
|
+
.overtype-container.preview-mode .syntax-marker.url-part,
|
|
660
|
+
.overtype-container.preview-mode .url-part {
|
|
661
|
+
display: none !important;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/* Hide all syntax markers inside links too */
|
|
665
|
+
.overtype-container.preview-mode a .syntax-marker {
|
|
666
|
+
display: none !important;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/* Headers - restore proper sizing in preview mode */
|
|
670
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview h1,
|
|
671
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview h2,
|
|
672
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview h3 {
|
|
673
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
|
|
674
|
+
font-weight: 600 !important;
|
|
675
|
+
margin: 0 !important;
|
|
676
|
+
display: block !important;
|
|
677
|
+
color: inherit !important; /* Use parent text color */
|
|
678
|
+
line-height: 1 !important; /* Tight line height for headings */
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview h1 {
|
|
682
|
+
font-size: 2em !important;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview h2 {
|
|
686
|
+
font-size: 1.5em !important;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview h3 {
|
|
690
|
+
font-size: 1.17em !important;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/* Lists - restore list styling in preview mode */
|
|
694
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview ul {
|
|
695
|
+
display: block !important;
|
|
696
|
+
list-style: disc !important;
|
|
697
|
+
padding-left: 2em !important;
|
|
698
|
+
margin: 1em 0 !important;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview ol {
|
|
702
|
+
display: block !important;
|
|
703
|
+
list-style: decimal !important;
|
|
704
|
+
padding-left: 2em !important;
|
|
705
|
+
margin: 1em 0 !important;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview li {
|
|
709
|
+
display: list-item !important;
|
|
710
|
+
margin: 0 !important;
|
|
711
|
+
padding: 0 !important;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/* Links - make clickable in preview mode */
|
|
715
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview a {
|
|
716
|
+
pointer-events: auto !important;
|
|
717
|
+
cursor: pointer !important;
|
|
718
|
+
color: var(--link, #0066cc) !important;
|
|
719
|
+
text-decoration: underline !important;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/* Code blocks - proper pre/code styling in preview mode */
|
|
723
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview pre.code-block {
|
|
724
|
+
background: #2d2d2d !important;
|
|
725
|
+
color: #f8f8f2 !important;
|
|
726
|
+
padding: 1.2em !important;
|
|
727
|
+
border-radius: 3px !important;
|
|
728
|
+
overflow-x: auto !important;
|
|
729
|
+
margin: 0 !important;
|
|
730
|
+
display: block !important;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/* Cave theme code block background in preview mode */
|
|
734
|
+
.overtype-container[data-theme="cave"].preview-mode .overtype-wrapper .overtype-preview pre.code-block {
|
|
735
|
+
background: #11171F !important;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview pre.code-block code {
|
|
739
|
+
background: transparent !important;
|
|
740
|
+
color: inherit !important;
|
|
741
|
+
padding: 0 !important;
|
|
742
|
+
font-family: ${fontFamily} !important;
|
|
743
|
+
font-size: 0.9em !important;
|
|
744
|
+
line-height: 1.4 !important;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/* Hide old code block lines and fences in preview mode */
|
|
748
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview .code-block-line {
|
|
749
|
+
display: none !important;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview .code-fence {
|
|
753
|
+
display: none !important;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/* Blockquotes - enhanced styling in preview mode */
|
|
757
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview .blockquote {
|
|
758
|
+
display: block !important;
|
|
759
|
+
border-left: 4px solid var(--blockquote, #ddd) !important;
|
|
760
|
+
padding-left: 1em !important;
|
|
761
|
+
margin: 1em 0 !important;
|
|
762
|
+
font-style: italic !important;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/* Typography improvements in preview mode */
|
|
766
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview {
|
|
767
|
+
font-family: Georgia, 'Times New Roman', serif !important;
|
|
768
|
+
font-size: 16px !important;
|
|
769
|
+
line-height: 1.8 !important;
|
|
770
|
+
color: var(--text, #333) !important; /* Consistent text color */
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/* Inline code in preview mode - keep monospace */
|
|
774
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview code {
|
|
775
|
+
font-family: ${fontFamily} !important;
|
|
776
|
+
font-size: 0.9em !important;
|
|
777
|
+
background: rgba(135, 131, 120, 0.15) !important;
|
|
778
|
+
padding: 0.2em 0.4em !important;
|
|
779
|
+
border-radius: 3px !important;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
/* Strong and em elements in preview mode */
|
|
783
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview strong {
|
|
784
|
+
font-weight: 700 !important;
|
|
785
|
+
color: inherit !important; /* Use parent text color */
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview em {
|
|
789
|
+
font-style: italic !important;
|
|
790
|
+
color: inherit !important; /* Use parent text color */
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
/* HR in preview mode */
|
|
794
|
+
.overtype-container.preview-mode .overtype-wrapper .overtype-preview .hr-marker {
|
|
795
|
+
display: block !important;
|
|
796
|
+
border-top: 2px solid var(--hr, #ddd) !important;
|
|
797
|
+
text-indent: -9999px !important;
|
|
798
|
+
height: 2px !important;
|
|
799
|
+
}
|
|
800
|
+
|
|
501
801
|
${mobileStyles}
|
|
502
802
|
`;
|
|
503
803
|
}
|
package/src/toolbar.js
CHANGED
|
@@ -41,7 +41,7 @@ export class Toolbar {
|
|
|
41
41
|
{ name: 'orderedList', icon: icons.orderedListIcon, title: 'Numbered List', action: 'toggleNumberedList' },
|
|
42
42
|
{ name: 'taskList', icon: icons.taskListIcon, title: 'Task List', action: 'toggleTaskList' },
|
|
43
43
|
{ separator: true },
|
|
44
|
-
{ name: '
|
|
44
|
+
{ name: 'viewMode', icon: icons.eyeIcon, title: 'View mode', action: 'toggle-view-menu', hasDropdown: true }
|
|
45
45
|
];
|
|
46
46
|
|
|
47
47
|
// Create buttons
|
|
@@ -80,10 +80,19 @@ export class Toolbar {
|
|
|
80
80
|
button.setAttribute('data-action', config.action);
|
|
81
81
|
button.innerHTML = config.icon;
|
|
82
82
|
|
|
83
|
+
// Add dropdown if needed
|
|
84
|
+
if (config.hasDropdown) {
|
|
85
|
+
button.classList.add('has-dropdown');
|
|
86
|
+
// Store reference for dropdown
|
|
87
|
+
if (config.name === 'viewMode') {
|
|
88
|
+
this.viewModeButton = button;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
83
92
|
// Add click handler
|
|
84
93
|
button.addEventListener('click', (e) => {
|
|
85
94
|
e.preventDefault();
|
|
86
|
-
this.handleAction(config.action);
|
|
95
|
+
this.handleAction(config.action, button);
|
|
87
96
|
});
|
|
88
97
|
|
|
89
98
|
return button;
|
|
@@ -92,11 +101,17 @@ export class Toolbar {
|
|
|
92
101
|
/**
|
|
93
102
|
* Handle toolbar button actions
|
|
94
103
|
*/
|
|
95
|
-
async handleAction(action) {
|
|
104
|
+
async handleAction(action, button) {
|
|
96
105
|
const textarea = this.editor.textarea;
|
|
97
106
|
if (!textarea) return;
|
|
98
107
|
|
|
99
|
-
//
|
|
108
|
+
// Handle dropdown toggle
|
|
109
|
+
if (action === 'toggle-view-menu') {
|
|
110
|
+
this.toggleViewDropdown(button);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Focus textarea for other actions
|
|
100
115
|
textarea.focus();
|
|
101
116
|
|
|
102
117
|
try {
|
|
@@ -210,11 +225,132 @@ export class Toolbar {
|
|
|
210
225
|
}
|
|
211
226
|
}
|
|
212
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Toggle view mode dropdown menu
|
|
230
|
+
*/
|
|
231
|
+
toggleViewDropdown(button) {
|
|
232
|
+
// Close any existing dropdown
|
|
233
|
+
const existingDropdown = document.querySelector('.overtype-dropdown-menu');
|
|
234
|
+
if (existingDropdown) {
|
|
235
|
+
existingDropdown.remove();
|
|
236
|
+
button.classList.remove('dropdown-active');
|
|
237
|
+
document.removeEventListener('click', this.handleDocumentClick);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Create dropdown menu
|
|
242
|
+
const dropdown = this.createViewDropdown();
|
|
243
|
+
|
|
244
|
+
// Position dropdown relative to button
|
|
245
|
+
const rect = button.getBoundingClientRect();
|
|
246
|
+
dropdown.style.top = `${rect.bottom + 4}px`;
|
|
247
|
+
dropdown.style.left = `${rect.left}px`;
|
|
248
|
+
|
|
249
|
+
// Append to body instead of button
|
|
250
|
+
document.body.appendChild(dropdown);
|
|
251
|
+
button.classList.add('dropdown-active');
|
|
252
|
+
|
|
253
|
+
// Store reference for document click handler
|
|
254
|
+
this.handleDocumentClick = (e) => {
|
|
255
|
+
if (!button.contains(e.target) && !dropdown.contains(e.target)) {
|
|
256
|
+
dropdown.remove();
|
|
257
|
+
button.classList.remove('dropdown-active');
|
|
258
|
+
document.removeEventListener('click', this.handleDocumentClick);
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
// Close on click outside
|
|
263
|
+
setTimeout(() => {
|
|
264
|
+
document.addEventListener('click', this.handleDocumentClick);
|
|
265
|
+
}, 0);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Create view mode dropdown menu
|
|
270
|
+
*/
|
|
271
|
+
createViewDropdown() {
|
|
272
|
+
const dropdown = document.createElement('div');
|
|
273
|
+
dropdown.className = 'overtype-dropdown-menu';
|
|
274
|
+
|
|
275
|
+
// Determine current mode
|
|
276
|
+
const isPlain = this.editor.container.classList.contains('plain-mode');
|
|
277
|
+
const isPreview = this.editor.container.classList.contains('preview-mode');
|
|
278
|
+
const currentMode = isPreview ? 'preview' : (isPlain ? 'plain' : 'normal');
|
|
279
|
+
|
|
280
|
+
// Create menu items
|
|
281
|
+
const modes = [
|
|
282
|
+
{ id: 'normal', label: 'Normal Edit', icon: '✓' },
|
|
283
|
+
{ id: 'plain', label: 'Plain Textarea', icon: '✓' },
|
|
284
|
+
{ id: 'preview', label: 'Preview Mode', icon: '✓' }
|
|
285
|
+
];
|
|
286
|
+
|
|
287
|
+
modes.forEach(mode => {
|
|
288
|
+
const item = document.createElement('button');
|
|
289
|
+
item.className = 'overtype-dropdown-item';
|
|
290
|
+
item.type = 'button';
|
|
291
|
+
|
|
292
|
+
const check = document.createElement('span');
|
|
293
|
+
check.className = 'overtype-dropdown-check';
|
|
294
|
+
check.textContent = currentMode === mode.id ? mode.icon : '';
|
|
295
|
+
|
|
296
|
+
const label = document.createElement('span');
|
|
297
|
+
label.textContent = mode.label;
|
|
298
|
+
|
|
299
|
+
item.appendChild(check);
|
|
300
|
+
item.appendChild(label);
|
|
301
|
+
|
|
302
|
+
if (currentMode === mode.id) {
|
|
303
|
+
item.classList.add('active');
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
item.addEventListener('click', (e) => {
|
|
307
|
+
e.stopPropagation();
|
|
308
|
+
this.setViewMode(mode.id);
|
|
309
|
+
dropdown.remove();
|
|
310
|
+
this.viewModeButton.classList.remove('dropdown-active');
|
|
311
|
+
document.removeEventListener('click', this.handleDocumentClick);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
dropdown.appendChild(item);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
return dropdown;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Set view mode
|
|
322
|
+
*/
|
|
323
|
+
setViewMode(mode) {
|
|
324
|
+
// Clear all mode classes
|
|
325
|
+
this.editor.container.classList.remove('plain-mode', 'preview-mode');
|
|
326
|
+
|
|
327
|
+
switch(mode) {
|
|
328
|
+
case 'plain':
|
|
329
|
+
this.editor.showPlainTextarea(true);
|
|
330
|
+
break;
|
|
331
|
+
case 'preview':
|
|
332
|
+
this.editor.showPreviewMode(true);
|
|
333
|
+
break;
|
|
334
|
+
case 'normal':
|
|
335
|
+
default:
|
|
336
|
+
// Normal edit mode
|
|
337
|
+
this.editor.showPlainTextarea(false);
|
|
338
|
+
if (typeof this.editor.showPreviewMode === 'function') {
|
|
339
|
+
this.editor.showPreviewMode(false);
|
|
340
|
+
}
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
213
345
|
/**
|
|
214
346
|
* Destroy toolbar
|
|
215
347
|
*/
|
|
216
348
|
destroy() {
|
|
217
349
|
if (this.container) {
|
|
350
|
+
// Clean up event listeners
|
|
351
|
+
if (this.handleDocumentClick) {
|
|
352
|
+
document.removeEventListener('click', this.handleDocumentClick);
|
|
353
|
+
}
|
|
218
354
|
this.container.remove();
|
|
219
355
|
this.container = null;
|
|
220
356
|
this.buttons = {};
|