overtype 2.1.0 → 2.1.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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * OverType v2.0.6
2
+ * OverType v2.1.0
3
3
  * A lightweight markdown editor library with perfect WYSIWYG alignment
4
4
  * @license MIT
5
5
  * @author David Miranda
@@ -733,1968 +733,1926 @@ __publicField(MarkdownParser, "LIST_PATTERNS", {
733
733
  checkbox: /^(\s*)-\s+\[([ x])\]\s+(.*)$/
734
734
  });
735
735
 
736
- // node_modules/markdown-actions/dist/markdown-actions.esm.js
737
- var __defProp2 = Object.defineProperty;
738
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
739
- var __hasOwnProp = Object.prototype.hasOwnProperty;
740
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
741
- var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
742
- var __spreadValues = (a, b) => {
743
- for (var prop in b || (b = {}))
744
- if (__hasOwnProp.call(b, prop))
745
- __defNormalProp2(a, prop, b[prop]);
746
- if (__getOwnPropSymbols)
747
- for (var prop of __getOwnPropSymbols(b)) {
748
- if (__propIsEnum.call(b, prop))
749
- __defNormalProp2(a, prop, b[prop]);
750
- }
751
- return a;
752
- };
753
- var FORMATS = {
754
- bold: {
755
- prefix: "**",
756
- suffix: "**",
757
- trimFirst: true
758
- },
759
- italic: {
760
- prefix: "_",
761
- suffix: "_",
762
- trimFirst: true
763
- },
764
- code: {
765
- prefix: "`",
766
- suffix: "`",
767
- blockPrefix: "```",
768
- blockSuffix: "```"
769
- },
770
- link: {
771
- prefix: "[",
772
- suffix: "](url)",
773
- replaceNext: "url",
774
- scanFor: "https?://"
775
- },
776
- bulletList: {
777
- prefix: "- ",
778
- multiline: true,
779
- unorderedList: true
780
- },
781
- numberedList: {
782
- prefix: "1. ",
783
- multiline: true,
784
- orderedList: true
785
- },
786
- quote: {
787
- prefix: "> ",
788
- multiline: true,
789
- surroundWithNewlines: true
790
- },
791
- taskList: {
792
- prefix: "- [ ] ",
793
- multiline: true,
794
- surroundWithNewlines: true
795
- },
796
- header1: { prefix: "# " },
797
- header2: { prefix: "## " },
798
- header3: { prefix: "### " },
799
- header4: { prefix: "#### " },
800
- header5: { prefix: "##### " },
801
- header6: { prefix: "###### " }
802
- };
803
- function getDefaultStyle() {
804
- return {
805
- prefix: "",
806
- suffix: "",
807
- blockPrefix: "",
808
- blockSuffix: "",
809
- multiline: false,
810
- replaceNext: "",
811
- prefixSpace: false,
812
- scanFor: "",
813
- surroundWithNewlines: false,
814
- orderedList: false,
815
- unorderedList: false,
816
- trimFirst: false
817
- };
818
- }
819
- function mergeWithDefaults(format) {
820
- return __spreadValues(__spreadValues({}, getDefaultStyle()), format);
821
- }
822
- var debugMode = false;
823
- function getDebugMode() {
824
- return debugMode;
825
- }
826
- function debugLog(funcName, message, data) {
827
- if (!debugMode)
828
- return;
829
- console.group(`\u{1F50D} ${funcName}`);
830
- console.log(message);
831
- if (data) {
832
- console.log("Data:", data);
833
- }
834
- console.groupEnd();
835
- }
836
- function debugSelection(textarea, label) {
837
- if (!debugMode)
838
- return;
839
- const selected = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
840
- console.group(`\u{1F4CD} Selection: ${label}`);
841
- console.log("Position:", `${textarea.selectionStart}-${textarea.selectionEnd}`);
842
- console.log("Selected text:", JSON.stringify(selected));
843
- console.log("Length:", selected.length);
844
- const before = textarea.value.slice(Math.max(0, textarea.selectionStart - 10), textarea.selectionStart);
845
- const after = textarea.value.slice(textarea.selectionEnd, Math.min(textarea.value.length, textarea.selectionEnd + 10));
846
- console.log("Context:", JSON.stringify(before) + "[SELECTION]" + JSON.stringify(after));
847
- console.groupEnd();
848
- }
849
- function debugResult(result) {
850
- if (!debugMode)
851
- return;
852
- console.group("\u{1F4DD} Result");
853
- console.log("Text to insert:", JSON.stringify(result.text));
854
- console.log("New selection:", `${result.selectionStart}-${result.selectionEnd}`);
855
- console.groupEnd();
856
- }
857
- var canInsertText = null;
858
- function insertText(textarea, { text, selectionStart, selectionEnd }) {
859
- const debugMode2 = getDebugMode();
860
- if (debugMode2) {
861
- console.group("\u{1F527} insertText");
862
- console.log("Current selection:", `${textarea.selectionStart}-${textarea.selectionEnd}`);
863
- console.log("Text to insert:", JSON.stringify(text));
864
- console.log("New selection to set:", selectionStart, "-", selectionEnd);
865
- }
866
- textarea.focus();
867
- const originalSelectionStart = textarea.selectionStart;
868
- const originalSelectionEnd = textarea.selectionEnd;
869
- const before = textarea.value.slice(0, originalSelectionStart);
870
- const after = textarea.value.slice(originalSelectionEnd);
871
- if (debugMode2) {
872
- console.log("Before text (last 20):", JSON.stringify(before.slice(-20)));
873
- console.log("After text (first 20):", JSON.stringify(after.slice(0, 20)));
874
- console.log("Selected text being replaced:", JSON.stringify(textarea.value.slice(originalSelectionStart, originalSelectionEnd)));
875
- }
876
- const originalValue = textarea.value;
877
- const hasSelection = originalSelectionStart !== originalSelectionEnd;
878
- if (canInsertText === null || canInsertText === true) {
879
- textarea.contentEditable = "true";
880
- try {
881
- canInsertText = document.execCommand("insertText", false, text);
882
- if (debugMode2)
883
- console.log("execCommand returned:", canInsertText, "for text with", text.split("\n").length, "lines");
884
- } catch (error) {
885
- canInsertText = false;
886
- if (debugMode2)
887
- console.log("execCommand threw error:", error);
888
- }
889
- textarea.contentEditable = "false";
890
- }
891
- if (debugMode2) {
892
- console.log("canInsertText before:", canInsertText);
893
- console.log("execCommand result:", canInsertText);
736
+ // src/shortcuts.js
737
+ var ShortcutsManager = class {
738
+ constructor(editor) {
739
+ this.editor = editor;
894
740
  }
895
- if (canInsertText) {
896
- const expectedValue = before + text + after;
897
- const actualValue = textarea.value;
898
- if (debugMode2) {
899
- console.log("Expected length:", expectedValue.length);
900
- console.log("Actual length:", actualValue.length);
741
+ /**
742
+ * Handle keydown events - called by OverType
743
+ * @param {KeyboardEvent} event - The keyboard event
744
+ * @returns {boolean} Whether the event was handled
745
+ */
746
+ handleKeydown(event) {
747
+ const isMac = navigator.platform.toLowerCase().includes("mac");
748
+ const modKey = isMac ? event.metaKey : event.ctrlKey;
749
+ if (!modKey)
750
+ return false;
751
+ let actionId = null;
752
+ switch (event.key.toLowerCase()) {
753
+ case "b":
754
+ if (!event.shiftKey)
755
+ actionId = "toggleBold";
756
+ break;
757
+ case "i":
758
+ if (!event.shiftKey)
759
+ actionId = "toggleItalic";
760
+ break;
761
+ case "k":
762
+ if (!event.shiftKey)
763
+ actionId = "insertLink";
764
+ break;
765
+ case "7":
766
+ if (event.shiftKey)
767
+ actionId = "toggleNumberedList";
768
+ break;
769
+ case "8":
770
+ if (event.shiftKey)
771
+ actionId = "toggleBulletList";
772
+ break;
901
773
  }
902
- if (actualValue !== expectedValue) {
903
- if (debugMode2) {
904
- console.log("execCommand changed the value but not as expected");
905
- console.log("Expected:", JSON.stringify(expectedValue.slice(0, 100)));
906
- console.log("Actual:", JSON.stringify(actualValue.slice(0, 100)));
907
- }
774
+ if (actionId) {
775
+ event.preventDefault();
776
+ this.editor.performAction(actionId, event);
777
+ return true;
908
778
  }
779
+ return false;
909
780
  }
910
- if (!canInsertText) {
911
- if (debugMode2)
912
- console.log("Using manual insertion");
913
- if (textarea.value === originalValue) {
914
- if (debugMode2)
915
- console.log("Value unchanged, doing manual replacement");
916
- try {
917
- document.execCommand("ms-beginUndoUnit");
918
- } catch (e) {
919
- }
920
- textarea.value = before + text + after;
921
- try {
922
- document.execCommand("ms-endUndoUnit");
923
- } catch (e) {
924
- }
925
- textarea.dispatchEvent(new CustomEvent("input", { bubbles: true, cancelable: true }));
926
- } else {
927
- if (debugMode2)
928
- console.log("Value was changed by execCommand, skipping manual insertion");
929
- }
781
+ /**
782
+ * Cleanup
783
+ */
784
+ destroy() {
930
785
  }
931
- if (debugMode2)
932
- console.log("Setting selection range:", selectionStart, selectionEnd);
933
- if (selectionStart != null && selectionEnd != null) {
934
- textarea.setSelectionRange(selectionStart, selectionEnd);
935
- } else {
936
- textarea.setSelectionRange(originalSelectionStart, textarea.selectionEnd);
786
+ };
787
+
788
+ // src/themes.js
789
+ var solar = {
790
+ name: "solar",
791
+ colors: {
792
+ bgPrimary: "#faf0ca",
793
+ // Lemon Chiffon - main background
794
+ bgSecondary: "#ffffff",
795
+ // White - editor background
796
+ text: "#0d3b66",
797
+ // Yale Blue - main text
798
+ textPrimary: "#0d3b66",
799
+ // Yale Blue - primary text (same as text)
800
+ textSecondary: "#5a7a9b",
801
+ // Muted blue - secondary text
802
+ h1: "#f95738",
803
+ // Tomato - h1 headers
804
+ h2: "#ee964b",
805
+ // Sandy Brown - h2 headers
806
+ h3: "#3d8a51",
807
+ // Forest green - h3 headers
808
+ strong: "#ee964b",
809
+ // Sandy Brown - bold text
810
+ em: "#f95738",
811
+ // Tomato - italic text
812
+ del: "#ee964b",
813
+ // Sandy Brown - deleted text (same as strong)
814
+ link: "#0d3b66",
815
+ // Yale Blue - links
816
+ code: "#0d3b66",
817
+ // Yale Blue - inline code
818
+ codeBg: "rgba(244, 211, 94, 0.4)",
819
+ // Naples Yellow with transparency
820
+ blockquote: "#5a7a9b",
821
+ // Muted blue - blockquotes
822
+ hr: "#5a7a9b",
823
+ // Muted blue - horizontal rules
824
+ syntaxMarker: "rgba(13, 59, 102, 0.52)",
825
+ // Yale Blue with transparency
826
+ syntax: "#999999",
827
+ // Gray - syntax highlighting fallback
828
+ cursor: "#f95738",
829
+ // Tomato - cursor
830
+ selection: "rgba(244, 211, 94, 0.4)",
831
+ // Naples Yellow with transparency
832
+ listMarker: "#ee964b",
833
+ // Sandy Brown - list markers
834
+ rawLine: "#5a7a9b",
835
+ // Muted blue - raw line indicators
836
+ border: "#e0e0e0",
837
+ // Light gray - borders
838
+ hoverBg: "#f0f0f0",
839
+ // Very light gray - hover backgrounds
840
+ primary: "#0d3b66",
841
+ // Yale Blue - primary accent
842
+ // Toolbar colors
843
+ toolbarBg: "#ffffff",
844
+ // White - toolbar background
845
+ toolbarIcon: "#0d3b66",
846
+ // Yale Blue - icon color
847
+ toolbarHover: "#f5f5f5",
848
+ // Light gray - hover background
849
+ toolbarActive: "#faf0ca"
850
+ // Lemon Chiffon - active button background
937
851
  }
938
- if (debugMode2) {
939
- console.log("Final value length:", textarea.value.length);
940
- console.groupEnd();
852
+ };
853
+ var cave = {
854
+ name: "cave",
855
+ colors: {
856
+ bgPrimary: "#141E26",
857
+ // Deep ocean - main background
858
+ bgSecondary: "#1D2D3E",
859
+ // Darker charcoal - editor background
860
+ text: "#c5dde8",
861
+ // Light blue-gray - main text
862
+ textPrimary: "#c5dde8",
863
+ // Light blue-gray - primary text (same as text)
864
+ textSecondary: "#9fcfec",
865
+ // Brighter blue - secondary text
866
+ h1: "#d4a5ff",
867
+ // Rich lavender - h1 headers
868
+ h2: "#f6ae2d",
869
+ // Hunyadi Yellow - h2 headers
870
+ h3: "#9fcfec",
871
+ // Brighter blue - h3 headers
872
+ strong: "#f6ae2d",
873
+ // Hunyadi Yellow - bold text
874
+ em: "#9fcfec",
875
+ // Brighter blue - italic text
876
+ del: "#f6ae2d",
877
+ // Hunyadi Yellow - deleted text (same as strong)
878
+ link: "#9fcfec",
879
+ // Brighter blue - links
880
+ code: "#c5dde8",
881
+ // Light blue-gray - inline code
882
+ codeBg: "#1a232b",
883
+ // Very dark blue - code background
884
+ blockquote: "#9fcfec",
885
+ // Brighter blue - same as italic
886
+ hr: "#c5dde8",
887
+ // Light blue-gray - horizontal rules
888
+ syntaxMarker: "rgba(159, 207, 236, 0.73)",
889
+ // Brighter blue semi-transparent
890
+ syntax: "#7a8c98",
891
+ // Muted gray-blue - syntax highlighting fallback
892
+ cursor: "#f26419",
893
+ // Orange Pantone - cursor
894
+ selection: "rgba(51, 101, 138, 0.4)",
895
+ // Lapis Lazuli with transparency
896
+ listMarker: "#f6ae2d",
897
+ // Hunyadi Yellow - list markers
898
+ rawLine: "#9fcfec",
899
+ // Brighter blue - raw line indicators
900
+ border: "#2a3f52",
901
+ // Dark blue-gray - borders
902
+ hoverBg: "#243546",
903
+ // Slightly lighter charcoal - hover backgrounds
904
+ primary: "#9fcfec",
905
+ // Brighter blue - primary accent
906
+ // Toolbar colors for dark theme
907
+ toolbarBg: "#1D2D3E",
908
+ // Darker charcoal - toolbar background
909
+ toolbarIcon: "#c5dde8",
910
+ // Light blue-gray - icon color
911
+ toolbarHover: "#243546",
912
+ // Slightly lighter charcoal - hover background
913
+ toolbarActive: "#2a3f52"
914
+ // Even lighter - active button background
941
915
  }
942
- }
943
- function isMultipleLines(string) {
944
- return string.trim().split("\n").length > 1;
945
- }
946
- function wordSelectionStart(text, i) {
947
- let index = i;
948
- while (text[index] && text[index - 1] != null && !text[index - 1].match(/\s/)) {
949
- index--;
916
+ };
917
+ var themes = {
918
+ solar,
919
+ cave,
920
+ // Aliases for backward compatibility
921
+ light: solar,
922
+ dark: cave
923
+ };
924
+ function getTheme(theme) {
925
+ if (typeof theme === "string") {
926
+ const themeObj = themes[theme] || themes.solar;
927
+ return { ...themeObj, name: theme };
950
928
  }
951
- return index;
929
+ return theme;
952
930
  }
953
- function wordSelectionEnd(text, i, multiline) {
954
- let index = i;
955
- const breakpoint = multiline ? /\n/ : /\s/;
956
- while (text[index] && !text[index].match(breakpoint)) {
957
- index++;
931
+ function themeToCSSVars(colors) {
932
+ const vars = [];
933
+ for (const [key, value] of Object.entries(colors)) {
934
+ const varName = key.replace(/([A-Z])/g, "-$1").toLowerCase();
935
+ vars.push(`--${varName}: ${value};`);
958
936
  }
959
- return index;
937
+ return vars.join("\n");
960
938
  }
961
- function expandSelectionToLine(textarea) {
962
- const lines = textarea.value.split("\n");
963
- let counter = 0;
964
- for (let index = 0; index < lines.length; index++) {
965
- const lineLength = lines[index].length + 1;
966
- if (textarea.selectionStart >= counter && textarea.selectionStart < counter + lineLength) {
967
- textarea.selectionStart = counter;
939
+ function mergeTheme(baseTheme, customColors = {}) {
940
+ return {
941
+ ...baseTheme,
942
+ colors: {
943
+ ...baseTheme.colors,
944
+ ...customColors
968
945
  }
969
- if (textarea.selectionEnd >= counter && textarea.selectionEnd < counter + lineLength) {
970
- if (index === lines.length - 1) {
971
- textarea.selectionEnd = Math.min(counter + lines[index].length, textarea.value.length);
972
- } else {
973
- textarea.selectionEnd = counter + lineLength - 1;
946
+ };
947
+ }
948
+
949
+ // src/styles.js
950
+ function generateStyles(options = {}) {
951
+ const {
952
+ fontSize = "14px",
953
+ lineHeight = 1.6,
954
+ /* System-first, guaranteed monospaced; avoids Android 'ui-monospace' pitfalls */
955
+ fontFamily = '"SF Mono", SFMono-Regular, Menlo, Monaco, "Cascadia Code", Consolas, "Roboto Mono", "Noto Sans Mono", "Droid Sans Mono", "Ubuntu Mono", "DejaVu Sans Mono", "Liberation Mono", "Courier New", Courier, monospace',
956
+ padding = "20px",
957
+ theme = null,
958
+ mobile = {}
959
+ } = options;
960
+ const mobileStyles = Object.keys(mobile).length > 0 ? `
961
+ @media (max-width: 640px) {
962
+ .overtype-wrapper .overtype-input,
963
+ .overtype-wrapper .overtype-preview {
964
+ ${Object.entries(mobile).map(([prop, val]) => {
965
+ const cssProp = prop.replace(/([A-Z])/g, "-$1").toLowerCase();
966
+ return `${cssProp}: ${val} !important;`;
967
+ }).join("\n ")}
974
968
  }
975
969
  }
976
- counter += lineLength;
977
- }
978
- }
979
- function expandSelectedText(textarea, prefixToUse, suffixToUse, multiline = false) {
980
- if (textarea.selectionStart === textarea.selectionEnd) {
981
- textarea.selectionStart = wordSelectionStart(textarea.value, textarea.selectionStart);
982
- textarea.selectionEnd = wordSelectionEnd(textarea.value, textarea.selectionEnd, multiline);
983
- } else {
984
- const expandedSelectionStart = textarea.selectionStart - prefixToUse.length;
985
- const expandedSelectionEnd = textarea.selectionEnd + suffixToUse.length;
986
- const beginsWithPrefix = textarea.value.slice(expandedSelectionStart, textarea.selectionStart) === prefixToUse;
987
- const endsWithSuffix = textarea.value.slice(textarea.selectionEnd, expandedSelectionEnd) === suffixToUse;
988
- if (beginsWithPrefix && endsWithSuffix) {
989
- textarea.selectionStart = expandedSelectionStart;
990
- textarea.selectionEnd = expandedSelectionEnd;
970
+ ` : "";
971
+ const themeVars = theme && theme.colors ? themeToCSSVars(theme.colors) : "";
972
+ return `
973
+ /* OverType Editor Styles */
974
+
975
+ /* Middle-ground CSS Reset - Prevent parent styles from leaking in */
976
+ .overtype-container * {
977
+ /* Box model - these commonly leak */
978
+ margin: 0 !important;
979
+ padding: 0 !important;
980
+ border: 0 !important;
981
+
982
+ /* Layout - these can break our layout */
983
+ /* Don't reset position - it breaks dropdowns */
984
+ float: none !important;
985
+ clear: none !important;
986
+
987
+ /* Typography - only reset decorative aspects */
988
+ text-decoration: none !important;
989
+ text-transform: none !important;
990
+ letter-spacing: normal !important;
991
+
992
+ /* Visual effects that can interfere */
993
+ box-shadow: none !important;
994
+ text-shadow: none !important;
995
+
996
+ /* Ensure box-sizing is consistent */
997
+ box-sizing: border-box !important;
998
+
999
+ /* Keep inheritance for these */
1000
+ /* font-family, color, line-height, font-size - inherit */
1001
+ }
1002
+
1003
+ /* Container base styles after reset */
1004
+ .overtype-container {
1005
+ display: flex !important;
1006
+ flex-direction: column !important;
1007
+ width: 100% !important;
1008
+ height: 100% !important;
1009
+ position: relative !important; /* Override reset - needed for absolute children */
1010
+ overflow: visible !important; /* Allow dropdown to overflow container */
1011
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
1012
+ text-align: left !important;
1013
+ ${themeVars ? `
1014
+ /* Theme Variables */
1015
+ ${themeVars}` : ""}
1016
+ }
1017
+
1018
+ /* Force left alignment for all elements in the editor */
1019
+ .overtype-container .overtype-wrapper * {
1020
+ text-align: left !important;
1021
+ }
1022
+
1023
+ /* Auto-resize mode styles */
1024
+ .overtype-container.overtype-auto-resize {
1025
+ height: auto !important;
1026
+ }
1027
+
1028
+ .overtype-container.overtype-auto-resize .overtype-wrapper {
1029
+ flex: 0 0 auto !important; /* Don't grow/shrink, use explicit height */
1030
+ height: auto !important;
1031
+ min-height: 60px !important;
1032
+ overflow: visible !important;
1033
+ }
1034
+
1035
+ .overtype-wrapper {
1036
+ position: relative !important; /* Override reset - needed for absolute children */
1037
+ width: 100% !important;
1038
+ flex: 1 1 0 !important; /* Grow to fill remaining space, with flex-basis: 0 */
1039
+ min-height: 60px !important; /* Minimum usable height */
1040
+ overflow: hidden !important;
1041
+ background: var(--bg-secondary, #ffffff) !important;
1042
+ z-index: 1; /* Below toolbar and dropdown */
1043
+ }
1044
+
1045
+ /* Critical alignment styles - must be identical for both layers */
1046
+ .overtype-wrapper .overtype-input,
1047
+ .overtype-wrapper .overtype-preview {
1048
+ /* Positioning - must be identical */
1049
+ position: absolute !important; /* Override reset - required for overlay */
1050
+ top: 0 !important;
1051
+ left: 0 !important;
1052
+ width: 100% !important;
1053
+ height: 100% !important;
1054
+
1055
+ /* Font properties - any difference breaks alignment */
1056
+ font-family: ${fontFamily} !important;
1057
+ font-variant-ligatures: none !important; /* keep metrics stable for code */
1058
+ font-size: var(--instance-font-size, ${fontSize}) !important;
1059
+ line-height: var(--instance-line-height, ${lineHeight}) !important;
1060
+ font-weight: normal !important;
1061
+ font-style: normal !important;
1062
+ font-variant: normal !important;
1063
+ font-stretch: normal !important;
1064
+ font-kerning: none !important;
1065
+ font-feature-settings: normal !important;
1066
+
1067
+ /* Box model - must match exactly */
1068
+ padding: var(--instance-padding, ${padding}) !important;
1069
+ margin: 0 !important;
1070
+ border: none !important;
1071
+ outline: none !important;
1072
+ box-sizing: border-box !important;
1073
+
1074
+ /* Text layout - critical for character positioning */
1075
+ white-space: pre-wrap !important;
1076
+ word-wrap: break-word !important;
1077
+ word-break: normal !important;
1078
+ overflow-wrap: break-word !important;
1079
+ tab-size: 2 !important;
1080
+ -moz-tab-size: 2 !important;
1081
+ text-align: left !important;
1082
+ text-indent: 0 !important;
1083
+ letter-spacing: normal !important;
1084
+ word-spacing: normal !important;
1085
+
1086
+ /* Text rendering */
1087
+ text-transform: none !important;
1088
+ text-rendering: auto !important;
1089
+ -webkit-font-smoothing: auto !important;
1090
+ -webkit-text-size-adjust: 100% !important;
1091
+
1092
+ /* Direction and writing */
1093
+ direction: ltr !important;
1094
+ writing-mode: horizontal-tb !important;
1095
+ unicode-bidi: normal !important;
1096
+ text-orientation: mixed !important;
1097
+
1098
+ /* Visual effects that could shift perception */
1099
+ text-shadow: none !important;
1100
+ filter: none !important;
1101
+ transform: none !important;
1102
+ zoom: 1 !important;
1103
+
1104
+ /* Vertical alignment */
1105
+ vertical-align: baseline !important;
1106
+
1107
+ /* Size constraints */
1108
+ min-width: 0 !important;
1109
+ min-height: 0 !important;
1110
+ max-width: none !important;
1111
+ max-height: none !important;
1112
+
1113
+ /* Overflow */
1114
+ overflow-y: auto !important;
1115
+ overflow-x: auto !important;
1116
+ /* overscroll-behavior removed to allow scroll-through to parent */
1117
+ scrollbar-width: auto !important;
1118
+ scrollbar-gutter: auto !important;
1119
+
1120
+ /* Animation/transition - disabled to prevent movement */
1121
+ animation: none !important;
1122
+ transition: none !important;
991
1123
  }
992
- }
993
- return textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
994
- }
995
- function newlinesToSurroundSelectedText(textarea) {
996
- const beforeSelection = textarea.value.slice(0, textarea.selectionStart);
997
- const afterSelection = textarea.value.slice(textarea.selectionEnd);
998
- const breaksBefore = beforeSelection.match(/\n*$/);
999
- const breaksAfter = afterSelection.match(/^\n*/);
1000
- const newlinesBeforeSelection = breaksBefore ? breaksBefore[0].length : 0;
1001
- const newlinesAfterSelection = breaksAfter ? breaksAfter[0].length : 0;
1002
- let newlinesToAppend = "";
1003
- let newlinesToPrepend = "";
1004
- if (beforeSelection.match(/\S/) && newlinesBeforeSelection < 2) {
1005
- newlinesToAppend = "\n".repeat(2 - newlinesBeforeSelection);
1006
- }
1007
- if (afterSelection.match(/\S/) && newlinesAfterSelection < 2) {
1008
- newlinesToPrepend = "\n".repeat(2 - newlinesAfterSelection);
1009
- }
1010
- return { newlinesToAppend, newlinesToPrepend };
1011
- }
1012
- function applyLineOperation(textarea, operation, options = {}) {
1013
- const originalStart = textarea.selectionStart;
1014
- const originalEnd = textarea.selectionEnd;
1015
- const noInitialSelection = originalStart === originalEnd;
1016
- const value = textarea.value;
1017
- let lineStart = originalStart;
1018
- while (lineStart > 0 && value[lineStart - 1] !== "\n") {
1019
- lineStart--;
1020
- }
1021
- if (noInitialSelection) {
1022
- let lineEnd = originalStart;
1023
- while (lineEnd < value.length && value[lineEnd] !== "\n") {
1024
- lineEnd++;
1124
+
1125
+ /* Input layer styles */
1126
+ .overtype-wrapper .overtype-input {
1127
+ /* Layer positioning */
1128
+ z-index: 1 !important;
1129
+
1130
+ /* Text visibility */
1131
+ color: transparent !important;
1132
+ caret-color: var(--cursor, #f95738) !important;
1133
+ background-color: transparent !important;
1134
+
1135
+ /* Textarea-specific */
1136
+ resize: none !important;
1137
+ appearance: none !important;
1138
+ -webkit-appearance: none !important;
1139
+ -moz-appearance: none !important;
1140
+
1141
+ /* Prevent mobile zoom on focus */
1142
+ touch-action: manipulation !important;
1143
+
1144
+ /* Disable autofill and spellcheck */
1145
+ autocomplete: off !important;
1146
+ autocorrect: off !important;
1147
+ autocapitalize: off !important;
1148
+ spellcheck: false !important;
1025
1149
  }
1026
- textarea.selectionStart = lineStart;
1027
- textarea.selectionEnd = lineEnd;
1028
- } else {
1029
- expandSelectionToLine(textarea);
1030
- }
1031
- const result = operation(textarea);
1032
- if (options.adjustSelection) {
1033
- const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
1034
- const isRemoving = selectedText.startsWith(options.prefix);
1035
- const adjusted = options.adjustSelection(isRemoving, originalStart, originalEnd, lineStart);
1036
- result.selectionStart = adjusted.start;
1037
- result.selectionEnd = adjusted.end;
1038
- } else if (options.prefix) {
1039
- const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
1040
- const isRemoving = selectedText.startsWith(options.prefix);
1041
- if (noInitialSelection) {
1042
- if (isRemoving) {
1043
- result.selectionStart = Math.max(originalStart - options.prefix.length, lineStart);
1044
- result.selectionEnd = result.selectionStart;
1045
- } else {
1046
- result.selectionStart = originalStart + options.prefix.length;
1047
- result.selectionEnd = result.selectionStart;
1048
- }
1049
- } else {
1050
- if (isRemoving) {
1051
- result.selectionStart = Math.max(originalStart - options.prefix.length, lineStart);
1052
- result.selectionEnd = Math.max(originalEnd - options.prefix.length, lineStart);
1053
- } else {
1054
- result.selectionStart = originalStart + options.prefix.length;
1055
- result.selectionEnd = originalEnd + options.prefix.length;
1056
- }
1150
+
1151
+ .overtype-wrapper .overtype-input::selection {
1152
+ background-color: var(--selection, rgba(244, 211, 94, 0.4));
1057
1153
  }
1058
- }
1059
- return result;
1060
- }
1061
- function blockStyle(textarea, style) {
1062
- let newlinesToAppend;
1063
- let newlinesToPrepend;
1064
- const { prefix, suffix, blockPrefix, blockSuffix, replaceNext, prefixSpace, scanFor, surroundWithNewlines, trimFirst } = style;
1065
- const originalSelectionStart = textarea.selectionStart;
1066
- const originalSelectionEnd = textarea.selectionEnd;
1067
- let selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
1068
- let prefixToUse = isMultipleLines(selectedText) && blockPrefix && blockPrefix.length > 0 ? `${blockPrefix}
1069
- ` : prefix;
1070
- let suffixToUse = isMultipleLines(selectedText) && blockSuffix && blockSuffix.length > 0 ? `
1071
- ${blockSuffix}` : suffix;
1072
- if (prefixSpace) {
1073
- const beforeSelection = textarea.value[textarea.selectionStart - 1];
1074
- if (textarea.selectionStart !== 0 && beforeSelection != null && !beforeSelection.match(/\s/)) {
1075
- prefixToUse = ` ${prefixToUse}`;
1154
+
1155
+ /* Preview layer styles */
1156
+ .overtype-wrapper .overtype-preview {
1157
+ /* Layer positioning */
1158
+ z-index: 0 !important;
1159
+ pointer-events: none !important;
1160
+ color: var(--text, #0d3b66) !important;
1161
+ background-color: transparent !important;
1162
+
1163
+ /* Prevent text selection */
1164
+ user-select: none !important;
1165
+ -webkit-user-select: none !important;
1166
+ -moz-user-select: none !important;
1167
+ -ms-user-select: none !important;
1076
1168
  }
1077
- }
1078
- selectedText = expandSelectedText(textarea, prefixToUse, suffixToUse, style.multiline);
1079
- let selectionStart = textarea.selectionStart;
1080
- let selectionEnd = textarea.selectionEnd;
1081
- const hasReplaceNext = replaceNext && replaceNext.length > 0 && suffixToUse.indexOf(replaceNext) > -1 && selectedText.length > 0;
1082
- if (surroundWithNewlines) {
1083
- const ref = newlinesToSurroundSelectedText(textarea);
1084
- newlinesToAppend = ref.newlinesToAppend;
1085
- newlinesToPrepend = ref.newlinesToPrepend;
1086
- prefixToUse = newlinesToAppend + prefix;
1087
- suffixToUse += newlinesToPrepend;
1088
- }
1089
- if (selectedText.startsWith(prefixToUse) && selectedText.endsWith(suffixToUse)) {
1090
- const replacementText = selectedText.slice(prefixToUse.length, selectedText.length - suffixToUse.length);
1091
- if (originalSelectionStart === originalSelectionEnd) {
1092
- let position = originalSelectionStart - prefixToUse.length;
1093
- position = Math.max(position, selectionStart);
1094
- position = Math.min(position, selectionStart + replacementText.length);
1095
- selectionStart = selectionEnd = position;
1096
- } else {
1097
- selectionEnd = selectionStart + replacementText.length;
1169
+
1170
+ /* Defensive styles for preview child divs */
1171
+ .overtype-wrapper .overtype-preview div {
1172
+ /* Reset any inherited styles */
1173
+ margin: 0 !important;
1174
+ padding: 0 !important;
1175
+ border: none !important;
1176
+ text-align: left !important;
1177
+ text-indent: 0 !important;
1178
+ display: block !important;
1179
+ position: static !important;
1180
+ transform: none !important;
1181
+ min-height: 0 !important;
1182
+ max-height: none !important;
1183
+ line-height: inherit !important;
1184
+ font-size: inherit !important;
1185
+ font-family: inherit !important;
1098
1186
  }
1099
- return { text: replacementText, selectionStart, selectionEnd };
1100
- } else if (!hasReplaceNext) {
1101
- let replacementText = prefixToUse + selectedText + suffixToUse;
1102
- selectionStart = originalSelectionStart + prefixToUse.length;
1103
- selectionEnd = originalSelectionEnd + prefixToUse.length;
1104
- const whitespaceEdges = selectedText.match(/^\s*|\s*$/g);
1105
- if (trimFirst && whitespaceEdges) {
1106
- const leadingWhitespace = whitespaceEdges[0] || "";
1107
- const trailingWhitespace = whitespaceEdges[1] || "";
1108
- replacementText = leadingWhitespace + prefixToUse + selectedText.trim() + suffixToUse + trailingWhitespace;
1109
- selectionStart += leadingWhitespace.length;
1110
- selectionEnd -= trailingWhitespace.length;
1187
+
1188
+ /* Markdown element styling - NO SIZE CHANGES */
1189
+ .overtype-wrapper .overtype-preview .header {
1190
+ font-weight: bold !important;
1111
1191
  }
1112
- return { text: replacementText, selectionStart, selectionEnd };
1113
- } else if (scanFor && scanFor.length > 0 && selectedText.match(scanFor)) {
1114
- suffixToUse = suffixToUse.replace(replaceNext, selectedText);
1115
- const replacementText = prefixToUse + suffixToUse;
1116
- selectionStart = selectionEnd = selectionStart + prefixToUse.length;
1117
- return { text: replacementText, selectionStart, selectionEnd };
1118
- } else {
1119
- const replacementText = prefixToUse + selectedText + suffixToUse;
1120
- selectionStart = selectionStart + prefixToUse.length + selectedText.length + suffixToUse.indexOf(replaceNext);
1121
- selectionEnd = selectionStart + replaceNext.length;
1122
- return { text: replacementText, selectionStart, selectionEnd };
1123
- }
1124
- }
1125
- function multilineStyle(textarea, style) {
1126
- const { prefix, suffix, surroundWithNewlines } = style;
1127
- let text = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
1128
- let selectionStart = textarea.selectionStart;
1129
- let selectionEnd = textarea.selectionEnd;
1130
- const lines = text.split("\n");
1131
- const undoStyle = lines.every((line) => line.startsWith(prefix) && (!suffix || line.endsWith(suffix)));
1132
- if (undoStyle) {
1133
- text = lines.map((line) => {
1134
- let result = line.slice(prefix.length);
1135
- if (suffix) {
1136
- result = result.slice(0, result.length - suffix.length);
1137
- }
1138
- return result;
1139
- }).join("\n");
1140
- selectionEnd = selectionStart + text.length;
1141
- } else {
1142
- text = lines.map((line) => prefix + line + (suffix || "")).join("\n");
1143
- if (surroundWithNewlines) {
1144
- const { newlinesToAppend, newlinesToPrepend } = newlinesToSurroundSelectedText(textarea);
1145
- selectionStart += newlinesToAppend.length;
1146
- selectionEnd = selectionStart + text.length;
1147
- text = newlinesToAppend + text + newlinesToPrepend;
1192
+
1193
+ /* Header colors */
1194
+ .overtype-wrapper .overtype-preview .h1 {
1195
+ color: var(--h1, #f95738) !important;
1148
1196
  }
1149
- }
1150
- return { text, selectionStart, selectionEnd };
1151
- }
1152
- function undoOrderedListStyle(text) {
1153
- const lines = text.split("\n");
1154
- const orderedListRegex = /^\d+\.\s+/;
1155
- const shouldUndoOrderedList = lines.every((line) => orderedListRegex.test(line));
1156
- let result = lines;
1157
- if (shouldUndoOrderedList) {
1158
- result = lines.map((line) => line.replace(orderedListRegex, ""));
1159
- }
1160
- return {
1161
- text: result.join("\n"),
1162
- processed: shouldUndoOrderedList
1163
- };
1164
- }
1165
- function undoUnorderedListStyle(text) {
1166
- const lines = text.split("\n");
1167
- const unorderedListPrefix = "- ";
1168
- const shouldUndoUnorderedList = lines.every((line) => line.startsWith(unorderedListPrefix));
1169
- let result = lines;
1170
- if (shouldUndoUnorderedList) {
1171
- result = lines.map((line) => line.slice(unorderedListPrefix.length));
1172
- }
1173
- return {
1174
- text: result.join("\n"),
1175
- processed: shouldUndoUnorderedList
1176
- };
1177
- }
1178
- function makePrefix(index, unorderedList) {
1179
- if (unorderedList) {
1180
- return "- ";
1181
- } else {
1182
- return `${index + 1}. `;
1183
- }
1184
- }
1185
- function clearExistingListStyle(style, selectedText) {
1186
- let undoResult;
1187
- let undoResultOppositeList;
1188
- let pristineText;
1189
- if (style.orderedList) {
1190
- undoResult = undoOrderedListStyle(selectedText);
1191
- undoResultOppositeList = undoUnorderedListStyle(undoResult.text);
1192
- pristineText = undoResultOppositeList.text;
1193
- } else {
1194
- undoResult = undoUnorderedListStyle(selectedText);
1195
- undoResultOppositeList = undoOrderedListStyle(undoResult.text);
1196
- pristineText = undoResultOppositeList.text;
1197
- }
1198
- return [undoResult, undoResultOppositeList, pristineText];
1199
- }
1200
- function listStyle(textarea, style) {
1201
- const noInitialSelection = textarea.selectionStart === textarea.selectionEnd;
1202
- let selectionStart = textarea.selectionStart;
1203
- let selectionEnd = textarea.selectionEnd;
1204
- expandSelectionToLine(textarea);
1205
- const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
1206
- const [undoResult, undoResultOppositeList, pristineText] = clearExistingListStyle(style, selectedText);
1207
- const prefixedLines = pristineText.split("\n").map((value, index) => {
1208
- return `${makePrefix(index, style.unorderedList)}${value}`;
1209
- });
1210
- const totalPrefixLength = prefixedLines.reduce((previousValue, _currentValue, currentIndex) => {
1211
- return previousValue + makePrefix(currentIndex, style.unorderedList).length;
1212
- }, 0);
1213
- const totalPrefixLengthOppositeList = prefixedLines.reduce((previousValue, _currentValue, currentIndex) => {
1214
- return previousValue + makePrefix(currentIndex, !style.unorderedList).length;
1215
- }, 0);
1216
- if (undoResult.processed) {
1217
- if (noInitialSelection) {
1218
- selectionStart = Math.max(selectionStart - makePrefix(0, style.unorderedList).length, 0);
1219
- selectionEnd = selectionStart;
1220
- } else {
1221
- selectionStart = textarea.selectionStart;
1222
- selectionEnd = textarea.selectionEnd - totalPrefixLength;
1197
+ .overtype-wrapper .overtype-preview .h2 {
1198
+ color: var(--h2, #ee964b) !important;
1223
1199
  }
1224
- return { text: pristineText, selectionStart, selectionEnd };
1225
- }
1226
- const { newlinesToAppend, newlinesToPrepend } = newlinesToSurroundSelectedText(textarea);
1227
- const text = newlinesToAppend + prefixedLines.join("\n") + newlinesToPrepend;
1228
- if (noInitialSelection) {
1229
- selectionStart = Math.max(selectionStart + makePrefix(0, style.unorderedList).length + newlinesToAppend.length, 0);
1230
- selectionEnd = selectionStart;
1231
- } else {
1232
- if (undoResultOppositeList.processed) {
1233
- selectionStart = Math.max(textarea.selectionStart + newlinesToAppend.length, 0);
1234
- selectionEnd = textarea.selectionEnd + newlinesToAppend.length + totalPrefixLength - totalPrefixLengthOppositeList;
1235
- } else {
1236
- selectionStart = Math.max(textarea.selectionStart + newlinesToAppend.length, 0);
1237
- selectionEnd = textarea.selectionEnd + newlinesToAppend.length + totalPrefixLength;
1200
+ .overtype-wrapper .overtype-preview .h3 {
1201
+ color: var(--h3, #3d8a51) !important;
1238
1202
  }
1239
- }
1240
- return { text, selectionStart, selectionEnd };
1241
- }
1242
- function applyListStyle(textarea, style) {
1243
- const result = applyLineOperation(
1244
- textarea,
1245
- (ta) => listStyle(ta, style),
1246
- {
1247
- // Custom selection adjustment for lists
1248
- adjustSelection: (isRemoving, selStart, selEnd, lineStart) => {
1249
- const currentLine = textarea.value.slice(lineStart, textarea.selectionEnd);
1250
- const orderedListRegex = /^\d+\.\s+/;
1251
- const unorderedListRegex = /^- /;
1252
- const hasOrderedList = orderedListRegex.test(currentLine);
1253
- const hasUnorderedList = unorderedListRegex.test(currentLine);
1254
- const isRemovingCurrent = style.orderedList && hasOrderedList || style.unorderedList && hasUnorderedList;
1255
- if (selStart === selEnd) {
1256
- if (isRemovingCurrent) {
1257
- const prefixMatch = currentLine.match(style.orderedList ? orderedListRegex : unorderedListRegex);
1258
- const prefixLength = prefixMatch ? prefixMatch[0].length : 0;
1259
- return {
1260
- start: Math.max(selStart - prefixLength, lineStart),
1261
- end: Math.max(selStart - prefixLength, lineStart)
1262
- };
1263
- } else if (hasOrderedList || hasUnorderedList) {
1264
- const oldPrefixMatch = currentLine.match(hasOrderedList ? orderedListRegex : unorderedListRegex);
1265
- const oldPrefixLength = oldPrefixMatch ? oldPrefixMatch[0].length : 0;
1266
- const newPrefixLength = style.unorderedList ? 2 : 3;
1267
- const adjustment = newPrefixLength - oldPrefixLength;
1268
- return {
1269
- start: selStart + adjustment,
1270
- end: selStart + adjustment
1271
- };
1272
- } else {
1273
- const prefixLength = style.unorderedList ? 2 : 3;
1274
- return {
1275
- start: selStart + prefixLength,
1276
- end: selStart + prefixLength
1277
- };
1278
- }
1279
- } else {
1280
- if (isRemovingCurrent) {
1281
- const prefixMatch = currentLine.match(style.orderedList ? orderedListRegex : unorderedListRegex);
1282
- const prefixLength = prefixMatch ? prefixMatch[0].length : 0;
1283
- return {
1284
- start: Math.max(selStart - prefixLength, lineStart),
1285
- end: Math.max(selEnd - prefixLength, lineStart)
1286
- };
1287
- } else if (hasOrderedList || hasUnorderedList) {
1288
- const oldPrefixMatch = currentLine.match(hasOrderedList ? orderedListRegex : unorderedListRegex);
1289
- const oldPrefixLength = oldPrefixMatch ? oldPrefixMatch[0].length : 0;
1290
- const newPrefixLength = style.unorderedList ? 2 : 3;
1291
- const adjustment = newPrefixLength - oldPrefixLength;
1292
- return {
1293
- start: selStart + adjustment,
1294
- end: selEnd + adjustment
1295
- };
1296
- } else {
1297
- const prefixLength = style.unorderedList ? 2 : 3;
1298
- return {
1299
- start: selStart + prefixLength,
1300
- end: selEnd + prefixLength
1301
- };
1302
- }
1303
- }
1304
- }
1203
+
1204
+ /* Semantic headers - flatten in edit mode */
1205
+ .overtype-wrapper .overtype-preview h1,
1206
+ .overtype-wrapper .overtype-preview h2,
1207
+ .overtype-wrapper .overtype-preview h3 {
1208
+ font-size: inherit !important;
1209
+ font-weight: bold !important;
1210
+ margin: 0 !important;
1211
+ padding: 0 !important;
1212
+ display: inline !important;
1213
+ line-height: inherit !important;
1305
1214
  }
1306
- );
1307
- insertText(textarea, result);
1308
- }
1309
- function getActiveFormats(textarea) {
1310
- if (!textarea)
1311
- return [];
1312
- const formats = [];
1313
- const { selectionStart, selectionEnd, value } = textarea;
1314
- const lines = value.split("\n");
1315
- let lineStart = 0;
1316
- let currentLine = "";
1317
- for (const line of lines) {
1318
- if (selectionStart >= lineStart && selectionStart <= lineStart + line.length) {
1319
- currentLine = line;
1320
- break;
1215
+
1216
+ /* Header colors for semantic headers */
1217
+ .overtype-wrapper .overtype-preview h1 {
1218
+ color: var(--h1, #f95738) !important;
1321
1219
  }
1322
- lineStart += line.length + 1;
1323
- }
1324
- if (currentLine.startsWith("- ")) {
1325
- if (currentLine.startsWith("- [ ] ") || currentLine.startsWith("- [x] ")) {
1326
- formats.push("task-list");
1327
- } else {
1328
- formats.push("bullet-list");
1220
+ .overtype-wrapper .overtype-preview h2 {
1221
+ color: var(--h2, #ee964b) !important;
1329
1222
  }
1330
- }
1331
- if (/^\d+\.\s/.test(currentLine)) {
1332
- formats.push("numbered-list");
1333
- }
1334
- if (currentLine.startsWith("> ")) {
1335
- formats.push("quote");
1336
- }
1337
- if (currentLine.startsWith("# "))
1338
- formats.push("header");
1339
- if (currentLine.startsWith("## "))
1340
- formats.push("header-2");
1341
- if (currentLine.startsWith("### "))
1342
- formats.push("header-3");
1343
- const lookBehind = Math.max(0, selectionStart - 10);
1344
- const lookAhead = Math.min(value.length, selectionEnd + 10);
1345
- const surrounding = value.slice(lookBehind, lookAhead);
1346
- if (surrounding.includes("**")) {
1347
- const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
1348
- const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
1349
- const lastOpenBold = beforeCursor.lastIndexOf("**");
1350
- const nextCloseBold = afterCursor.indexOf("**");
1351
- if (lastOpenBold !== -1 && nextCloseBold !== -1) {
1352
- formats.push("bold");
1223
+ .overtype-wrapper .overtype-preview h3 {
1224
+ color: var(--h3, #3d8a51) !important;
1353
1225
  }
1354
- }
1355
- if (surrounding.includes("_")) {
1356
- const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
1357
- const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
1358
- const lastOpenItalic = beforeCursor.lastIndexOf("_");
1359
- const nextCloseItalic = afterCursor.indexOf("_");
1360
- if (lastOpenItalic !== -1 && nextCloseItalic !== -1) {
1361
- formats.push("italic");
1226
+
1227
+ /* Lists - remove styling in edit mode */
1228
+ .overtype-wrapper .overtype-preview ul,
1229
+ .overtype-wrapper .overtype-preview ol {
1230
+ list-style: none !important;
1231
+ margin: 0 !important;
1232
+ padding: 0 !important;
1233
+ display: block !important; /* Lists need to be block for line breaks */
1362
1234
  }
1363
- }
1364
- if (surrounding.includes("`")) {
1365
- const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
1366
- const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
1367
- if (beforeCursor.includes("`") && afterCursor.includes("`")) {
1368
- formats.push("code");
1235
+
1236
+ .overtype-wrapper .overtype-preview li {
1237
+ display: block !important; /* Each item on its own line */
1238
+ margin: 0 !important;
1239
+ padding: 0 !important;
1240
+ /* Don't set list-style here - let ul/ol control it */
1369
1241
  }
1370
- }
1371
- if (surrounding.includes("[") && surrounding.includes("]")) {
1372
- const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
1373
- const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
1374
- const lastOpenBracket = beforeCursor.lastIndexOf("[");
1375
- const nextCloseBracket = afterCursor.indexOf("]");
1376
- if (lastOpenBracket !== -1 && nextCloseBracket !== -1) {
1377
- const afterBracket = value.slice(selectionEnd + nextCloseBracket + 1, selectionEnd + nextCloseBracket + 10);
1378
- if (afterBracket.startsWith("(")) {
1379
- formats.push("link");
1380
- }
1242
+
1243
+ /* Bold text */
1244
+ .overtype-wrapper .overtype-preview strong {
1245
+ color: var(--strong, #ee964b) !important;
1246
+ font-weight: bold !important;
1381
1247
  }
1382
- }
1383
- return formats;
1384
- }
1385
- function toggleBold(textarea) {
1386
- if (!textarea || textarea.disabled || textarea.readOnly)
1387
- return;
1388
- debugLog("toggleBold", "Starting");
1389
- debugSelection(textarea, "Before");
1390
- const style = mergeWithDefaults(FORMATS.bold);
1391
- const result = blockStyle(textarea, style);
1392
- debugResult(result);
1393
- insertText(textarea, result);
1394
- debugSelection(textarea, "After");
1395
- }
1396
- function toggleItalic(textarea) {
1397
- if (!textarea || textarea.disabled || textarea.readOnly)
1398
- return;
1399
- const style = mergeWithDefaults(FORMATS.italic);
1400
- const result = blockStyle(textarea, style);
1401
- insertText(textarea, result);
1402
- }
1403
- function toggleCode(textarea) {
1404
- if (!textarea || textarea.disabled || textarea.readOnly)
1405
- return;
1406
- const style = mergeWithDefaults(FORMATS.code);
1407
- const result = blockStyle(textarea, style);
1408
- insertText(textarea, result);
1409
- }
1410
- function insertLink(textarea, options = {}) {
1411
- if (!textarea || textarea.disabled || textarea.readOnly)
1412
- return;
1413
- const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
1414
- let style = mergeWithDefaults(FORMATS.link);
1415
- const isURL = selectedText && selectedText.match(/^https?:\/\//);
1416
- if (isURL && !options.url) {
1417
- style.suffix = `](${selectedText})`;
1418
- style.replaceNext = "";
1419
- } else if (options.url) {
1420
- style.suffix = `](${options.url})`;
1421
- style.replaceNext = "";
1422
- }
1423
- if (options.text && !selectedText) {
1424
- const pos = textarea.selectionStart;
1425
- textarea.value = textarea.value.slice(0, pos) + options.text + textarea.value.slice(pos);
1426
- textarea.selectionStart = pos;
1427
- textarea.selectionEnd = pos + options.text.length;
1428
- }
1429
- const result = blockStyle(textarea, style);
1430
- insertText(textarea, result);
1431
- }
1432
- function toggleBulletList(textarea) {
1433
- if (!textarea || textarea.disabled || textarea.readOnly)
1434
- return;
1435
- const style = mergeWithDefaults(FORMATS.bulletList);
1436
- applyListStyle(textarea, style);
1437
- }
1438
- function toggleNumberedList(textarea) {
1439
- if (!textarea || textarea.disabled || textarea.readOnly)
1440
- return;
1441
- const style = mergeWithDefaults(FORMATS.numberedList);
1442
- applyListStyle(textarea, style);
1443
- }
1444
- function toggleQuote(textarea) {
1445
- if (!textarea || textarea.disabled || textarea.readOnly)
1446
- return;
1447
- debugLog("toggleQuote", "Starting");
1448
- debugSelection(textarea, "Initial");
1449
- const style = mergeWithDefaults(FORMATS.quote);
1450
- const result = applyLineOperation(
1451
- textarea,
1452
- (ta) => multilineStyle(ta, style),
1453
- { prefix: style.prefix }
1454
- );
1455
- debugResult(result);
1456
- insertText(textarea, result);
1457
- debugSelection(textarea, "Final");
1458
- }
1459
- function toggleTaskList(textarea) {
1460
- if (!textarea || textarea.disabled || textarea.readOnly)
1461
- return;
1462
- const style = mergeWithDefaults(FORMATS.taskList);
1463
- const result = applyLineOperation(
1464
- textarea,
1465
- (ta) => multilineStyle(ta, style),
1466
- { prefix: style.prefix }
1467
- );
1468
- insertText(textarea, result);
1469
- }
1470
- function insertHeader(textarea, level = 1, toggle = false) {
1471
- if (!textarea || textarea.disabled || textarea.readOnly)
1472
- return;
1473
- if (level < 1 || level > 6)
1474
- level = 1;
1475
- debugLog("insertHeader", `============ START ============`);
1476
- debugLog("insertHeader", `Level: ${level}, Toggle: ${toggle}`);
1477
- debugLog("insertHeader", `Initial cursor: ${textarea.selectionStart}-${textarea.selectionEnd}`);
1478
- const headerKey = `header${level === 1 ? "1" : level}`;
1479
- const style = mergeWithDefaults(FORMATS[headerKey] || FORMATS.header1);
1480
- debugLog("insertHeader", `Style prefix: "${style.prefix}"`);
1481
- const value = textarea.value;
1482
- const originalStart = textarea.selectionStart;
1483
- const originalEnd = textarea.selectionEnd;
1484
- let lineStart = originalStart;
1485
- while (lineStart > 0 && value[lineStart - 1] !== "\n") {
1486
- lineStart--;
1487
- }
1488
- let lineEnd = originalEnd;
1489
- while (lineEnd < value.length && value[lineEnd] !== "\n") {
1490
- lineEnd++;
1491
- }
1492
- const currentLineContent = value.slice(lineStart, lineEnd);
1493
- debugLog("insertHeader", `Current line (before): "${currentLineContent}"`);
1494
- const existingHeaderMatch = currentLineContent.match(/^(#{1,6})\s*/);
1495
- const existingLevel = existingHeaderMatch ? existingHeaderMatch[1].length : 0;
1496
- const existingPrefixLength = existingHeaderMatch ? existingHeaderMatch[0].length : 0;
1497
- debugLog("insertHeader", `Existing header check:`);
1498
- debugLog("insertHeader", ` - Match: ${existingHeaderMatch ? `"${existingHeaderMatch[0]}"` : "none"}`);
1499
- debugLog("insertHeader", ` - Existing level: ${existingLevel}`);
1500
- debugLog("insertHeader", ` - Existing prefix length: ${existingPrefixLength}`);
1501
- debugLog("insertHeader", ` - Target level: ${level}`);
1502
- const shouldToggleOff = toggle && existingLevel === level;
1503
- debugLog("insertHeader", `Should toggle OFF: ${shouldToggleOff} (toggle=${toggle}, existingLevel=${existingLevel}, level=${level})`);
1504
- const result = applyLineOperation(
1505
- textarea,
1506
- (ta) => {
1507
- const currentLine = ta.value.slice(ta.selectionStart, ta.selectionEnd);
1508
- debugLog("insertHeader", `Line in operation: "${currentLine}"`);
1509
- const cleanedLine = currentLine.replace(/^#{1,6}\s*/, "");
1510
- debugLog("insertHeader", `Cleaned line: "${cleanedLine}"`);
1511
- let newLine;
1512
- if (shouldToggleOff) {
1513
- debugLog("insertHeader", "ACTION: Toggling OFF - removing header");
1514
- newLine = cleanedLine;
1515
- } else if (existingLevel > 0) {
1516
- debugLog("insertHeader", `ACTION: Replacing H${existingLevel} with H${level}`);
1517
- newLine = style.prefix + cleanedLine;
1518
- } else {
1519
- debugLog("insertHeader", "ACTION: Adding new header");
1520
- newLine = style.prefix + cleanedLine;
1521
- }
1522
- debugLog("insertHeader", `New line: "${newLine}"`);
1523
- return {
1524
- text: newLine,
1525
- selectionStart: ta.selectionStart,
1526
- selectionEnd: ta.selectionEnd
1527
- };
1528
- },
1529
- {
1530
- prefix: style.prefix,
1531
- // Custom selection adjustment for headers
1532
- adjustSelection: (isRemoving, selStart, selEnd, lineStartPos) => {
1533
- debugLog("insertHeader", `Adjusting selection:`);
1534
- debugLog("insertHeader", ` - isRemoving param: ${isRemoving}`);
1535
- debugLog("insertHeader", ` - shouldToggleOff: ${shouldToggleOff}`);
1536
- debugLog("insertHeader", ` - selStart: ${selStart}, selEnd: ${selEnd}`);
1537
- debugLog("insertHeader", ` - lineStartPos: ${lineStartPos}`);
1538
- if (shouldToggleOff) {
1539
- const adjustment = Math.max(selStart - existingPrefixLength, lineStartPos);
1540
- debugLog("insertHeader", ` - Removing header, adjusting by -${existingPrefixLength}`);
1541
- return {
1542
- start: adjustment,
1543
- end: selStart === selEnd ? adjustment : Math.max(selEnd - existingPrefixLength, lineStartPos)
1544
- };
1545
- } else if (existingPrefixLength > 0) {
1546
- const prefixDiff = style.prefix.length - existingPrefixLength;
1547
- debugLog("insertHeader", ` - Replacing header, adjusting by ${prefixDiff}`);
1548
- return {
1549
- start: selStart + prefixDiff,
1550
- end: selEnd + prefixDiff
1551
- };
1552
- } else {
1553
- debugLog("insertHeader", ` - Adding header, adjusting by +${style.prefix.length}`);
1554
- return {
1555
- start: selStart + style.prefix.length,
1556
- end: selEnd + style.prefix.length
1557
- };
1558
- }
1559
- }
1248
+
1249
+ /* Italic text */
1250
+ .overtype-wrapper .overtype-preview em {
1251
+ color: var(--em, #f95738) !important;
1252
+ text-decoration-color: var(--em, #f95738) !important;
1253
+ text-decoration-thickness: 1px !important;
1254
+ font-style: italic !important;
1255
+ }
1256
+
1257
+ /* Strikethrough text */
1258
+ .overtype-wrapper .overtype-preview del {
1259
+ color: var(--del, #ee964b) !important;
1260
+ text-decoration: line-through !important;
1261
+ text-decoration-color: var(--del, #ee964b) !important;
1262
+ text-decoration-thickness: 1px !important;
1560
1263
  }
1561
- );
1562
- debugLog("insertHeader", `Final result: text="${result.text}", cursor=${result.selectionStart}-${result.selectionEnd}`);
1563
- debugLog("insertHeader", `============ END ============`);
1564
- insertText(textarea, result);
1565
- }
1566
- function toggleH1(textarea) {
1567
- insertHeader(textarea, 1, true);
1568
- }
1569
- function toggleH2(textarea) {
1570
- insertHeader(textarea, 2, true);
1571
- }
1572
- function toggleH3(textarea) {
1573
- insertHeader(textarea, 3, true);
1574
- }
1575
- function getActiveFormats2(textarea) {
1576
- return getActiveFormats(textarea);
1577
- }
1578
1264
 
1579
- // src/shortcuts.js
1580
- var ShortcutsManager = class {
1581
- constructor(editor) {
1582
- this.editor = editor;
1583
- this.textarea = editor.textarea;
1584
- }
1585
- /**
1586
- * Handle keydown events - called by OverType
1587
- * @param {KeyboardEvent} event - The keyboard event
1588
- * @returns {boolean} Whether the event was handled
1589
- */
1590
- handleKeydown(event) {
1591
- const isMac = navigator.platform.toLowerCase().includes("mac");
1592
- const modKey = isMac ? event.metaKey : event.ctrlKey;
1593
- if (!modKey)
1594
- return false;
1595
- let action = null;
1596
- switch (event.key.toLowerCase()) {
1597
- case "b":
1598
- if (!event.shiftKey) {
1599
- action = "toggleBold";
1600
- }
1601
- break;
1602
- case "i":
1603
- if (!event.shiftKey) {
1604
- action = "toggleItalic";
1605
- }
1606
- break;
1607
- case "k":
1608
- if (!event.shiftKey) {
1609
- action = "insertLink";
1610
- }
1611
- break;
1612
- case "7":
1613
- if (event.shiftKey) {
1614
- action = "toggleNumberedList";
1615
- }
1616
- break;
1617
- case "8":
1618
- if (event.shiftKey) {
1619
- action = "toggleBulletList";
1620
- }
1621
- break;
1265
+ /* Inline code */
1266
+ .overtype-wrapper .overtype-preview code {
1267
+ background: var(--code-bg, rgba(244, 211, 94, 0.4)) !important;
1268
+ color: var(--code, #0d3b66) !important;
1269
+ padding: 0 !important;
1270
+ border-radius: 2px !important;
1271
+ font-family: inherit !important;
1272
+ font-size: inherit !important;
1273
+ line-height: inherit !important;
1274
+ font-weight: normal !important;
1622
1275
  }
1623
- if (action) {
1624
- event.preventDefault();
1625
- if (this.editor.toolbar) {
1626
- this.editor.toolbar.handleAction(action);
1627
- } else {
1628
- this.handleAction(action);
1629
- }
1630
- return true;
1276
+
1277
+ /* Code blocks - consolidated pre blocks */
1278
+ .overtype-wrapper .overtype-preview pre {
1279
+ padding: 0 !important;
1280
+ margin: 0 !important;
1281
+ border-radius: 4px !important;
1282
+ overflow-x: auto !important;
1631
1283
  }
1632
- return false;
1633
- }
1634
- /**
1635
- * Handle action - fallback when no toolbar exists
1636
- * This duplicates toolbar.handleAction for consistency
1637
- */
1638
- async handleAction(action) {
1639
- const textarea = this.textarea;
1640
- if (!textarea)
1641
- return;
1642
- textarea.focus();
1643
- try {
1644
- switch (action) {
1645
- case "toggleBold":
1646
- toggleBold(textarea);
1647
- break;
1648
- case "toggleItalic":
1649
- toggleItalic(textarea);
1650
- break;
1651
- case "insertLink":
1652
- insertLink(textarea);
1653
- break;
1654
- case "toggleBulletList":
1655
- toggleBulletList(textarea);
1656
- break;
1657
- case "toggleNumberedList":
1658
- toggleNumberedList(textarea);
1659
- break;
1660
- }
1661
- textarea.dispatchEvent(new Event("input", { bubbles: true }));
1662
- } catch (error) {
1663
- console.error("Error in markdown action:", error);
1284
+
1285
+ /* Code block styling in normal mode - yellow background */
1286
+ .overtype-wrapper .overtype-preview pre.code-block {
1287
+ background: var(--code-bg, rgba(244, 211, 94, 0.4)) !important;
1288
+ white-space: break-spaces !important; /* Prevent horizontal scrollbar that breaks alignment */
1664
1289
  }
1665
- }
1666
- /**
1667
- * Cleanup
1668
- */
1669
- destroy() {
1670
- }
1671
- };
1672
1290
 
1673
- // src/themes.js
1674
- var solar = {
1675
- name: "solar",
1676
- colors: {
1677
- bgPrimary: "#faf0ca",
1678
- // Lemon Chiffon - main background
1679
- bgSecondary: "#ffffff",
1680
- // White - editor background
1681
- text: "#0d3b66",
1682
- // Yale Blue - main text
1683
- textPrimary: "#0d3b66",
1684
- // Yale Blue - primary text (same as text)
1685
- textSecondary: "#5a7a9b",
1686
- // Muted blue - secondary text
1687
- h1: "#f95738",
1688
- // Tomato - h1 headers
1689
- h2: "#ee964b",
1690
- // Sandy Brown - h2 headers
1691
- h3: "#3d8a51",
1692
- // Forest green - h3 headers
1693
- strong: "#ee964b",
1694
- // Sandy Brown - bold text
1695
- em: "#f95738",
1696
- // Tomato - italic text
1697
- del: "#ee964b",
1698
- // Sandy Brown - deleted text (same as strong)
1699
- link: "#0d3b66",
1700
- // Yale Blue - links
1701
- code: "#0d3b66",
1702
- // Yale Blue - inline code
1703
- codeBg: "rgba(244, 211, 94, 0.4)",
1704
- // Naples Yellow with transparency
1705
- blockquote: "#5a7a9b",
1706
- // Muted blue - blockquotes
1707
- hr: "#5a7a9b",
1708
- // Muted blue - horizontal rules
1709
- syntaxMarker: "rgba(13, 59, 102, 0.52)",
1710
- // Yale Blue with transparency
1711
- syntax: "#999999",
1712
- // Gray - syntax highlighting fallback
1713
- cursor: "#f95738",
1714
- // Tomato - cursor
1715
- selection: "rgba(244, 211, 94, 0.4)",
1716
- // Naples Yellow with transparency
1717
- listMarker: "#ee964b",
1718
- // Sandy Brown - list markers
1719
- rawLine: "#5a7a9b",
1720
- // Muted blue - raw line indicators
1721
- border: "#e0e0e0",
1722
- // Light gray - borders
1723
- hoverBg: "#f0f0f0",
1724
- // Very light gray - hover backgrounds
1725
- primary: "#0d3b66",
1726
- // Yale Blue - primary accent
1727
- // Toolbar colors
1728
- toolbarBg: "#ffffff",
1729
- // White - toolbar background
1730
- toolbarIcon: "#0d3b66",
1731
- // Yale Blue - icon color
1732
- toolbarHover: "#f5f5f5",
1733
- // Light gray - hover background
1734
- toolbarActive: "#faf0ca"
1735
- // Lemon Chiffon - active button background
1736
- }
1737
- };
1738
- var cave = {
1739
- name: "cave",
1740
- colors: {
1741
- bgPrimary: "#141E26",
1742
- // Deep ocean - main background
1743
- bgSecondary: "#1D2D3E",
1744
- // Darker charcoal - editor background
1745
- text: "#c5dde8",
1746
- // Light blue-gray - main text
1747
- textPrimary: "#c5dde8",
1748
- // Light blue-gray - primary text (same as text)
1749
- textSecondary: "#9fcfec",
1750
- // Brighter blue - secondary text
1751
- h1: "#d4a5ff",
1752
- // Rich lavender - h1 headers
1753
- h2: "#f6ae2d",
1754
- // Hunyadi Yellow - h2 headers
1755
- h3: "#9fcfec",
1756
- // Brighter blue - h3 headers
1757
- strong: "#f6ae2d",
1758
- // Hunyadi Yellow - bold text
1759
- em: "#9fcfec",
1760
- // Brighter blue - italic text
1761
- del: "#f6ae2d",
1762
- // Hunyadi Yellow - deleted text (same as strong)
1763
- link: "#9fcfec",
1764
- // Brighter blue - links
1765
- code: "#c5dde8",
1766
- // Light blue-gray - inline code
1767
- codeBg: "#1a232b",
1768
- // Very dark blue - code background
1769
- blockquote: "#9fcfec",
1770
- // Brighter blue - same as italic
1771
- hr: "#c5dde8",
1772
- // Light blue-gray - horizontal rules
1773
- syntaxMarker: "rgba(159, 207, 236, 0.73)",
1774
- // Brighter blue semi-transparent
1775
- syntax: "#7a8c98",
1776
- // Muted gray-blue - syntax highlighting fallback
1777
- cursor: "#f26419",
1778
- // Orange Pantone - cursor
1779
- selection: "rgba(51, 101, 138, 0.4)",
1780
- // Lapis Lazuli with transparency
1781
- listMarker: "#f6ae2d",
1782
- // Hunyadi Yellow - list markers
1783
- rawLine: "#9fcfec",
1784
- // Brighter blue - raw line indicators
1785
- border: "#2a3f52",
1786
- // Dark blue-gray - borders
1787
- hoverBg: "#243546",
1788
- // Slightly lighter charcoal - hover backgrounds
1789
- primary: "#9fcfec",
1790
- // Brighter blue - primary accent
1791
- // Toolbar colors for dark theme
1792
- toolbarBg: "#1D2D3E",
1793
- // Darker charcoal - toolbar background
1794
- toolbarIcon: "#c5dde8",
1795
- // Light blue-gray - icon color
1796
- toolbarHover: "#243546",
1797
- // Slightly lighter charcoal - hover background
1798
- toolbarActive: "#2a3f52"
1799
- // Even lighter - active button background
1800
- }
1801
- };
1802
- var themes = {
1803
- solar,
1804
- cave,
1805
- // Aliases for backward compatibility
1806
- light: solar,
1807
- dark: cave
1808
- };
1809
- function getTheme(theme) {
1810
- if (typeof theme === "string") {
1811
- const themeObj = themes[theme] || themes.solar;
1812
- return { ...themeObj, name: theme };
1813
- }
1814
- return theme;
1815
- }
1816
- function themeToCSSVars(colors) {
1817
- const vars = [];
1818
- for (const [key, value] of Object.entries(colors)) {
1819
- const varName = key.replace(/([A-Z])/g, "-$1").toLowerCase();
1820
- vars.push(`--${varName}: ${value};`);
1821
- }
1822
- return vars.join("\n");
1823
- }
1824
- function mergeTheme(baseTheme, customColors = {}) {
1825
- return {
1826
- ...baseTheme,
1827
- colors: {
1828
- ...baseTheme.colors,
1829
- ...customColors
1291
+ /* Code inside pre blocks - remove background */
1292
+ .overtype-wrapper .overtype-preview pre code {
1293
+ background: transparent !important;
1294
+ color: var(--code, #0d3b66) !important;
1295
+ font-family: ${fontFamily} !important; /* Match textarea font exactly for alignment */
1830
1296
  }
1831
- };
1832
- }
1833
1297
 
1834
- // src/styles.js
1835
- function generateStyles(options = {}) {
1836
- const {
1837
- fontSize = "14px",
1838
- lineHeight = 1.6,
1839
- /* System-first, guaranteed monospaced; avoids Android 'ui-monospace' pitfalls */
1840
- fontFamily = '"SF Mono", SFMono-Regular, Menlo, Monaco, "Cascadia Code", Consolas, "Roboto Mono", "Noto Sans Mono", "Droid Sans Mono", "Ubuntu Mono", "DejaVu Sans Mono", "Liberation Mono", "Courier New", Courier, monospace',
1841
- padding = "20px",
1842
- theme = null,
1843
- mobile = {}
1844
- } = options;
1845
- const mobileStyles = Object.keys(mobile).length > 0 ? `
1846
- @media (max-width: 640px) {
1847
- .overtype-wrapper .overtype-input,
1848
- .overtype-wrapper .overtype-preview {
1849
- ${Object.entries(mobile).map(([prop, val]) => {
1850
- const cssProp = prop.replace(/([A-Z])/g, "-$1").toLowerCase();
1851
- return `${cssProp}: ${val} !important;`;
1852
- }).join("\n ")}
1853
- }
1298
+ /* Blockquotes */
1299
+ .overtype-wrapper .overtype-preview .blockquote {
1300
+ color: var(--blockquote, #5a7a9b) !important;
1301
+ padding: 0 !important;
1302
+ margin: 0 !important;
1303
+ border: none !important;
1854
1304
  }
1855
- ` : "";
1856
- const themeVars = theme && theme.colors ? themeToCSSVars(theme.colors) : "";
1857
- return `
1858
- /* OverType Editor Styles */
1859
-
1860
- /* Middle-ground CSS Reset - Prevent parent styles from leaking in */
1861
- .overtype-container * {
1862
- /* Box model - these commonly leak */
1305
+
1306
+ /* Links */
1307
+ .overtype-wrapper .overtype-preview a {
1308
+ color: var(--link, #0d3b66) !important;
1309
+ text-decoration: underline !important;
1310
+ font-weight: normal !important;
1311
+ }
1312
+
1313
+ .overtype-wrapper .overtype-preview a:hover {
1314
+ text-decoration: underline !important;
1315
+ color: var(--link, #0d3b66) !important;
1316
+ }
1317
+
1318
+ /* Lists - no list styling */
1319
+ .overtype-wrapper .overtype-preview ul,
1320
+ .overtype-wrapper .overtype-preview ol {
1321
+ list-style: none !important;
1863
1322
  margin: 0 !important;
1864
1323
  padding: 0 !important;
1865
- border: 0 !important;
1866
-
1867
- /* Layout - these can break our layout */
1868
- /* Don't reset position - it breaks dropdowns */
1869
- float: none !important;
1870
- clear: none !important;
1871
-
1872
- /* Typography - only reset decorative aspects */
1873
- text-decoration: none !important;
1874
- text-transform: none !important;
1875
- letter-spacing: normal !important;
1876
-
1877
- /* Visual effects that can interfere */
1878
- box-shadow: none !important;
1879
- text-shadow: none !important;
1880
-
1881
- /* Ensure box-sizing is consistent */
1882
- box-sizing: border-box !important;
1883
-
1884
- /* Keep inheritance for these */
1885
- /* font-family, color, line-height, font-size - inherit */
1886
1324
  }
1887
-
1888
- /* Container base styles after reset */
1889
- .overtype-container {
1890
- display: flex !important;
1891
- flex-direction: column !important;
1892
- width: 100% !important;
1893
- height: 100% !important;
1894
- position: relative !important; /* Override reset - needed for absolute children */
1895
- overflow: visible !important; /* Allow dropdown to overflow container */
1896
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
1897
- text-align: left !important;
1898
- ${themeVars ? `
1899
- /* Theme Variables */
1900
- ${themeVars}` : ""}
1325
+
1326
+
1327
+ /* Horizontal rules */
1328
+ .overtype-wrapper .overtype-preview hr {
1329
+ border: none !important;
1330
+ color: var(--hr, #5a7a9b) !important;
1331
+ margin: 0 !important;
1332
+ padding: 0 !important;
1333
+ }
1334
+
1335
+ .overtype-wrapper .overtype-preview .hr-marker {
1336
+ color: var(--hr, #5a7a9b) !important;
1337
+ opacity: 0.6 !important;
1338
+ }
1339
+
1340
+ /* Code fence markers - with background when not in code block */
1341
+ .overtype-wrapper .overtype-preview .code-fence {
1342
+ color: var(--code, #0d3b66) !important;
1343
+ background: var(--code-bg, rgba(244, 211, 94, 0.4)) !important;
1901
1344
  }
1902
1345
 
1903
- /* Force left alignment for all elements in the editor */
1904
- .overtype-container .overtype-wrapper * {
1905
- text-align: left !important;
1346
+ /* Code block lines - background for entire code block */
1347
+ .overtype-wrapper .overtype-preview .code-block-line {
1348
+ background: var(--code-bg, rgba(244, 211, 94, 0.4)) !important;
1906
1349
  }
1907
1350
 
1908
- /* Auto-resize mode styles */
1909
- .overtype-container.overtype-auto-resize {
1910
- height: auto !important;
1351
+ /* Remove background from code fence when inside code block line */
1352
+ .overtype-wrapper .overtype-preview .code-block-line .code-fence {
1353
+ background: transparent !important;
1911
1354
  }
1912
1355
 
1913
- .overtype-container.overtype-auto-resize .overtype-wrapper {
1914
- flex: 0 0 auto !important; /* Don't grow/shrink, use explicit height */
1915
- height: auto !important;
1916
- min-height: 60px !important;
1917
- overflow: visible !important;
1356
+ /* Raw markdown line */
1357
+ .overtype-wrapper .overtype-preview .raw-line {
1358
+ color: var(--raw-line, #5a7a9b) !important;
1359
+ font-style: normal !important;
1360
+ font-weight: normal !important;
1918
1361
  }
1919
-
1920
- .overtype-wrapper {
1921
- position: relative !important; /* Override reset - needed for absolute children */
1922
- width: 100% !important;
1923
- flex: 1 1 0 !important; /* Grow to fill remaining space, with flex-basis: 0 */
1924
- min-height: 60px !important; /* Minimum usable height */
1925
- overflow: hidden !important;
1926
- background: var(--bg-secondary, #ffffff) !important;
1927
- z-index: 1; /* Below toolbar and dropdown */
1362
+
1363
+ /* Syntax markers */
1364
+ .overtype-wrapper .overtype-preview .syntax-marker {
1365
+ color: var(--syntax-marker, rgba(13, 59, 102, 0.52)) !important;
1366
+ opacity: 0.7 !important;
1928
1367
  }
1929
1368
 
1930
- /* Critical alignment styles - must be identical for both layers */
1931
- .overtype-wrapper .overtype-input,
1932
- .overtype-wrapper .overtype-preview {
1933
- /* Positioning - must be identical */
1934
- position: absolute !important; /* Override reset - required for overlay */
1935
- top: 0 !important;
1936
- left: 0 !important;
1937
- width: 100% !important;
1938
- height: 100% !important;
1939
-
1940
- /* Font properties - any difference breaks alignment */
1941
- font-family: ${fontFamily} !important;
1942
- font-variant-ligatures: none !important; /* keep metrics stable for code */
1943
- font-size: var(--instance-font-size, ${fontSize}) !important;
1944
- line-height: var(--instance-line-height, ${lineHeight}) !important;
1945
- font-weight: normal !important;
1946
- font-style: normal !important;
1947
- font-variant: normal !important;
1948
- font-stretch: normal !important;
1949
- font-kerning: none !important;
1950
- font-feature-settings: normal !important;
1951
-
1952
- /* Box model - must match exactly */
1953
- padding: var(--instance-padding, ${padding}) !important;
1954
- margin: 0 !important;
1955
- border: none !important;
1956
- outline: none !important;
1957
- box-sizing: border-box !important;
1958
-
1959
- /* Text layout - critical for character positioning */
1960
- white-space: pre-wrap !important;
1961
- word-wrap: break-word !important;
1962
- word-break: normal !important;
1963
- overflow-wrap: break-word !important;
1964
- tab-size: 2 !important;
1965
- -moz-tab-size: 2 !important;
1966
- text-align: left !important;
1967
- text-indent: 0 !important;
1968
- letter-spacing: normal !important;
1969
- word-spacing: normal !important;
1970
-
1971
- /* Text rendering */
1972
- text-transform: none !important;
1973
- text-rendering: auto !important;
1974
- -webkit-font-smoothing: auto !important;
1975
- -webkit-text-size-adjust: 100% !important;
1976
-
1977
- /* Direction and writing */
1978
- direction: ltr !important;
1979
- writing-mode: horizontal-tb !important;
1980
- unicode-bidi: normal !important;
1981
- text-orientation: mixed !important;
1982
-
1983
- /* Visual effects that could shift perception */
1984
- text-shadow: none !important;
1985
- filter: none !important;
1986
- transform: none !important;
1987
- zoom: 1 !important;
1988
-
1989
- /* Vertical alignment */
1990
- vertical-align: baseline !important;
1991
-
1992
- /* Size constraints */
1993
- min-width: 0 !important;
1994
- min-height: 0 !important;
1995
- max-width: none !important;
1996
- max-height: none !important;
1997
-
1998
- /* Overflow */
1999
- overflow-y: auto !important;
2000
- overflow-x: auto !important;
2001
- /* overscroll-behavior removed to allow scroll-through to parent */
2002
- scrollbar-width: auto !important;
2003
- scrollbar-gutter: auto !important;
2004
-
2005
- /* Animation/transition - disabled to prevent movement */
2006
- animation: none !important;
2007
- transition: none !important;
1369
+ /* List markers */
1370
+ .overtype-wrapper .overtype-preview .list-marker {
1371
+ color: var(--list-marker, #ee964b) !important;
1372
+ }
1373
+
1374
+ /* Stats bar */
1375
+
1376
+ /* Stats bar - positioned by flexbox */
1377
+ .overtype-stats {
1378
+ height: 40px !important;
1379
+ padding: 0 20px !important;
1380
+ background: #f8f9fa !important;
1381
+ border-top: 1px solid #e0e0e0 !important;
1382
+ display: flex !important;
1383
+ justify-content: space-between !important;
1384
+ align-items: center !important;
1385
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
1386
+ font-size: 0.85rem !important;
1387
+ color: #666 !important;
1388
+ flex-shrink: 0 !important; /* Don't shrink */
1389
+ z-index: 10001 !important; /* Above link tooltip */
1390
+ position: relative !important; /* Enable z-index */
1391
+ }
1392
+
1393
+ /* Dark theme stats bar */
1394
+ .overtype-container[data-theme="cave"] .overtype-stats {
1395
+ background: var(--bg-secondary, #1D2D3E) !important;
1396
+ border-top: 1px solid rgba(197, 221, 232, 0.1) !important;
1397
+ color: var(--text, #c5dde8) !important;
1398
+ }
1399
+
1400
+ .overtype-stats .overtype-stat {
1401
+ display: flex !important;
1402
+ align-items: center !important;
1403
+ gap: 5px !important;
1404
+ white-space: nowrap !important;
1405
+ }
1406
+
1407
+ .overtype-stats .live-dot {
1408
+ width: 8px !important;
1409
+ height: 8px !important;
1410
+ background: #4caf50 !important;
1411
+ border-radius: 50% !important;
1412
+ animation: overtype-pulse 2s infinite !important;
1413
+ }
1414
+
1415
+ @keyframes overtype-pulse {
1416
+ 0%, 100% { opacity: 1; transform: scale(1); }
1417
+ 50% { opacity: 0.6; transform: scale(1.2); }
2008
1418
  }
1419
+
2009
1420
 
2010
- /* Input layer styles */
2011
- .overtype-wrapper .overtype-input {
2012
- /* Layer positioning */
2013
- z-index: 1 !important;
2014
-
2015
- /* Text visibility */
2016
- color: transparent !important;
2017
- caret-color: var(--cursor, #f95738) !important;
2018
- background-color: transparent !important;
2019
-
2020
- /* Textarea-specific */
2021
- resize: none !important;
2022
- appearance: none !important;
2023
- -webkit-appearance: none !important;
2024
- -moz-appearance: none !important;
2025
-
2026
- /* Prevent mobile zoom on focus */
2027
- touch-action: manipulation !important;
2028
-
2029
- /* Disable autofill and spellcheck */
2030
- autocomplete: off !important;
2031
- autocorrect: off !important;
2032
- autocapitalize: off !important;
2033
- spellcheck: false !important;
1421
+ /* Toolbar Styles */
1422
+ .overtype-toolbar {
1423
+ display: flex !important;
1424
+ align-items: center !important;
1425
+ gap: 4px !important;
1426
+ padding: 8px !important; /* Override reset */
1427
+ background: var(--toolbar-bg, var(--bg-primary, #f8f9fa)) !important; /* Override reset */
1428
+ border-bottom: 1px solid var(--toolbar-border, transparent) !important; /* Override reset */
1429
+ overflow-x: auto !important; /* Allow horizontal scrolling */
1430
+ overflow-y: hidden !important; /* Hide vertical overflow */
1431
+ -webkit-overflow-scrolling: touch !important;
1432
+ flex-shrink: 0 !important;
1433
+ height: auto !important;
1434
+ position: relative !important; /* Override reset */
1435
+ z-index: 100 !important; /* Ensure toolbar is above wrapper */
1436
+ scrollbar-width: thin; /* Thin scrollbar on Firefox */
1437
+ }
1438
+
1439
+ /* Thin scrollbar styling */
1440
+ .overtype-toolbar::-webkit-scrollbar {
1441
+ height: 4px;
1442
+ }
1443
+
1444
+ .overtype-toolbar::-webkit-scrollbar-track {
1445
+ background: transparent;
1446
+ }
1447
+
1448
+ .overtype-toolbar::-webkit-scrollbar-thumb {
1449
+ background: rgba(0, 0, 0, 0.2);
1450
+ border-radius: 2px;
2034
1451
  }
2035
1452
 
2036
- .overtype-wrapper .overtype-input::selection {
2037
- background-color: var(--selection, rgba(244, 211, 94, 0.4));
1453
+ .overtype-toolbar-button {
1454
+ display: flex;
1455
+ align-items: center;
1456
+ justify-content: center;
1457
+ width: 32px;
1458
+ height: 32px;
1459
+ padding: 0;
1460
+ border: none;
1461
+ border-radius: 6px;
1462
+ background: transparent;
1463
+ color: var(--toolbar-icon, var(--text-secondary, #666));
1464
+ cursor: pointer;
1465
+ transition: all 0.2s ease;
1466
+ flex-shrink: 0;
2038
1467
  }
2039
1468
 
2040
- /* Preview layer styles */
2041
- .overtype-wrapper .overtype-preview {
2042
- /* Layer positioning */
2043
- z-index: 0 !important;
2044
- pointer-events: none !important;
2045
- color: var(--text, #0d3b66) !important;
2046
- background-color: transparent !important;
2047
-
2048
- /* Prevent text selection */
2049
- user-select: none !important;
2050
- -webkit-user-select: none !important;
2051
- -moz-user-select: none !important;
2052
- -ms-user-select: none !important;
1469
+ .overtype-toolbar-button svg {
1470
+ width: 20px;
1471
+ height: 20px;
1472
+ fill: currentColor;
2053
1473
  }
2054
1474
 
2055
- /* Defensive styles for preview child divs */
2056
- .overtype-wrapper .overtype-preview div {
2057
- /* Reset any inherited styles */
2058
- margin: 0 !important;
2059
- padding: 0 !important;
2060
- border: none !important;
2061
- text-align: left !important;
2062
- text-indent: 0 !important;
2063
- display: block !important;
2064
- position: static !important;
2065
- transform: none !important;
2066
- min-height: 0 !important;
2067
- max-height: none !important;
2068
- line-height: inherit !important;
2069
- font-size: inherit !important;
2070
- font-family: inherit !important;
1475
+ .overtype-toolbar-button:hover {
1476
+ background: var(--toolbar-hover, var(--bg-secondary, #e9ecef));
1477
+ color: var(--toolbar-icon, var(--text-primary, #333));
2071
1478
  }
2072
1479
 
2073
- /* Markdown element styling - NO SIZE CHANGES */
2074
- .overtype-wrapper .overtype-preview .header {
2075
- font-weight: bold !important;
1480
+ .overtype-toolbar-button:active {
1481
+ transform: scale(0.95);
2076
1482
  }
2077
1483
 
2078
- /* Header colors */
2079
- .overtype-wrapper .overtype-preview .h1 {
2080
- color: var(--h1, #f95738) !important;
1484
+ .overtype-toolbar-button.active {
1485
+ background: var(--toolbar-active, var(--primary, #007bff));
1486
+ color: var(--toolbar-icon, var(--text-primary, #333));
2081
1487
  }
2082
- .overtype-wrapper .overtype-preview .h2 {
2083
- color: var(--h2, #ee964b) !important;
1488
+
1489
+ .overtype-toolbar-button:disabled {
1490
+ opacity: 0.5;
1491
+ cursor: not-allowed;
2084
1492
  }
2085
- .overtype-wrapper .overtype-preview .h3 {
2086
- color: var(--h3, #3d8a51) !important;
1493
+
1494
+ .overtype-toolbar-separator {
1495
+ width: 1px;
1496
+ height: 24px;
1497
+ background: var(--border, #e0e0e0);
1498
+ margin: 0 4px;
1499
+ flex-shrink: 0;
2087
1500
  }
2088
1501
 
2089
- /* Semantic headers - flatten in edit mode */
2090
- .overtype-wrapper .overtype-preview h1,
2091
- .overtype-wrapper .overtype-preview h2,
2092
- .overtype-wrapper .overtype-preview h3 {
2093
- font-size: inherit !important;
2094
- font-weight: bold !important;
2095
- margin: 0 !important;
2096
- padding: 0 !important;
2097
- display: inline !important;
2098
- line-height: inherit !important;
1502
+ /* Adjust wrapper when toolbar is present */
1503
+ /* Mobile toolbar adjustments */
1504
+ @media (max-width: 640px) {
1505
+ .overtype-toolbar {
1506
+ padding: 6px;
1507
+ gap: 2px;
1508
+ }
1509
+
1510
+ .overtype-toolbar-button {
1511
+ width: 36px;
1512
+ height: 36px;
1513
+ }
1514
+
1515
+ .overtype-toolbar-separator {
1516
+ margin: 0 2px;
1517
+ }
1518
+ }
1519
+
1520
+ /* Plain mode - hide preview and show textarea text */
1521
+ .overtype-container[data-mode="plain"] .overtype-preview {
1522
+ display: none !important;
1523
+ }
1524
+
1525
+ .overtype-container[data-mode="plain"] .overtype-input {
1526
+ color: var(--text, #0d3b66) !important;
1527
+ /* Use system font stack for better plain text readability */
1528
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
1529
+ "Helvetica Neue", Arial, sans-serif !important;
1530
+ }
1531
+
1532
+ /* Ensure textarea remains transparent in overlay mode */
1533
+ .overtype-container:not([data-mode="plain"]) .overtype-input {
1534
+ color: transparent !important;
2099
1535
  }
2100
1536
 
2101
- /* Header colors for semantic headers */
2102
- .overtype-wrapper .overtype-preview h1 {
2103
- color: var(--h1, #f95738) !important;
1537
+ /* Dropdown menu styles */
1538
+ .overtype-toolbar-button {
1539
+ position: relative !important; /* Override reset - needed for dropdown */
2104
1540
  }
2105
- .overtype-wrapper .overtype-preview h2 {
2106
- color: var(--h2, #ee964b) !important;
1541
+
1542
+ .overtype-toolbar-button.dropdown-active {
1543
+ background: var(--toolbar-active, var(--hover-bg, #f0f0f0));
2107
1544
  }
2108
- .overtype-wrapper .overtype-preview h3 {
2109
- color: var(--h3, #3d8a51) !important;
1545
+
1546
+ .overtype-dropdown-menu {
1547
+ position: fixed !important; /* Fixed positioning relative to viewport */
1548
+ background: var(--bg-secondary, white) !important; /* Override reset */
1549
+ border: 1px solid var(--border, #e0e0e0) !important; /* Override reset */
1550
+ border-radius: 6px;
1551
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1) !important; /* Override reset */
1552
+ z-index: 10000; /* Very high z-index to ensure visibility */
1553
+ min-width: 150px;
1554
+ padding: 4px 0 !important; /* Override reset */
1555
+ /* Position will be set via JavaScript based on button position */
2110
1556
  }
2111
1557
 
2112
- /* Lists - remove styling in edit mode */
2113
- .overtype-wrapper .overtype-preview ul,
2114
- .overtype-wrapper .overtype-preview ol {
2115
- list-style: none !important;
2116
- margin: 0 !important;
2117
- padding: 0 !important;
2118
- display: block !important; /* Lists need to be block for line breaks */
1558
+ .overtype-dropdown-item {
1559
+ display: flex;
1560
+ align-items: center;
1561
+ width: 100%;
1562
+ padding: 8px 12px;
1563
+ border: none;
1564
+ background: none;
1565
+ text-align: left;
1566
+ cursor: pointer;
1567
+ font-size: 14px;
1568
+ color: var(--text, #333);
1569
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
2119
1570
  }
2120
1571
 
2121
- .overtype-wrapper .overtype-preview li {
2122
- display: block !important; /* Each item on its own line */
2123
- margin: 0 !important;
2124
- padding: 0 !important;
2125
- /* Don't set list-style here - let ul/ol control it */
1572
+ .overtype-dropdown-item:hover {
1573
+ background: var(--hover-bg, #f0f0f0);
2126
1574
  }
2127
1575
 
2128
- /* Bold text */
2129
- .overtype-wrapper .overtype-preview strong {
2130
- color: var(--strong, #ee964b) !important;
2131
- font-weight: bold !important;
1576
+ .overtype-dropdown-item.active {
1577
+ font-weight: 600;
1578
+ }
1579
+
1580
+ .overtype-dropdown-check {
1581
+ width: 16px;
1582
+ margin-right: 8px;
1583
+ color: var(--h1, #007bff);
2132
1584
  }
2133
1585
 
2134
- /* Italic text */
2135
- .overtype-wrapper .overtype-preview em {
2136
- color: var(--em, #f95738) !important;
2137
- text-decoration-color: var(--em, #f95738) !important;
2138
- text-decoration-thickness: 1px !important;
2139
- font-style: italic !important;
1586
+ .overtype-dropdown-icon {
1587
+ width: 20px;
1588
+ margin-right: 8px;
1589
+ text-align: center;
2140
1590
  }
2141
1591
 
2142
- /* Strikethrough text */
2143
- .overtype-wrapper .overtype-preview del {
2144
- color: var(--del, #ee964b) !important;
2145
- text-decoration: line-through !important;
2146
- text-decoration-color: var(--del, #ee964b) !important;
2147
- text-decoration-thickness: 1px !important;
1592
+ /* Preview mode styles */
1593
+ .overtype-container[data-mode="preview"] .overtype-input {
1594
+ display: none !important;
2148
1595
  }
2149
1596
 
2150
- /* Inline code */
2151
- .overtype-wrapper .overtype-preview code {
2152
- background: var(--code-bg, rgba(244, 211, 94, 0.4)) !important;
2153
- color: var(--code, #0d3b66) !important;
2154
- padding: 0 !important;
2155
- border-radius: 2px !important;
2156
- font-family: inherit !important;
2157
- font-size: inherit !important;
2158
- line-height: inherit !important;
2159
- font-weight: normal !important;
1597
+ .overtype-container[data-mode="preview"] .overtype-preview {
1598
+ pointer-events: auto !important;
1599
+ user-select: text !important;
1600
+ cursor: text !important;
2160
1601
  }
2161
1602
 
2162
- /* Code blocks - consolidated pre blocks */
2163
- .overtype-wrapper .overtype-preview pre {
2164
- padding: 0 !important;
2165
- margin: 0 !important;
2166
- border-radius: 4px !important;
2167
- overflow-x: auto !important;
1603
+ /* Hide syntax markers in preview mode */
1604
+ .overtype-container[data-mode="preview"] .syntax-marker {
1605
+ display: none !important;
2168
1606
  }
2169
1607
 
2170
- /* Code block styling in normal mode - yellow background */
2171
- .overtype-wrapper .overtype-preview pre.code-block {
2172
- background: var(--code-bg, rgba(244, 211, 94, 0.4)) !important;
2173
- white-space: break-spaces !important; /* Prevent horizontal scrollbar that breaks alignment */
1608
+ /* Hide URL part of links in preview mode - extra specificity */
1609
+ .overtype-container[data-mode="preview"] .syntax-marker.url-part,
1610
+ .overtype-container[data-mode="preview"] .url-part {
1611
+ display: none !important;
2174
1612
  }
2175
-
2176
- /* Code inside pre blocks - remove background */
2177
- .overtype-wrapper .overtype-preview pre code {
2178
- background: transparent !important;
2179
- color: var(--code, #0d3b66) !important;
2180
- font-family: ${fontFamily} !important; /* Match textarea font exactly for alignment */
1613
+
1614
+ /* Hide all syntax markers inside links too */
1615
+ .overtype-container[data-mode="preview"] a .syntax-marker {
1616
+ display: none !important;
2181
1617
  }
2182
1618
 
2183
- /* Blockquotes */
2184
- .overtype-wrapper .overtype-preview .blockquote {
2185
- color: var(--blockquote, #5a7a9b) !important;
2186
- padding: 0 !important;
1619
+ /* Headers - restore proper sizing in preview mode */
1620
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h1,
1621
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h2,
1622
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h3 {
1623
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
1624
+ font-weight: 600 !important;
2187
1625
  margin: 0 !important;
2188
- border: none !important;
1626
+ display: block !important;
1627
+ color: inherit !important; /* Use parent text color */
1628
+ line-height: 1 !important; /* Tight line height for headings */
2189
1629
  }
2190
-
2191
- /* Links */
2192
- .overtype-wrapper .overtype-preview a {
2193
- color: var(--link, #0d3b66) !important;
2194
- text-decoration: underline !important;
2195
- font-weight: normal !important;
1630
+
1631
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h1 {
1632
+ font-size: 2em !important;
2196
1633
  }
2197
-
2198
- .overtype-wrapper .overtype-preview a:hover {
2199
- text-decoration: underline !important;
2200
- color: var(--link, #0d3b66) !important;
1634
+
1635
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h2 {
1636
+ font-size: 1.5em !important;
2201
1637
  }
2202
-
2203
- /* Lists - no list styling */
2204
- .overtype-wrapper .overtype-preview ul,
2205
- .overtype-wrapper .overtype-preview ol {
2206
- list-style: none !important;
2207
- margin: 0 !important;
2208
- padding: 0 !important;
1638
+
1639
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h3 {
1640
+ font-size: 1.17em !important;
2209
1641
  }
2210
1642
 
1643
+ /* Lists - restore list styling in preview mode */
1644
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview ul {
1645
+ display: block !important;
1646
+ list-style: disc !important;
1647
+ padding-left: 2em !important;
1648
+ margin: 1em 0 !important;
1649
+ }
2211
1650
 
2212
- /* Horizontal rules */
2213
- .overtype-wrapper .overtype-preview hr {
2214
- border: none !important;
2215
- color: var(--hr, #5a7a9b) !important;
1651
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview ol {
1652
+ display: block !important;
1653
+ list-style: decimal !important;
1654
+ padding-left: 2em !important;
1655
+ margin: 1em 0 !important;
1656
+ }
1657
+
1658
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview li {
1659
+ display: list-item !important;
2216
1660
  margin: 0 !important;
2217
1661
  padding: 0 !important;
2218
1662
  }
2219
1663
 
2220
- .overtype-wrapper .overtype-preview .hr-marker {
2221
- color: var(--hr, #5a7a9b) !important;
2222
- opacity: 0.6 !important;
1664
+ /* Task list checkboxes - only in preview mode */
1665
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview li.task-list {
1666
+ list-style: none !important;
1667
+ position: relative !important;
2223
1668
  }
2224
1669
 
2225
- /* Code fence markers - with background when not in code block */
2226
- .overtype-wrapper .overtype-preview .code-fence {
2227
- color: var(--code, #0d3b66) !important;
2228
- background: var(--code-bg, rgba(244, 211, 94, 0.4)) !important;
2229
- }
2230
-
2231
- /* Code block lines - background for entire code block */
2232
- .overtype-wrapper .overtype-preview .code-block-line {
2233
- background: var(--code-bg, rgba(244, 211, 94, 0.4)) !important;
2234
- }
2235
-
2236
- /* Remove background from code fence when inside code block line */
2237
- .overtype-wrapper .overtype-preview .code-block-line .code-fence {
2238
- background: transparent !important;
1670
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview li.task-list input[type="checkbox"] {
1671
+ margin-right: 0.5em !important;
1672
+ cursor: default !important;
1673
+ vertical-align: middle !important;
2239
1674
  }
2240
1675
 
2241
- /* Raw markdown line */
2242
- .overtype-wrapper .overtype-preview .raw-line {
2243
- color: var(--raw-line, #5a7a9b) !important;
2244
- font-style: normal !important;
2245
- font-weight: normal !important;
1676
+ /* Task list in normal mode - keep syntax visible */
1677
+ .overtype-container:not([data-mode="preview"]) .overtype-wrapper .overtype-preview li.task-list {
1678
+ list-style: none !important;
2246
1679
  }
2247
1680
 
2248
- /* Syntax markers */
2249
- .overtype-wrapper .overtype-preview .syntax-marker {
2250
- color: var(--syntax-marker, rgba(13, 59, 102, 0.52)) !important;
2251
- opacity: 0.7 !important;
1681
+ .overtype-container:not([data-mode="preview"]) .overtype-wrapper .overtype-preview li.task-list .syntax-marker {
1682
+ color: var(--syntax, #999999) !important;
1683
+ font-weight: normal !important;
2252
1684
  }
2253
1685
 
2254
- /* List markers */
2255
- .overtype-wrapper .overtype-preview .list-marker {
2256
- color: var(--list-marker, #ee964b) !important;
1686
+ /* Links - make clickable in preview mode */
1687
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview a {
1688
+ pointer-events: auto !important;
1689
+ cursor: pointer !important;
1690
+ color: var(--link, #0066cc) !important;
1691
+ text-decoration: underline !important;
2257
1692
  }
2258
1693
 
2259
- /* Stats bar */
2260
-
2261
- /* Stats bar - positioned by flexbox */
2262
- .overtype-stats {
2263
- height: 40px !important;
2264
- padding: 0 20px !important;
2265
- background: #f8f9fa !important;
2266
- border-top: 1px solid #e0e0e0 !important;
2267
- display: flex !important;
2268
- justify-content: space-between !important;
2269
- align-items: center !important;
2270
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
2271
- font-size: 0.85rem !important;
2272
- color: #666 !important;
2273
- flex-shrink: 0 !important; /* Don't shrink */
2274
- z-index: 10001 !important; /* Above link tooltip */
2275
- position: relative !important; /* Enable z-index */
1694
+ /* Code blocks - proper pre/code styling in preview mode */
1695
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview pre.code-block {
1696
+ background: #2d2d2d !important;
1697
+ color: #f8f8f2 !important;
1698
+ padding: 1.2em !important;
1699
+ border-radius: 3px !important;
1700
+ overflow-x: auto !important;
1701
+ margin: 0 !important;
1702
+ display: block !important;
2276
1703
  }
2277
1704
 
2278
- /* Dark theme stats bar */
2279
- .overtype-container[data-theme="cave"] .overtype-stats {
2280
- background: var(--bg-secondary, #1D2D3E) !important;
2281
- border-top: 1px solid rgba(197, 221, 232, 0.1) !important;
2282
- color: var(--text, #c5dde8) !important;
1705
+ /* Cave theme code block background in preview mode */
1706
+ .overtype-container[data-theme="cave"][data-mode="preview"] .overtype-wrapper .overtype-preview pre.code-block {
1707
+ background: #11171F !important;
2283
1708
  }
2284
-
2285
- .overtype-stats .overtype-stat {
2286
- display: flex !important;
2287
- align-items: center !important;
2288
- gap: 5px !important;
2289
- white-space: nowrap !important;
1709
+
1710
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview pre.code-block code {
1711
+ background: transparent !important;
1712
+ color: inherit !important;
1713
+ padding: 0 !important;
1714
+ font-family: ${fontFamily} !important;
1715
+ font-size: 0.9em !important;
1716
+ line-height: 1.4 !important;
2290
1717
  }
2291
-
2292
- .overtype-stats .live-dot {
2293
- width: 8px !important;
2294
- height: 8px !important;
2295
- background: #4caf50 !important;
2296
- border-radius: 50% !important;
2297
- animation: overtype-pulse 2s infinite !important;
1718
+
1719
+ /* Hide old code block lines and fences in preview mode */
1720
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview .code-block-line {
1721
+ display: none !important;
2298
1722
  }
2299
-
2300
- @keyframes overtype-pulse {
2301
- 0%, 100% { opacity: 1; transform: scale(1); }
2302
- 50% { opacity: 0.6; transform: scale(1.2); }
1723
+
1724
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview .code-fence {
1725
+ display: none !important;
2303
1726
  }
2304
-
2305
1727
 
2306
- /* Toolbar Styles */
2307
- .overtype-toolbar {
2308
- display: flex !important;
2309
- align-items: center !important;
2310
- gap: 4px !important;
2311
- padding: 8px !important; /* Override reset */
2312
- background: var(--toolbar-bg, var(--bg-primary, #f8f9fa)) !important; /* Override reset */
2313
- border-bottom: 1px solid var(--toolbar-border, transparent) !important; /* Override reset */
2314
- overflow-x: auto !important; /* Allow horizontal scrolling */
2315
- overflow-y: hidden !important; /* Hide vertical overflow */
2316
- -webkit-overflow-scrolling: touch !important;
2317
- flex-shrink: 0 !important;
2318
- height: auto !important;
2319
- position: relative !important; /* Override reset */
2320
- z-index: 100 !important; /* Ensure toolbar is above wrapper */
2321
- scrollbar-width: thin; /* Thin scrollbar on Firefox */
1728
+ /* Blockquotes - enhanced styling in preview mode */
1729
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview .blockquote {
1730
+ display: block !important;
1731
+ border-left: 4px solid var(--blockquote, #ddd) !important;
1732
+ padding-left: 1em !important;
1733
+ margin: 1em 0 !important;
1734
+ font-style: italic !important;
2322
1735
  }
2323
-
2324
- /* Thin scrollbar styling */
2325
- .overtype-toolbar::-webkit-scrollbar {
2326
- height: 4px;
1736
+
1737
+ /* Typography improvements in preview mode */
1738
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview {
1739
+ font-family: Georgia, 'Times New Roman', serif !important;
1740
+ font-size: 16px !important;
1741
+ line-height: 1.8 !important;
1742
+ color: var(--text, #333) !important; /* Consistent text color */
2327
1743
  }
2328
-
2329
- .overtype-toolbar::-webkit-scrollbar-track {
2330
- background: transparent;
1744
+
1745
+ /* Inline code in preview mode - keep monospace */
1746
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview code {
1747
+ font-family: ${fontFamily} !important;
1748
+ font-size: 0.9em !important;
1749
+ background: rgba(135, 131, 120, 0.15) !important;
1750
+ padding: 0.2em 0.4em !important;
1751
+ border-radius: 3px !important;
2331
1752
  }
2332
-
2333
- .overtype-toolbar::-webkit-scrollbar-thumb {
2334
- background: rgba(0, 0, 0, 0.2);
2335
- border-radius: 2px;
1753
+
1754
+ /* Strong and em elements in preview mode */
1755
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview strong {
1756
+ font-weight: 700 !important;
1757
+ color: inherit !important; /* Use parent text color */
2336
1758
  }
2337
1759
 
2338
- .overtype-toolbar-button {
2339
- display: flex;
2340
- align-items: center;
2341
- justify-content: center;
2342
- width: 32px;
2343
- height: 32px;
2344
- padding: 0;
2345
- border: none;
2346
- border-radius: 6px;
2347
- background: transparent;
2348
- color: var(--toolbar-icon, var(--text-secondary, #666));
2349
- cursor: pointer;
2350
- transition: all 0.2s ease;
2351
- flex-shrink: 0;
1760
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview em {
1761
+ font-style: italic !important;
1762
+ color: inherit !important; /* Use parent text color */
2352
1763
  }
2353
1764
 
2354
- .overtype-toolbar-button svg {
2355
- width: 20px;
2356
- height: 20px;
2357
- fill: currentColor;
1765
+ /* HR in preview mode */
1766
+ .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview .hr-marker {
1767
+ display: block !important;
1768
+ border-top: 2px solid var(--hr, #ddd) !important;
1769
+ text-indent: -9999px !important;
1770
+ height: 2px !important;
2358
1771
  }
2359
1772
 
2360
- .overtype-toolbar-button:hover {
2361
- background: var(--toolbar-hover, var(--bg-secondary, #e9ecef));
2362
- color: var(--toolbar-icon, var(--text-primary, #333));
1773
+ /* Link Tooltip - Base styles (all browsers) */
1774
+ .overtype-link-tooltip {
1775
+ /* Visual styles that work for both positioning methods */
1776
+ background: #333 !important;
1777
+ color: white !important;
1778
+ padding: 6px 10px !important;
1779
+ border-radius: 16px !important;
1780
+ font-size: 12px !important;
1781
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
1782
+ display: none !important;
1783
+ z-index: 10000 !important;
1784
+ cursor: pointer !important;
1785
+ box-shadow: 0 2px 8px rgba(0,0,0,0.3) !important;
1786
+ max-width: 300px !important;
1787
+ white-space: nowrap !important;
1788
+ overflow: hidden !important;
1789
+ text-overflow: ellipsis !important;
1790
+
1791
+ /* Base positioning for Floating UI fallback */
1792
+ position: absolute;
2363
1793
  }
2364
1794
 
2365
- .overtype-toolbar-button:active {
2366
- transform: scale(0.95);
1795
+ .overtype-link-tooltip.visible {
1796
+ display: flex !important;
2367
1797
  }
2368
1798
 
2369
- .overtype-toolbar-button.active {
2370
- background: var(--toolbar-active, var(--primary, #007bff));
2371
- color: var(--toolbar-icon, var(--text-primary, #333));
1799
+ /* CSS Anchor Positioning (modern browsers only) */
1800
+ @supports (position-anchor: --x) and (position-area: center) {
1801
+ .overtype-link-tooltip {
1802
+ /* Only anchor positioning specific properties */
1803
+ position-anchor: var(--target-anchor, --link-0);
1804
+ position-area: block-end center;
1805
+ margin-top: 8px !important;
1806
+ position-try: most-width block-end inline-end, flip-inline, block-start center;
1807
+ position-visibility: anchors-visible;
1808
+ }
2372
1809
  }
2373
1810
 
2374
- .overtype-toolbar-button:disabled {
2375
- opacity: 0.5;
2376
- cursor: not-allowed;
1811
+ ${mobileStyles}
1812
+ `;
1813
+ }
1814
+
1815
+ // node_modules/markdown-actions/dist/markdown-actions.esm.js
1816
+ var __defProp2 = Object.defineProperty;
1817
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
1818
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
1819
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
1820
+ var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1821
+ var __spreadValues = (a, b) => {
1822
+ for (var prop in b || (b = {}))
1823
+ if (__hasOwnProp.call(b, prop))
1824
+ __defNormalProp2(a, prop, b[prop]);
1825
+ if (__getOwnPropSymbols)
1826
+ for (var prop of __getOwnPropSymbols(b)) {
1827
+ if (__propIsEnum.call(b, prop))
1828
+ __defNormalProp2(a, prop, b[prop]);
1829
+ }
1830
+ return a;
1831
+ };
1832
+ var FORMATS = {
1833
+ bold: {
1834
+ prefix: "**",
1835
+ suffix: "**",
1836
+ trimFirst: true
1837
+ },
1838
+ italic: {
1839
+ prefix: "_",
1840
+ suffix: "_",
1841
+ trimFirst: true
1842
+ },
1843
+ code: {
1844
+ prefix: "`",
1845
+ suffix: "`",
1846
+ blockPrefix: "```",
1847
+ blockSuffix: "```"
1848
+ },
1849
+ link: {
1850
+ prefix: "[",
1851
+ suffix: "](url)",
1852
+ replaceNext: "url",
1853
+ scanFor: "https?://"
1854
+ },
1855
+ bulletList: {
1856
+ prefix: "- ",
1857
+ multiline: true,
1858
+ unorderedList: true
1859
+ },
1860
+ numberedList: {
1861
+ prefix: "1. ",
1862
+ multiline: true,
1863
+ orderedList: true
1864
+ },
1865
+ quote: {
1866
+ prefix: "> ",
1867
+ multiline: true,
1868
+ surroundWithNewlines: true
1869
+ },
1870
+ taskList: {
1871
+ prefix: "- [ ] ",
1872
+ multiline: true,
1873
+ surroundWithNewlines: true
1874
+ },
1875
+ header1: { prefix: "# " },
1876
+ header2: { prefix: "## " },
1877
+ header3: { prefix: "### " },
1878
+ header4: { prefix: "#### " },
1879
+ header5: { prefix: "##### " },
1880
+ header6: { prefix: "###### " }
1881
+ };
1882
+ function getDefaultStyle() {
1883
+ return {
1884
+ prefix: "",
1885
+ suffix: "",
1886
+ blockPrefix: "",
1887
+ blockSuffix: "",
1888
+ multiline: false,
1889
+ replaceNext: "",
1890
+ prefixSpace: false,
1891
+ scanFor: "",
1892
+ surroundWithNewlines: false,
1893
+ orderedList: false,
1894
+ unorderedList: false,
1895
+ trimFirst: false
1896
+ };
1897
+ }
1898
+ function mergeWithDefaults(format) {
1899
+ return __spreadValues(__spreadValues({}, getDefaultStyle()), format);
1900
+ }
1901
+ var debugMode = false;
1902
+ function getDebugMode() {
1903
+ return debugMode;
1904
+ }
1905
+ function debugLog(funcName, message, data) {
1906
+ if (!debugMode)
1907
+ return;
1908
+ console.group(`\u{1F50D} ${funcName}`);
1909
+ console.log(message);
1910
+ if (data) {
1911
+ console.log("Data:", data);
1912
+ }
1913
+ console.groupEnd();
1914
+ }
1915
+ function debugSelection(textarea, label) {
1916
+ if (!debugMode)
1917
+ return;
1918
+ const selected = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
1919
+ console.group(`\u{1F4CD} Selection: ${label}`);
1920
+ console.log("Position:", `${textarea.selectionStart}-${textarea.selectionEnd}`);
1921
+ console.log("Selected text:", JSON.stringify(selected));
1922
+ console.log("Length:", selected.length);
1923
+ const before = textarea.value.slice(Math.max(0, textarea.selectionStart - 10), textarea.selectionStart);
1924
+ const after = textarea.value.slice(textarea.selectionEnd, Math.min(textarea.value.length, textarea.selectionEnd + 10));
1925
+ console.log("Context:", JSON.stringify(before) + "[SELECTION]" + JSON.stringify(after));
1926
+ console.groupEnd();
1927
+ }
1928
+ function debugResult(result) {
1929
+ if (!debugMode)
1930
+ return;
1931
+ console.group("\u{1F4DD} Result");
1932
+ console.log("Text to insert:", JSON.stringify(result.text));
1933
+ console.log("New selection:", `${result.selectionStart}-${result.selectionEnd}`);
1934
+ console.groupEnd();
1935
+ }
1936
+ var canInsertText = null;
1937
+ function insertText(textarea, { text, selectionStart, selectionEnd }) {
1938
+ const debugMode2 = getDebugMode();
1939
+ if (debugMode2) {
1940
+ console.group("\u{1F527} insertText");
1941
+ console.log("Current selection:", `${textarea.selectionStart}-${textarea.selectionEnd}`);
1942
+ console.log("Text to insert:", JSON.stringify(text));
1943
+ console.log("New selection to set:", selectionStart, "-", selectionEnd);
1944
+ }
1945
+ textarea.focus();
1946
+ const originalSelectionStart = textarea.selectionStart;
1947
+ const originalSelectionEnd = textarea.selectionEnd;
1948
+ const before = textarea.value.slice(0, originalSelectionStart);
1949
+ const after = textarea.value.slice(originalSelectionEnd);
1950
+ if (debugMode2) {
1951
+ console.log("Before text (last 20):", JSON.stringify(before.slice(-20)));
1952
+ console.log("After text (first 20):", JSON.stringify(after.slice(0, 20)));
1953
+ console.log("Selected text being replaced:", JSON.stringify(textarea.value.slice(originalSelectionStart, originalSelectionEnd)));
1954
+ }
1955
+ const originalValue = textarea.value;
1956
+ const hasSelection = originalSelectionStart !== originalSelectionEnd;
1957
+ if (canInsertText === null || canInsertText === true) {
1958
+ textarea.contentEditable = "true";
1959
+ try {
1960
+ canInsertText = document.execCommand("insertText", false, text);
1961
+ if (debugMode2)
1962
+ console.log("execCommand returned:", canInsertText, "for text with", text.split("\n").length, "lines");
1963
+ } catch (error) {
1964
+ canInsertText = false;
1965
+ if (debugMode2)
1966
+ console.log("execCommand threw error:", error);
2377
1967
  }
2378
-
2379
- .overtype-toolbar-separator {
2380
- width: 1px;
2381
- height: 24px;
2382
- background: var(--border, #e0e0e0);
2383
- margin: 0 4px;
2384
- flex-shrink: 0;
1968
+ textarea.contentEditable = "false";
1969
+ }
1970
+ if (debugMode2) {
1971
+ console.log("canInsertText before:", canInsertText);
1972
+ console.log("execCommand result:", canInsertText);
1973
+ }
1974
+ if (canInsertText) {
1975
+ const expectedValue = before + text + after;
1976
+ const actualValue = textarea.value;
1977
+ if (debugMode2) {
1978
+ console.log("Expected length:", expectedValue.length);
1979
+ console.log("Actual length:", actualValue.length);
2385
1980
  }
2386
-
2387
- /* Adjust wrapper when toolbar is present */
2388
- /* Mobile toolbar adjustments */
2389
- @media (max-width: 640px) {
2390
- .overtype-toolbar {
2391
- padding: 6px;
2392
- gap: 2px;
1981
+ if (actualValue !== expectedValue) {
1982
+ if (debugMode2) {
1983
+ console.log("execCommand changed the value but not as expected");
1984
+ console.log("Expected:", JSON.stringify(expectedValue.slice(0, 100)));
1985
+ console.log("Actual:", JSON.stringify(actualValue.slice(0, 100)));
2393
1986
  }
2394
-
2395
- .overtype-toolbar-button {
2396
- width: 36px;
2397
- height: 36px;
1987
+ }
1988
+ }
1989
+ if (!canInsertText) {
1990
+ if (debugMode2)
1991
+ console.log("Using manual insertion");
1992
+ if (textarea.value === originalValue) {
1993
+ if (debugMode2)
1994
+ console.log("Value unchanged, doing manual replacement");
1995
+ try {
1996
+ document.execCommand("ms-beginUndoUnit");
1997
+ } catch (e) {
2398
1998
  }
2399
-
2400
- .overtype-toolbar-separator {
2401
- margin: 0 2px;
1999
+ textarea.value = before + text + after;
2000
+ try {
2001
+ document.execCommand("ms-endUndoUnit");
2002
+ } catch (e) {
2402
2003
  }
2004
+ textarea.dispatchEvent(new CustomEvent("input", { bubbles: true, cancelable: true }));
2005
+ } else {
2006
+ if (debugMode2)
2007
+ console.log("Value was changed by execCommand, skipping manual insertion");
2403
2008
  }
2404
-
2405
- /* Plain mode - hide preview and show textarea text */
2406
- .overtype-container[data-mode="plain"] .overtype-preview {
2407
- display: none !important;
2408
- }
2409
-
2410
- .overtype-container[data-mode="plain"] .overtype-input {
2411
- color: var(--text, #0d3b66) !important;
2412
- /* Use system font stack for better plain text readability */
2413
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
2414
- "Helvetica Neue", Arial, sans-serif !important;
2415
- }
2416
-
2417
- /* Ensure textarea remains transparent in overlay mode */
2418
- .overtype-container:not([data-mode="plain"]) .overtype-input {
2419
- color: transparent !important;
2420
- }
2421
-
2422
- /* Dropdown menu styles */
2423
- .overtype-toolbar-button {
2424
- position: relative !important; /* Override reset - needed for dropdown */
2425
- }
2426
-
2427
- .overtype-toolbar-button.dropdown-active {
2428
- background: var(--toolbar-active, var(--hover-bg, #f0f0f0));
2429
- }
2430
-
2431
- .overtype-dropdown-menu {
2432
- position: fixed !important; /* Fixed positioning relative to viewport */
2433
- background: var(--bg-secondary, white) !important; /* Override reset */
2434
- border: 1px solid var(--border, #e0e0e0) !important; /* Override reset */
2435
- border-radius: 6px;
2436
- box-shadow: 0 2px 8px rgba(0,0,0,0.1) !important; /* Override reset */
2437
- z-index: 10000; /* Very high z-index to ensure visibility */
2438
- min-width: 150px;
2439
- padding: 4px 0 !important; /* Override reset */
2440
- /* Position will be set via JavaScript based on button position */
2441
- }
2442
-
2443
- .overtype-dropdown-item {
2444
- display: flex;
2445
- align-items: center;
2446
- width: 100%;
2447
- padding: 8px 12px;
2448
- border: none;
2449
- background: none;
2450
- text-align: left;
2451
- cursor: pointer;
2452
- font-size: 14px;
2453
- color: var(--text, #333);
2454
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
2455
- }
2456
-
2457
- .overtype-dropdown-item:hover {
2458
- background: var(--hover-bg, #f0f0f0);
2459
- }
2460
-
2461
- .overtype-dropdown-item.active {
2462
- font-weight: 600;
2463
- }
2464
-
2465
- .overtype-dropdown-check {
2466
- width: 16px;
2467
- margin-right: 8px;
2468
- color: var(--h1, #007bff);
2469
- }
2470
-
2471
- .overtype-dropdown-icon {
2472
- width: 20px;
2473
- margin-right: 8px;
2474
- text-align: center;
2475
- }
2476
-
2477
- /* Preview mode styles */
2478
- .overtype-container[data-mode="preview"] .overtype-input {
2479
- display: none !important;
2480
- }
2481
-
2482
- .overtype-container[data-mode="preview"] .overtype-preview {
2483
- pointer-events: auto !important;
2484
- user-select: text !important;
2485
- cursor: text !important;
2486
- }
2487
-
2488
- /* Hide syntax markers in preview mode */
2489
- .overtype-container[data-mode="preview"] .syntax-marker {
2490
- display: none !important;
2491
- }
2492
-
2493
- /* Hide URL part of links in preview mode - extra specificity */
2494
- .overtype-container[data-mode="preview"] .syntax-marker.url-part,
2495
- .overtype-container[data-mode="preview"] .url-part {
2496
- display: none !important;
2497
- }
2498
-
2499
- /* Hide all syntax markers inside links too */
2500
- .overtype-container[data-mode="preview"] a .syntax-marker {
2501
- display: none !important;
2502
- }
2503
-
2504
- /* Headers - restore proper sizing in preview mode */
2505
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h1,
2506
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h2,
2507
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h3 {
2508
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
2509
- font-weight: 600 !important;
2510
- margin: 0 !important;
2511
- display: block !important;
2512
- color: inherit !important; /* Use parent text color */
2513
- line-height: 1 !important; /* Tight line height for headings */
2514
- }
2515
-
2516
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h1 {
2517
- font-size: 2em !important;
2518
- }
2519
-
2520
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h2 {
2521
- font-size: 1.5em !important;
2522
- }
2523
-
2524
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h3 {
2525
- font-size: 1.17em !important;
2526
- }
2527
-
2528
- /* Lists - restore list styling in preview mode */
2529
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview ul {
2530
- display: block !important;
2531
- list-style: disc !important;
2532
- padding-left: 2em !important;
2533
- margin: 1em 0 !important;
2534
- }
2535
-
2536
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview ol {
2537
- display: block !important;
2538
- list-style: decimal !important;
2539
- padding-left: 2em !important;
2540
- margin: 1em 0 !important;
2541
- }
2542
-
2543
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview li {
2544
- display: list-item !important;
2545
- margin: 0 !important;
2546
- padding: 0 !important;
2547
- }
2548
-
2549
- /* Task list checkboxes - only in preview mode */
2550
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview li.task-list {
2551
- list-style: none !important;
2552
- position: relative !important;
2009
+ }
2010
+ if (debugMode2)
2011
+ console.log("Setting selection range:", selectionStart, selectionEnd);
2012
+ if (selectionStart != null && selectionEnd != null) {
2013
+ textarea.setSelectionRange(selectionStart, selectionEnd);
2014
+ } else {
2015
+ textarea.setSelectionRange(originalSelectionStart, textarea.selectionEnd);
2016
+ }
2017
+ if (debugMode2) {
2018
+ console.log("Final value length:", textarea.value.length);
2019
+ console.groupEnd();
2020
+ }
2021
+ }
2022
+ function isMultipleLines(string) {
2023
+ return string.trim().split("\n").length > 1;
2024
+ }
2025
+ function wordSelectionStart(text, i) {
2026
+ let index = i;
2027
+ while (text[index] && text[index - 1] != null && !text[index - 1].match(/\s/)) {
2028
+ index--;
2029
+ }
2030
+ return index;
2031
+ }
2032
+ function wordSelectionEnd(text, i, multiline) {
2033
+ let index = i;
2034
+ const breakpoint = multiline ? /\n/ : /\s/;
2035
+ while (text[index] && !text[index].match(breakpoint)) {
2036
+ index++;
2037
+ }
2038
+ return index;
2039
+ }
2040
+ function expandSelectionToLine(textarea) {
2041
+ const lines = textarea.value.split("\n");
2042
+ let counter = 0;
2043
+ for (let index = 0; index < lines.length; index++) {
2044
+ const lineLength = lines[index].length + 1;
2045
+ if (textarea.selectionStart >= counter && textarea.selectionStart < counter + lineLength) {
2046
+ textarea.selectionStart = counter;
2553
2047
  }
2554
-
2555
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview li.task-list input[type="checkbox"] {
2556
- margin-right: 0.5em !important;
2557
- cursor: default !important;
2558
- vertical-align: middle !important;
2048
+ if (textarea.selectionEnd >= counter && textarea.selectionEnd < counter + lineLength) {
2049
+ if (index === lines.length - 1) {
2050
+ textarea.selectionEnd = Math.min(counter + lines[index].length, textarea.value.length);
2051
+ } else {
2052
+ textarea.selectionEnd = counter + lineLength - 1;
2053
+ }
2559
2054
  }
2560
-
2561
- /* Task list in normal mode - keep syntax visible */
2562
- .overtype-container:not([data-mode="preview"]) .overtype-wrapper .overtype-preview li.task-list {
2563
- list-style: none !important;
2055
+ counter += lineLength;
2056
+ }
2057
+ }
2058
+ function expandSelectedText(textarea, prefixToUse, suffixToUse, multiline = false) {
2059
+ if (textarea.selectionStart === textarea.selectionEnd) {
2060
+ textarea.selectionStart = wordSelectionStart(textarea.value, textarea.selectionStart);
2061
+ textarea.selectionEnd = wordSelectionEnd(textarea.value, textarea.selectionEnd, multiline);
2062
+ } else {
2063
+ const expandedSelectionStart = textarea.selectionStart - prefixToUse.length;
2064
+ const expandedSelectionEnd = textarea.selectionEnd + suffixToUse.length;
2065
+ const beginsWithPrefix = textarea.value.slice(expandedSelectionStart, textarea.selectionStart) === prefixToUse;
2066
+ const endsWithSuffix = textarea.value.slice(textarea.selectionEnd, expandedSelectionEnd) === suffixToUse;
2067
+ if (beginsWithPrefix && endsWithSuffix) {
2068
+ textarea.selectionStart = expandedSelectionStart;
2069
+ textarea.selectionEnd = expandedSelectionEnd;
2564
2070
  }
2565
-
2566
- .overtype-container:not([data-mode="preview"]) .overtype-wrapper .overtype-preview li.task-list .syntax-marker {
2567
- color: var(--syntax, #999999) !important;
2568
- font-weight: normal !important;
2071
+ }
2072
+ return textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
2073
+ }
2074
+ function newlinesToSurroundSelectedText(textarea) {
2075
+ const beforeSelection = textarea.value.slice(0, textarea.selectionStart);
2076
+ const afterSelection = textarea.value.slice(textarea.selectionEnd);
2077
+ const breaksBefore = beforeSelection.match(/\n*$/);
2078
+ const breaksAfter = afterSelection.match(/^\n*/);
2079
+ const newlinesBeforeSelection = breaksBefore ? breaksBefore[0].length : 0;
2080
+ const newlinesAfterSelection = breaksAfter ? breaksAfter[0].length : 0;
2081
+ let newlinesToAppend = "";
2082
+ let newlinesToPrepend = "";
2083
+ if (beforeSelection.match(/\S/) && newlinesBeforeSelection < 2) {
2084
+ newlinesToAppend = "\n".repeat(2 - newlinesBeforeSelection);
2085
+ }
2086
+ if (afterSelection.match(/\S/) && newlinesAfterSelection < 2) {
2087
+ newlinesToPrepend = "\n".repeat(2 - newlinesAfterSelection);
2088
+ }
2089
+ return { newlinesToAppend, newlinesToPrepend };
2090
+ }
2091
+ function applyLineOperation(textarea, operation, options = {}) {
2092
+ const originalStart = textarea.selectionStart;
2093
+ const originalEnd = textarea.selectionEnd;
2094
+ const noInitialSelection = originalStart === originalEnd;
2095
+ const value = textarea.value;
2096
+ let lineStart = originalStart;
2097
+ while (lineStart > 0 && value[lineStart - 1] !== "\n") {
2098
+ lineStart--;
2099
+ }
2100
+ if (noInitialSelection) {
2101
+ let lineEnd = originalStart;
2102
+ while (lineEnd < value.length && value[lineEnd] !== "\n") {
2103
+ lineEnd++;
2569
2104
  }
2570
-
2571
- /* Links - make clickable in preview mode */
2572
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview a {
2573
- pointer-events: auto !important;
2574
- cursor: pointer !important;
2575
- color: var(--link, #0066cc) !important;
2576
- text-decoration: underline !important;
2105
+ textarea.selectionStart = lineStart;
2106
+ textarea.selectionEnd = lineEnd;
2107
+ } else {
2108
+ expandSelectionToLine(textarea);
2109
+ }
2110
+ const result = operation(textarea);
2111
+ if (options.adjustSelection) {
2112
+ const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
2113
+ const isRemoving = selectedText.startsWith(options.prefix);
2114
+ const adjusted = options.adjustSelection(isRemoving, originalStart, originalEnd, lineStart);
2115
+ result.selectionStart = adjusted.start;
2116
+ result.selectionEnd = adjusted.end;
2117
+ } else if (options.prefix) {
2118
+ const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
2119
+ const isRemoving = selectedText.startsWith(options.prefix);
2120
+ if (noInitialSelection) {
2121
+ if (isRemoving) {
2122
+ result.selectionStart = Math.max(originalStart - options.prefix.length, lineStart);
2123
+ result.selectionEnd = result.selectionStart;
2124
+ } else {
2125
+ result.selectionStart = originalStart + options.prefix.length;
2126
+ result.selectionEnd = result.selectionStart;
2127
+ }
2128
+ } else {
2129
+ if (isRemoving) {
2130
+ result.selectionStart = Math.max(originalStart - options.prefix.length, lineStart);
2131
+ result.selectionEnd = Math.max(originalEnd - options.prefix.length, lineStart);
2132
+ } else {
2133
+ result.selectionStart = originalStart + options.prefix.length;
2134
+ result.selectionEnd = originalEnd + options.prefix.length;
2135
+ }
2577
2136
  }
2578
-
2579
- /* Code blocks - proper pre/code styling in preview mode */
2580
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview pre.code-block {
2581
- background: #2d2d2d !important;
2582
- color: #f8f8f2 !important;
2583
- padding: 1.2em !important;
2584
- border-radius: 3px !important;
2585
- overflow-x: auto !important;
2586
- margin: 0 !important;
2587
- display: block !important;
2137
+ }
2138
+ return result;
2139
+ }
2140
+ function blockStyle(textarea, style) {
2141
+ let newlinesToAppend;
2142
+ let newlinesToPrepend;
2143
+ const { prefix, suffix, blockPrefix, blockSuffix, replaceNext, prefixSpace, scanFor, surroundWithNewlines, trimFirst } = style;
2144
+ const originalSelectionStart = textarea.selectionStart;
2145
+ const originalSelectionEnd = textarea.selectionEnd;
2146
+ let selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
2147
+ let prefixToUse = isMultipleLines(selectedText) && blockPrefix && blockPrefix.length > 0 ? `${blockPrefix}
2148
+ ` : prefix;
2149
+ let suffixToUse = isMultipleLines(selectedText) && blockSuffix && blockSuffix.length > 0 ? `
2150
+ ${blockSuffix}` : suffix;
2151
+ if (prefixSpace) {
2152
+ const beforeSelection = textarea.value[textarea.selectionStart - 1];
2153
+ if (textarea.selectionStart !== 0 && beforeSelection != null && !beforeSelection.match(/\s/)) {
2154
+ prefixToUse = ` ${prefixToUse}`;
2588
2155
  }
2589
-
2590
- /* Cave theme code block background in preview mode */
2591
- .overtype-container[data-theme="cave"][data-mode="preview"] .overtype-wrapper .overtype-preview pre.code-block {
2592
- background: #11171F !important;
2156
+ }
2157
+ selectedText = expandSelectedText(textarea, prefixToUse, suffixToUse, style.multiline);
2158
+ let selectionStart = textarea.selectionStart;
2159
+ let selectionEnd = textarea.selectionEnd;
2160
+ const hasReplaceNext = replaceNext && replaceNext.length > 0 && suffixToUse.indexOf(replaceNext) > -1 && selectedText.length > 0;
2161
+ if (surroundWithNewlines) {
2162
+ const ref = newlinesToSurroundSelectedText(textarea);
2163
+ newlinesToAppend = ref.newlinesToAppend;
2164
+ newlinesToPrepend = ref.newlinesToPrepend;
2165
+ prefixToUse = newlinesToAppend + prefix;
2166
+ suffixToUse += newlinesToPrepend;
2167
+ }
2168
+ if (selectedText.startsWith(prefixToUse) && selectedText.endsWith(suffixToUse)) {
2169
+ const replacementText = selectedText.slice(prefixToUse.length, selectedText.length - suffixToUse.length);
2170
+ if (originalSelectionStart === originalSelectionEnd) {
2171
+ let position = originalSelectionStart - prefixToUse.length;
2172
+ position = Math.max(position, selectionStart);
2173
+ position = Math.min(position, selectionStart + replacementText.length);
2174
+ selectionStart = selectionEnd = position;
2175
+ } else {
2176
+ selectionEnd = selectionStart + replacementText.length;
2593
2177
  }
2594
-
2595
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview pre.code-block code {
2596
- background: transparent !important;
2597
- color: inherit !important;
2598
- padding: 0 !important;
2599
- font-family: ${fontFamily} !important;
2600
- font-size: 0.9em !important;
2601
- line-height: 1.4 !important;
2178
+ return { text: replacementText, selectionStart, selectionEnd };
2179
+ } else if (!hasReplaceNext) {
2180
+ let replacementText = prefixToUse + selectedText + suffixToUse;
2181
+ selectionStart = originalSelectionStart + prefixToUse.length;
2182
+ selectionEnd = originalSelectionEnd + prefixToUse.length;
2183
+ const whitespaceEdges = selectedText.match(/^\s*|\s*$/g);
2184
+ if (trimFirst && whitespaceEdges) {
2185
+ const leadingWhitespace = whitespaceEdges[0] || "";
2186
+ const trailingWhitespace = whitespaceEdges[1] || "";
2187
+ replacementText = leadingWhitespace + prefixToUse + selectedText.trim() + suffixToUse + trailingWhitespace;
2188
+ selectionStart += leadingWhitespace.length;
2189
+ selectionEnd -= trailingWhitespace.length;
2602
2190
  }
2603
-
2604
- /* Hide old code block lines and fences in preview mode */
2605
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview .code-block-line {
2606
- display: none !important;
2191
+ return { text: replacementText, selectionStart, selectionEnd };
2192
+ } else if (scanFor && scanFor.length > 0 && selectedText.match(scanFor)) {
2193
+ suffixToUse = suffixToUse.replace(replaceNext, selectedText);
2194
+ const replacementText = prefixToUse + suffixToUse;
2195
+ selectionStart = selectionEnd = selectionStart + prefixToUse.length;
2196
+ return { text: replacementText, selectionStart, selectionEnd };
2197
+ } else {
2198
+ const replacementText = prefixToUse + selectedText + suffixToUse;
2199
+ selectionStart = selectionStart + prefixToUse.length + selectedText.length + suffixToUse.indexOf(replaceNext);
2200
+ selectionEnd = selectionStart + replaceNext.length;
2201
+ return { text: replacementText, selectionStart, selectionEnd };
2202
+ }
2203
+ }
2204
+ function multilineStyle(textarea, style) {
2205
+ const { prefix, suffix, surroundWithNewlines } = style;
2206
+ let text = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
2207
+ let selectionStart = textarea.selectionStart;
2208
+ let selectionEnd = textarea.selectionEnd;
2209
+ const lines = text.split("\n");
2210
+ const undoStyle = lines.every((line) => line.startsWith(prefix) && (!suffix || line.endsWith(suffix)));
2211
+ if (undoStyle) {
2212
+ text = lines.map((line) => {
2213
+ let result = line.slice(prefix.length);
2214
+ if (suffix) {
2215
+ result = result.slice(0, result.length - suffix.length);
2216
+ }
2217
+ return result;
2218
+ }).join("\n");
2219
+ selectionEnd = selectionStart + text.length;
2220
+ } else {
2221
+ text = lines.map((line) => prefix + line + (suffix || "")).join("\n");
2222
+ if (surroundWithNewlines) {
2223
+ const { newlinesToAppend, newlinesToPrepend } = newlinesToSurroundSelectedText(textarea);
2224
+ selectionStart += newlinesToAppend.length;
2225
+ selectionEnd = selectionStart + text.length;
2226
+ text = newlinesToAppend + text + newlinesToPrepend;
2607
2227
  }
2608
-
2609
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview .code-fence {
2610
- display: none !important;
2228
+ }
2229
+ return { text, selectionStart, selectionEnd };
2230
+ }
2231
+ function undoOrderedListStyle(text) {
2232
+ const lines = text.split("\n");
2233
+ const orderedListRegex = /^\d+\.\s+/;
2234
+ const shouldUndoOrderedList = lines.every((line) => orderedListRegex.test(line));
2235
+ let result = lines;
2236
+ if (shouldUndoOrderedList) {
2237
+ result = lines.map((line) => line.replace(orderedListRegex, ""));
2238
+ }
2239
+ return {
2240
+ text: result.join("\n"),
2241
+ processed: shouldUndoOrderedList
2242
+ };
2243
+ }
2244
+ function undoUnorderedListStyle(text) {
2245
+ const lines = text.split("\n");
2246
+ const unorderedListPrefix = "- ";
2247
+ const shouldUndoUnorderedList = lines.every((line) => line.startsWith(unorderedListPrefix));
2248
+ let result = lines;
2249
+ if (shouldUndoUnorderedList) {
2250
+ result = lines.map((line) => line.slice(unorderedListPrefix.length));
2251
+ }
2252
+ return {
2253
+ text: result.join("\n"),
2254
+ processed: shouldUndoUnorderedList
2255
+ };
2256
+ }
2257
+ function makePrefix(index, unorderedList) {
2258
+ if (unorderedList) {
2259
+ return "- ";
2260
+ } else {
2261
+ return `${index + 1}. `;
2262
+ }
2263
+ }
2264
+ function clearExistingListStyle(style, selectedText) {
2265
+ let undoResult;
2266
+ let undoResultOppositeList;
2267
+ let pristineText;
2268
+ if (style.orderedList) {
2269
+ undoResult = undoOrderedListStyle(selectedText);
2270
+ undoResultOppositeList = undoUnorderedListStyle(undoResult.text);
2271
+ pristineText = undoResultOppositeList.text;
2272
+ } else {
2273
+ undoResult = undoUnorderedListStyle(selectedText);
2274
+ undoResultOppositeList = undoOrderedListStyle(undoResult.text);
2275
+ pristineText = undoResultOppositeList.text;
2276
+ }
2277
+ return [undoResult, undoResultOppositeList, pristineText];
2278
+ }
2279
+ function listStyle(textarea, style) {
2280
+ const noInitialSelection = textarea.selectionStart === textarea.selectionEnd;
2281
+ let selectionStart = textarea.selectionStart;
2282
+ let selectionEnd = textarea.selectionEnd;
2283
+ expandSelectionToLine(textarea);
2284
+ const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
2285
+ const [undoResult, undoResultOppositeList, pristineText] = clearExistingListStyle(style, selectedText);
2286
+ const prefixedLines = pristineText.split("\n").map((value, index) => {
2287
+ return `${makePrefix(index, style.unorderedList)}${value}`;
2288
+ });
2289
+ const totalPrefixLength = prefixedLines.reduce((previousValue, _currentValue, currentIndex) => {
2290
+ return previousValue + makePrefix(currentIndex, style.unorderedList).length;
2291
+ }, 0);
2292
+ const totalPrefixLengthOppositeList = prefixedLines.reduce((previousValue, _currentValue, currentIndex) => {
2293
+ return previousValue + makePrefix(currentIndex, !style.unorderedList).length;
2294
+ }, 0);
2295
+ if (undoResult.processed) {
2296
+ if (noInitialSelection) {
2297
+ selectionStart = Math.max(selectionStart - makePrefix(0, style.unorderedList).length, 0);
2298
+ selectionEnd = selectionStart;
2299
+ } else {
2300
+ selectionStart = textarea.selectionStart;
2301
+ selectionEnd = textarea.selectionEnd - totalPrefixLength;
2611
2302
  }
2612
-
2613
- /* Blockquotes - enhanced styling in preview mode */
2614
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview .blockquote {
2615
- display: block !important;
2616
- border-left: 4px solid var(--blockquote, #ddd) !important;
2617
- padding-left: 1em !important;
2618
- margin: 1em 0 !important;
2619
- font-style: italic !important;
2303
+ return { text: pristineText, selectionStart, selectionEnd };
2304
+ }
2305
+ const { newlinesToAppend, newlinesToPrepend } = newlinesToSurroundSelectedText(textarea);
2306
+ const text = newlinesToAppend + prefixedLines.join("\n") + newlinesToPrepend;
2307
+ if (noInitialSelection) {
2308
+ selectionStart = Math.max(selectionStart + makePrefix(0, style.unorderedList).length + newlinesToAppend.length, 0);
2309
+ selectionEnd = selectionStart;
2310
+ } else {
2311
+ if (undoResultOppositeList.processed) {
2312
+ selectionStart = Math.max(textarea.selectionStart + newlinesToAppend.length, 0);
2313
+ selectionEnd = textarea.selectionEnd + newlinesToAppend.length + totalPrefixLength - totalPrefixLengthOppositeList;
2314
+ } else {
2315
+ selectionStart = Math.max(textarea.selectionStart + newlinesToAppend.length, 0);
2316
+ selectionEnd = textarea.selectionEnd + newlinesToAppend.length + totalPrefixLength;
2620
2317
  }
2621
-
2622
- /* Typography improvements in preview mode */
2623
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview {
2624
- font-family: Georgia, 'Times New Roman', serif !important;
2625
- font-size: 16px !important;
2626
- line-height: 1.8 !important;
2627
- color: var(--text, #333) !important; /* Consistent text color */
2318
+ }
2319
+ return { text, selectionStart, selectionEnd };
2320
+ }
2321
+ function applyListStyle(textarea, style) {
2322
+ const result = applyLineOperation(
2323
+ textarea,
2324
+ (ta) => listStyle(ta, style),
2325
+ {
2326
+ // Custom selection adjustment for lists
2327
+ adjustSelection: (isRemoving, selStart, selEnd, lineStart) => {
2328
+ const currentLine = textarea.value.slice(lineStart, textarea.selectionEnd);
2329
+ const orderedListRegex = /^\d+\.\s+/;
2330
+ const unorderedListRegex = /^- /;
2331
+ const hasOrderedList = orderedListRegex.test(currentLine);
2332
+ const hasUnorderedList = unorderedListRegex.test(currentLine);
2333
+ const isRemovingCurrent = style.orderedList && hasOrderedList || style.unorderedList && hasUnorderedList;
2334
+ if (selStart === selEnd) {
2335
+ if (isRemovingCurrent) {
2336
+ const prefixMatch = currentLine.match(style.orderedList ? orderedListRegex : unorderedListRegex);
2337
+ const prefixLength = prefixMatch ? prefixMatch[0].length : 0;
2338
+ return {
2339
+ start: Math.max(selStart - prefixLength, lineStart),
2340
+ end: Math.max(selStart - prefixLength, lineStart)
2341
+ };
2342
+ } else if (hasOrderedList || hasUnorderedList) {
2343
+ const oldPrefixMatch = currentLine.match(hasOrderedList ? orderedListRegex : unorderedListRegex);
2344
+ const oldPrefixLength = oldPrefixMatch ? oldPrefixMatch[0].length : 0;
2345
+ const newPrefixLength = style.unorderedList ? 2 : 3;
2346
+ const adjustment = newPrefixLength - oldPrefixLength;
2347
+ return {
2348
+ start: selStart + adjustment,
2349
+ end: selStart + adjustment
2350
+ };
2351
+ } else {
2352
+ const prefixLength = style.unorderedList ? 2 : 3;
2353
+ return {
2354
+ start: selStart + prefixLength,
2355
+ end: selStart + prefixLength
2356
+ };
2357
+ }
2358
+ } else {
2359
+ if (isRemovingCurrent) {
2360
+ const prefixMatch = currentLine.match(style.orderedList ? orderedListRegex : unorderedListRegex);
2361
+ const prefixLength = prefixMatch ? prefixMatch[0].length : 0;
2362
+ return {
2363
+ start: Math.max(selStart - prefixLength, lineStart),
2364
+ end: Math.max(selEnd - prefixLength, lineStart)
2365
+ };
2366
+ } else if (hasOrderedList || hasUnorderedList) {
2367
+ const oldPrefixMatch = currentLine.match(hasOrderedList ? orderedListRegex : unorderedListRegex);
2368
+ const oldPrefixLength = oldPrefixMatch ? oldPrefixMatch[0].length : 0;
2369
+ const newPrefixLength = style.unorderedList ? 2 : 3;
2370
+ const adjustment = newPrefixLength - oldPrefixLength;
2371
+ return {
2372
+ start: selStart + adjustment,
2373
+ end: selEnd + adjustment
2374
+ };
2375
+ } else {
2376
+ const prefixLength = style.unorderedList ? 2 : 3;
2377
+ return {
2378
+ start: selStart + prefixLength,
2379
+ end: selEnd + prefixLength
2380
+ };
2381
+ }
2382
+ }
2383
+ }
2628
2384
  }
2629
-
2630
- /* Inline code in preview mode - keep monospace */
2631
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview code {
2632
- font-family: ${fontFamily} !important;
2633
- font-size: 0.9em !important;
2634
- background: rgba(135, 131, 120, 0.15) !important;
2635
- padding: 0.2em 0.4em !important;
2636
- border-radius: 3px !important;
2385
+ );
2386
+ insertText(textarea, result);
2387
+ }
2388
+ function getActiveFormats(textarea) {
2389
+ if (!textarea)
2390
+ return [];
2391
+ const formats = [];
2392
+ const { selectionStart, selectionEnd, value } = textarea;
2393
+ const lines = value.split("\n");
2394
+ let lineStart = 0;
2395
+ let currentLine = "";
2396
+ for (const line of lines) {
2397
+ if (selectionStart >= lineStart && selectionStart <= lineStart + line.length) {
2398
+ currentLine = line;
2399
+ break;
2637
2400
  }
2638
-
2639
- /* Strong and em elements in preview mode */
2640
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview strong {
2641
- font-weight: 700 !important;
2642
- color: inherit !important; /* Use parent text color */
2401
+ lineStart += line.length + 1;
2402
+ }
2403
+ if (currentLine.startsWith("- ")) {
2404
+ if (currentLine.startsWith("- [ ] ") || currentLine.startsWith("- [x] ")) {
2405
+ formats.push("task-list");
2406
+ } else {
2407
+ formats.push("bullet-list");
2643
2408
  }
2644
-
2645
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview em {
2646
- font-style: italic !important;
2647
- color: inherit !important; /* Use parent text color */
2409
+ }
2410
+ if (/^\d+\.\s/.test(currentLine)) {
2411
+ formats.push("numbered-list");
2412
+ }
2413
+ if (currentLine.startsWith("> ")) {
2414
+ formats.push("quote");
2415
+ }
2416
+ if (currentLine.startsWith("# "))
2417
+ formats.push("header");
2418
+ if (currentLine.startsWith("## "))
2419
+ formats.push("header-2");
2420
+ if (currentLine.startsWith("### "))
2421
+ formats.push("header-3");
2422
+ const lookBehind = Math.max(0, selectionStart - 10);
2423
+ const lookAhead = Math.min(value.length, selectionEnd + 10);
2424
+ const surrounding = value.slice(lookBehind, lookAhead);
2425
+ if (surrounding.includes("**")) {
2426
+ const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
2427
+ const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
2428
+ const lastOpenBold = beforeCursor.lastIndexOf("**");
2429
+ const nextCloseBold = afterCursor.indexOf("**");
2430
+ if (lastOpenBold !== -1 && nextCloseBold !== -1) {
2431
+ formats.push("bold");
2648
2432
  }
2649
-
2650
- /* HR in preview mode */
2651
- .overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview .hr-marker {
2652
- display: block !important;
2653
- border-top: 2px solid var(--hr, #ddd) !important;
2654
- text-indent: -9999px !important;
2655
- height: 2px !important;
2433
+ }
2434
+ if (surrounding.includes("_")) {
2435
+ const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
2436
+ const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
2437
+ const lastOpenItalic = beforeCursor.lastIndexOf("_");
2438
+ const nextCloseItalic = afterCursor.indexOf("_");
2439
+ if (lastOpenItalic !== -1 && nextCloseItalic !== -1) {
2440
+ formats.push("italic");
2656
2441
  }
2657
-
2658
- /* Link Tooltip - Base styles (all browsers) */
2659
- .overtype-link-tooltip {
2660
- /* Visual styles that work for both positioning methods */
2661
- background: #333 !important;
2662
- color: white !important;
2663
- padding: 6px 10px !important;
2664
- border-radius: 16px !important;
2665
- font-size: 12px !important;
2666
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
2667
- display: none !important;
2668
- z-index: 10000 !important;
2669
- cursor: pointer !important;
2670
- box-shadow: 0 2px 8px rgba(0,0,0,0.3) !important;
2671
- max-width: 300px !important;
2672
- white-space: nowrap !important;
2673
- overflow: hidden !important;
2674
- text-overflow: ellipsis !important;
2675
-
2676
- /* Base positioning for Floating UI fallback */
2677
- position: absolute;
2442
+ }
2443
+ if (surrounding.includes("`")) {
2444
+ const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
2445
+ const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
2446
+ if (beforeCursor.includes("`") && afterCursor.includes("`")) {
2447
+ formats.push("code");
2678
2448
  }
2679
-
2680
- .overtype-link-tooltip.visible {
2681
- display: flex !important;
2449
+ }
2450
+ if (surrounding.includes("[") && surrounding.includes("]")) {
2451
+ const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
2452
+ const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
2453
+ const lastOpenBracket = beforeCursor.lastIndexOf("[");
2454
+ const nextCloseBracket = afterCursor.indexOf("]");
2455
+ if (lastOpenBracket !== -1 && nextCloseBracket !== -1) {
2456
+ const afterBracket = value.slice(selectionEnd + nextCloseBracket + 1, selectionEnd + nextCloseBracket + 10);
2457
+ if (afterBracket.startsWith("(")) {
2458
+ formats.push("link");
2459
+ }
2682
2460
  }
2683
-
2684
- /* CSS Anchor Positioning (modern browsers only) */
2685
- @supports (position-anchor: --x) and (position-area: center) {
2686
- .overtype-link-tooltip {
2687
- /* Only anchor positioning specific properties */
2688
- position-anchor: var(--target-anchor, --link-0);
2689
- position-area: block-end center;
2690
- margin-top: 8px !important;
2691
- position-try: most-width block-end inline-end, flip-inline, block-start center;
2692
- position-visibility: anchors-visible;
2461
+ }
2462
+ return formats;
2463
+ }
2464
+ function toggleBold(textarea) {
2465
+ if (!textarea || textarea.disabled || textarea.readOnly)
2466
+ return;
2467
+ debugLog("toggleBold", "Starting");
2468
+ debugSelection(textarea, "Before");
2469
+ const style = mergeWithDefaults(FORMATS.bold);
2470
+ const result = blockStyle(textarea, style);
2471
+ debugResult(result);
2472
+ insertText(textarea, result);
2473
+ debugSelection(textarea, "After");
2474
+ }
2475
+ function toggleItalic(textarea) {
2476
+ if (!textarea || textarea.disabled || textarea.readOnly)
2477
+ return;
2478
+ const style = mergeWithDefaults(FORMATS.italic);
2479
+ const result = blockStyle(textarea, style);
2480
+ insertText(textarea, result);
2481
+ }
2482
+ function toggleCode(textarea) {
2483
+ if (!textarea || textarea.disabled || textarea.readOnly)
2484
+ return;
2485
+ const style = mergeWithDefaults(FORMATS.code);
2486
+ const result = blockStyle(textarea, style);
2487
+ insertText(textarea, result);
2488
+ }
2489
+ function insertLink(textarea, options = {}) {
2490
+ if (!textarea || textarea.disabled || textarea.readOnly)
2491
+ return;
2492
+ const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
2493
+ let style = mergeWithDefaults(FORMATS.link);
2494
+ const isURL = selectedText && selectedText.match(/^https?:\/\//);
2495
+ if (isURL && !options.url) {
2496
+ style.suffix = `](${selectedText})`;
2497
+ style.replaceNext = "";
2498
+ } else if (options.url) {
2499
+ style.suffix = `](${options.url})`;
2500
+ style.replaceNext = "";
2501
+ }
2502
+ if (options.text && !selectedText) {
2503
+ const pos = textarea.selectionStart;
2504
+ textarea.value = textarea.value.slice(0, pos) + options.text + textarea.value.slice(pos);
2505
+ textarea.selectionStart = pos;
2506
+ textarea.selectionEnd = pos + options.text.length;
2507
+ }
2508
+ const result = blockStyle(textarea, style);
2509
+ insertText(textarea, result);
2510
+ }
2511
+ function toggleBulletList(textarea) {
2512
+ if (!textarea || textarea.disabled || textarea.readOnly)
2513
+ return;
2514
+ const style = mergeWithDefaults(FORMATS.bulletList);
2515
+ applyListStyle(textarea, style);
2516
+ }
2517
+ function toggleNumberedList(textarea) {
2518
+ if (!textarea || textarea.disabled || textarea.readOnly)
2519
+ return;
2520
+ const style = mergeWithDefaults(FORMATS.numberedList);
2521
+ applyListStyle(textarea, style);
2522
+ }
2523
+ function toggleQuote(textarea) {
2524
+ if (!textarea || textarea.disabled || textarea.readOnly)
2525
+ return;
2526
+ debugLog("toggleQuote", "Starting");
2527
+ debugSelection(textarea, "Initial");
2528
+ const style = mergeWithDefaults(FORMATS.quote);
2529
+ const result = applyLineOperation(
2530
+ textarea,
2531
+ (ta) => multilineStyle(ta, style),
2532
+ { prefix: style.prefix }
2533
+ );
2534
+ debugResult(result);
2535
+ insertText(textarea, result);
2536
+ debugSelection(textarea, "Final");
2537
+ }
2538
+ function toggleTaskList(textarea) {
2539
+ if (!textarea || textarea.disabled || textarea.readOnly)
2540
+ return;
2541
+ const style = mergeWithDefaults(FORMATS.taskList);
2542
+ const result = applyLineOperation(
2543
+ textarea,
2544
+ (ta) => multilineStyle(ta, style),
2545
+ { prefix: style.prefix }
2546
+ );
2547
+ insertText(textarea, result);
2548
+ }
2549
+ function insertHeader(textarea, level = 1, toggle = false) {
2550
+ if (!textarea || textarea.disabled || textarea.readOnly)
2551
+ return;
2552
+ if (level < 1 || level > 6)
2553
+ level = 1;
2554
+ debugLog("insertHeader", `============ START ============`);
2555
+ debugLog("insertHeader", `Level: ${level}, Toggle: ${toggle}`);
2556
+ debugLog("insertHeader", `Initial cursor: ${textarea.selectionStart}-${textarea.selectionEnd}`);
2557
+ const headerKey = `header${level === 1 ? "1" : level}`;
2558
+ const style = mergeWithDefaults(FORMATS[headerKey] || FORMATS.header1);
2559
+ debugLog("insertHeader", `Style prefix: "${style.prefix}"`);
2560
+ const value = textarea.value;
2561
+ const originalStart = textarea.selectionStart;
2562
+ const originalEnd = textarea.selectionEnd;
2563
+ let lineStart = originalStart;
2564
+ while (lineStart > 0 && value[lineStart - 1] !== "\n") {
2565
+ lineStart--;
2566
+ }
2567
+ let lineEnd = originalEnd;
2568
+ while (lineEnd < value.length && value[lineEnd] !== "\n") {
2569
+ lineEnd++;
2570
+ }
2571
+ const currentLineContent = value.slice(lineStart, lineEnd);
2572
+ debugLog("insertHeader", `Current line (before): "${currentLineContent}"`);
2573
+ const existingHeaderMatch = currentLineContent.match(/^(#{1,6})\s*/);
2574
+ const existingLevel = existingHeaderMatch ? existingHeaderMatch[1].length : 0;
2575
+ const existingPrefixLength = existingHeaderMatch ? existingHeaderMatch[0].length : 0;
2576
+ debugLog("insertHeader", `Existing header check:`);
2577
+ debugLog("insertHeader", ` - Match: ${existingHeaderMatch ? `"${existingHeaderMatch[0]}"` : "none"}`);
2578
+ debugLog("insertHeader", ` - Existing level: ${existingLevel}`);
2579
+ debugLog("insertHeader", ` - Existing prefix length: ${existingPrefixLength}`);
2580
+ debugLog("insertHeader", ` - Target level: ${level}`);
2581
+ const shouldToggleOff = toggle && existingLevel === level;
2582
+ debugLog("insertHeader", `Should toggle OFF: ${shouldToggleOff} (toggle=${toggle}, existingLevel=${existingLevel}, level=${level})`);
2583
+ const result = applyLineOperation(
2584
+ textarea,
2585
+ (ta) => {
2586
+ const currentLine = ta.value.slice(ta.selectionStart, ta.selectionEnd);
2587
+ debugLog("insertHeader", `Line in operation: "${currentLine}"`);
2588
+ const cleanedLine = currentLine.replace(/^#{1,6}\s*/, "");
2589
+ debugLog("insertHeader", `Cleaned line: "${cleanedLine}"`);
2590
+ let newLine;
2591
+ if (shouldToggleOff) {
2592
+ debugLog("insertHeader", "ACTION: Toggling OFF - removing header");
2593
+ newLine = cleanedLine;
2594
+ } else if (existingLevel > 0) {
2595
+ debugLog("insertHeader", `ACTION: Replacing H${existingLevel} with H${level}`);
2596
+ newLine = style.prefix + cleanedLine;
2597
+ } else {
2598
+ debugLog("insertHeader", "ACTION: Adding new header");
2599
+ newLine = style.prefix + cleanedLine;
2600
+ }
2601
+ debugLog("insertHeader", `New line: "${newLine}"`);
2602
+ return {
2603
+ text: newLine,
2604
+ selectionStart: ta.selectionStart,
2605
+ selectionEnd: ta.selectionEnd
2606
+ };
2607
+ },
2608
+ {
2609
+ prefix: style.prefix,
2610
+ // Custom selection adjustment for headers
2611
+ adjustSelection: (isRemoving, selStart, selEnd, lineStartPos) => {
2612
+ debugLog("insertHeader", `Adjusting selection:`);
2613
+ debugLog("insertHeader", ` - isRemoving param: ${isRemoving}`);
2614
+ debugLog("insertHeader", ` - shouldToggleOff: ${shouldToggleOff}`);
2615
+ debugLog("insertHeader", ` - selStart: ${selStart}, selEnd: ${selEnd}`);
2616
+ debugLog("insertHeader", ` - lineStartPos: ${lineStartPos}`);
2617
+ if (shouldToggleOff) {
2618
+ const adjustment = Math.max(selStart - existingPrefixLength, lineStartPos);
2619
+ debugLog("insertHeader", ` - Removing header, adjusting by -${existingPrefixLength}`);
2620
+ return {
2621
+ start: adjustment,
2622
+ end: selStart === selEnd ? adjustment : Math.max(selEnd - existingPrefixLength, lineStartPos)
2623
+ };
2624
+ } else if (existingPrefixLength > 0) {
2625
+ const prefixDiff = style.prefix.length - existingPrefixLength;
2626
+ debugLog("insertHeader", ` - Replacing header, adjusting by ${prefixDiff}`);
2627
+ return {
2628
+ start: selStart + prefixDiff,
2629
+ end: selEnd + prefixDiff
2630
+ };
2631
+ } else {
2632
+ debugLog("insertHeader", ` - Adding header, adjusting by +${style.prefix.length}`);
2633
+ return {
2634
+ start: selStart + style.prefix.length,
2635
+ end: selEnd + style.prefix.length
2636
+ };
2637
+ }
2693
2638
  }
2694
2639
  }
2695
-
2696
- ${mobileStyles}
2697
- `;
2640
+ );
2641
+ debugLog("insertHeader", `Final result: text="${result.text}", cursor=${result.selectionStart}-${result.selectionEnd}`);
2642
+ debugLog("insertHeader", `============ END ============`);
2643
+ insertText(textarea, result);
2644
+ }
2645
+ function toggleH1(textarea) {
2646
+ insertHeader(textarea, 1, true);
2647
+ }
2648
+ function toggleH2(textarea) {
2649
+ insertHeader(textarea, 2, true);
2650
+ }
2651
+ function toggleH3(textarea) {
2652
+ insertHeader(textarea, 3, true);
2653
+ }
2654
+ function getActiveFormats2(textarea) {
2655
+ return getActiveFormats(textarea);
2698
2656
  }
2699
2657
 
2700
2658
  // src/toolbar.js
@@ -2754,55 +2712,43 @@ var Toolbar = class {
2754
2712
  });
2755
2713
  return button;
2756
2714
  }
2757
- button._clickHandler = async (e) => {
2715
+ button._clickHandler = (e) => {
2758
2716
  e.preventDefault();
2759
- this.editor.textarea.focus();
2760
- try {
2761
- if (buttonConfig.action) {
2762
- await buttonConfig.action({
2763
- editor: this.editor,
2764
- getValue: () => this.editor.getValue(),
2765
- setValue: (value) => this.editor.setValue(value),
2766
- event: e
2767
- });
2768
- }
2769
- } catch (error) {
2770
- console.error(`Button "${buttonConfig.name}" error:`, error);
2771
- this.editor.wrapper.dispatchEvent(new CustomEvent("button-error", {
2772
- detail: { buttonName: buttonConfig.name, error }
2773
- }));
2774
- button.classList.add("button-error");
2775
- button.style.animation = "buttonError 0.3s";
2776
- setTimeout(() => {
2777
- button.classList.remove("button-error");
2778
- button.style.animation = "";
2779
- }, 300);
2780
- }
2717
+ const actionId = buttonConfig.actionId || buttonConfig.name;
2718
+ this.editor.performAction(actionId, e);
2781
2719
  };
2782
2720
  button.addEventListener("click", button._clickHandler);
2783
2721
  return button;
2784
2722
  }
2785
2723
  /**
2786
- * Handle button action programmatically (used by keyboard shortcuts)
2787
- * @param {Object} buttonConfig - Button configuration object with action function
2724
+ * Handle button action programmatically
2725
+ * Accepts either an actionId string or a buttonConfig object (backwards compatible)
2726
+ * @param {string|Object} actionIdOrConfig - Action identifier string or button config object
2727
+ * @returns {Promise<boolean>} Whether the action was executed
2788
2728
  */
2789
- async handleAction(buttonConfig) {
2790
- this.editor.textarea.focus();
2791
- try {
2792
- if (buttonConfig.action) {
2793
- await buttonConfig.action({
2729
+ async handleAction(actionIdOrConfig) {
2730
+ if (actionIdOrConfig && typeof actionIdOrConfig === "object" && typeof actionIdOrConfig.action === "function") {
2731
+ this.editor.textarea.focus();
2732
+ try {
2733
+ await actionIdOrConfig.action({
2794
2734
  editor: this.editor,
2795
2735
  getValue: () => this.editor.getValue(),
2796
2736
  setValue: (value) => this.editor.setValue(value),
2797
2737
  event: null
2798
2738
  });
2739
+ return true;
2740
+ } catch (error) {
2741
+ console.error(`Action "${actionIdOrConfig.name}" error:`, error);
2742
+ this.editor.wrapper.dispatchEvent(new CustomEvent("button-error", {
2743
+ detail: { buttonName: actionIdOrConfig.name, error }
2744
+ }));
2745
+ return false;
2799
2746
  }
2800
- } catch (error) {
2801
- console.error(`Action "${buttonConfig.name}" error:`, error);
2802
- this.editor.wrapper.dispatchEvent(new CustomEvent("button-error", {
2803
- detail: { buttonName: buttonConfig.name, error }
2804
- }));
2805
2747
  }
2748
+ if (typeof actionIdOrConfig === "string") {
2749
+ return this.editor.performAction(actionIdOrConfig, null);
2750
+ }
2751
+ return false;
2806
2752
  }
2807
2753
  /**
2808
2754
  * Sanitize SVG to prevent XSS
@@ -2972,6 +2918,7 @@ var LinkTooltip = class {
2972
2918
  this.visibilityChangeHandler = null;
2973
2919
  this.useFloatingUI = false;
2974
2920
  this.floatingUI = null;
2921
+ this.isTooltipHovered = false;
2975
2922
  this.init();
2976
2923
  }
2977
2924
  async init() {
@@ -3005,14 +2952,25 @@ var LinkTooltip = class {
3005
2952
  this.hide();
3006
2953
  }
3007
2954
  });
3008
- this.editor.textarea.addEventListener("blur", () => this.hide());
2955
+ this.editor.textarea.addEventListener("blur", () => {
2956
+ if (!this.isTooltipHovered) {
2957
+ this.hide();
2958
+ }
2959
+ });
3009
2960
  this.visibilityChangeHandler = () => {
3010
2961
  if (document.hidden) {
3011
2962
  this.hide();
3012
2963
  }
3013
2964
  };
3014
2965
  document.addEventListener("visibilitychange", this.visibilityChangeHandler);
3015
- this.tooltip.addEventListener("mouseenter", () => this.cancelHide());
2966
+ this.tooltip.addEventListener("mouseenter", () => {
2967
+ this.isTooltipHovered = true;
2968
+ this.cancelHide();
2969
+ });
2970
+ this.tooltip.addEventListener("mouseleave", () => {
2971
+ this.isTooltipHovered = false;
2972
+ this.scheduleHide();
2973
+ });
3016
2974
  }
3017
2975
  createTooltip() {
3018
2976
  this.tooltip = document.createElement("div");
@@ -3122,6 +3080,7 @@ var LinkTooltip = class {
3122
3080
  hide() {
3123
3081
  this.tooltip.classList.remove("visible");
3124
3082
  this.currentLink = null;
3083
+ this.isTooltipHovered = false;
3125
3084
  }
3126
3085
  scheduleHide() {
3127
3086
  this.cancelHide();
@@ -3146,6 +3105,7 @@ var LinkTooltip = class {
3146
3105
  this.currentLink = null;
3147
3106
  this.floatingUI = null;
3148
3107
  this.useFloatingUI = false;
3108
+ this.isTooltipHovered = false;
3149
3109
  }
3150
3110
  };
3151
3111
 
@@ -3216,27 +3176,30 @@ var eyeIcon = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke
3216
3176
  var toolbarButtons = {
3217
3177
  bold: {
3218
3178
  name: "bold",
3179
+ actionId: "toggleBold",
3219
3180
  icon: boldIcon,
3220
3181
  title: "Bold (Ctrl+B)",
3221
- action: ({ editor, event }) => {
3182
+ action: ({ editor }) => {
3222
3183
  toggleBold(editor.textarea);
3223
3184
  editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
3224
3185
  }
3225
3186
  },
3226
3187
  italic: {
3227
3188
  name: "italic",
3189
+ actionId: "toggleItalic",
3228
3190
  icon: italicIcon,
3229
3191
  title: "Italic (Ctrl+I)",
3230
- action: ({ editor, event }) => {
3192
+ action: ({ editor }) => {
3231
3193
  toggleItalic(editor.textarea);
3232
3194
  editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
3233
3195
  }
3234
3196
  },
3235
3197
  code: {
3236
3198
  name: "code",
3199
+ actionId: "toggleCode",
3237
3200
  icon: codeIcon,
3238
3201
  title: "Inline Code",
3239
- action: ({ editor, event }) => {
3202
+ action: ({ editor }) => {
3240
3203
  toggleCode(editor.textarea);
3241
3204
  editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
3242
3205
  }
@@ -3247,63 +3210,70 @@ var toolbarButtons = {
3247
3210
  },
3248
3211
  link: {
3249
3212
  name: "link",
3213
+ actionId: "insertLink",
3250
3214
  icon: linkIcon,
3251
3215
  title: "Insert Link",
3252
- action: ({ editor, event }) => {
3216
+ action: ({ editor }) => {
3253
3217
  insertLink(editor.textarea);
3254
3218
  editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
3255
3219
  }
3256
3220
  },
3257
3221
  h1: {
3258
3222
  name: "h1",
3223
+ actionId: "toggleH1",
3259
3224
  icon: h1Icon,
3260
3225
  title: "Heading 1",
3261
- action: ({ editor, event }) => {
3226
+ action: ({ editor }) => {
3262
3227
  toggleH1(editor.textarea);
3263
3228
  editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
3264
3229
  }
3265
3230
  },
3266
3231
  h2: {
3267
3232
  name: "h2",
3233
+ actionId: "toggleH2",
3268
3234
  icon: h2Icon,
3269
3235
  title: "Heading 2",
3270
- action: ({ editor, event }) => {
3236
+ action: ({ editor }) => {
3271
3237
  toggleH2(editor.textarea);
3272
3238
  editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
3273
3239
  }
3274
3240
  },
3275
3241
  h3: {
3276
3242
  name: "h3",
3243
+ actionId: "toggleH3",
3277
3244
  icon: h3Icon,
3278
3245
  title: "Heading 3",
3279
- action: ({ editor, event }) => {
3246
+ action: ({ editor }) => {
3280
3247
  toggleH3(editor.textarea);
3281
3248
  editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
3282
3249
  }
3283
3250
  },
3284
3251
  bulletList: {
3285
3252
  name: "bulletList",
3253
+ actionId: "toggleBulletList",
3286
3254
  icon: bulletListIcon,
3287
3255
  title: "Bullet List",
3288
- action: ({ editor, event }) => {
3256
+ action: ({ editor }) => {
3289
3257
  toggleBulletList(editor.textarea);
3290
3258
  editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
3291
3259
  }
3292
3260
  },
3293
3261
  orderedList: {
3294
3262
  name: "orderedList",
3263
+ actionId: "toggleNumberedList",
3295
3264
  icon: orderedListIcon,
3296
3265
  title: "Numbered List",
3297
- action: ({ editor, event }) => {
3266
+ action: ({ editor }) => {
3298
3267
  toggleNumberedList(editor.textarea);
3299
3268
  editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
3300
3269
  }
3301
3270
  },
3302
3271
  taskList: {
3303
3272
  name: "taskList",
3273
+ actionId: "toggleTaskList",
3304
3274
  icon: taskListIcon,
3305
3275
  title: "Task List",
3306
- action: ({ editor, event }) => {
3276
+ action: ({ editor }) => {
3307
3277
  if (toggleTaskList) {
3308
3278
  toggleTaskList(editor.textarea);
3309
3279
  editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
@@ -3312,9 +3282,10 @@ var toolbarButtons = {
3312
3282
  },
3313
3283
  quote: {
3314
3284
  name: "quote",
3285
+ actionId: "toggleQuote",
3315
3286
  icon: quoteIcon,
3316
3287
  title: "Quote",
3317
- action: ({ editor, event }) => {
3288
+ action: ({ editor }) => {
3318
3289
  toggleQuote(editor.textarea);
3319
3290
  editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
3320
3291
  }
@@ -3348,6 +3319,45 @@ var defaultToolbarButtons = [
3348
3319
  ];
3349
3320
 
3350
3321
  // src/overtype.js
3322
+ function buildActionsMap(buttons) {
3323
+ const map = {};
3324
+ (buttons || []).forEach((btn) => {
3325
+ if (!btn || btn.name === "separator")
3326
+ return;
3327
+ const id = btn.actionId || btn.name;
3328
+ if (btn.action) {
3329
+ map[id] = btn.action;
3330
+ }
3331
+ });
3332
+ return map;
3333
+ }
3334
+ function normalizeButtons(buttons) {
3335
+ const list = buttons || defaultToolbarButtons;
3336
+ if (!Array.isArray(list))
3337
+ return null;
3338
+ return list.map((btn) => ({
3339
+ name: (btn == null ? void 0 : btn.name) || null,
3340
+ actionId: (btn == null ? void 0 : btn.actionId) || (btn == null ? void 0 : btn.name) || null,
3341
+ icon: (btn == null ? void 0 : btn.icon) || null,
3342
+ title: (btn == null ? void 0 : btn.title) || null
3343
+ }));
3344
+ }
3345
+ function toolbarButtonsChanged(prevButtons, nextButtons) {
3346
+ const prev = normalizeButtons(prevButtons);
3347
+ const next = normalizeButtons(nextButtons);
3348
+ if (prev === null || next === null)
3349
+ return prev !== next;
3350
+ if (prev.length !== next.length)
3351
+ return true;
3352
+ for (let i = 0; i < prev.length; i++) {
3353
+ const a = prev[i];
3354
+ const b = next[i];
3355
+ if (a.name !== b.name || a.actionId !== b.actionId || a.icon !== b.icon || a.title !== b.title) {
3356
+ return true;
3357
+ }
3358
+ }
3359
+ return false;
3360
+ }
3351
3361
  var _OverType = class _OverType {
3352
3362
  /**
3353
3363
  * Constructor - Always returns an array of instances
@@ -3405,6 +3415,7 @@ var _OverType = class _OverType {
3405
3415
  this._buildFromScratch();
3406
3416
  }
3407
3417
  this.shortcuts = new ShortcutsManager(this);
3418
+ this._rebuildActionsMap();
3408
3419
  this.linkTooltip = new LinkTooltip(this);
3409
3420
  requestAnimationFrame(() => {
3410
3421
  requestAnimationFrame(() => {
@@ -3660,6 +3671,17 @@ var _OverType = class _OverType {
3660
3671
  this._toolbarInputListener = null;
3661
3672
  }
3662
3673
  }
3674
+ /**
3675
+ * Rebuild the action map from current toolbar button configuration
3676
+ * Called during init and reinit to keep shortcuts in sync with toolbar buttons
3677
+ * @private
3678
+ */
3679
+ _rebuildActionsMap() {
3680
+ this.actionsById = buildActionsMap(defaultToolbarButtons);
3681
+ if (this.options.toolbarButtons) {
3682
+ Object.assign(this.actionsById, buildActionsMap(this.options.toolbarButtons));
3683
+ }
3684
+ }
3663
3685
  /**
3664
3686
  * Apply options to the editor
3665
3687
  * @private
@@ -3921,6 +3943,40 @@ var _OverType = class _OverType {
3921
3943
  this._updateAutoHeight();
3922
3944
  }
3923
3945
  }
3946
+ /**
3947
+ * Execute an action by ID
3948
+ * Central dispatcher used by toolbar clicks, keyboard shortcuts, and programmatic calls
3949
+ * @param {string} actionId - The action identifier (e.g., 'toggleBold', 'insertLink')
3950
+ * @param {Event|null} event - Optional event that triggered the action
3951
+ * @returns {Promise<boolean>} Whether the action was executed successfully
3952
+ */
3953
+ async performAction(actionId, event = null) {
3954
+ var _a;
3955
+ const textarea = this.textarea;
3956
+ if (!textarea)
3957
+ return false;
3958
+ const action = (_a = this.actionsById) == null ? void 0 : _a[actionId];
3959
+ if (!action) {
3960
+ console.warn(`OverType: Unknown action "${actionId}"`);
3961
+ return false;
3962
+ }
3963
+ textarea.focus();
3964
+ try {
3965
+ await action({
3966
+ editor: this,
3967
+ getValue: () => this.getValue(),
3968
+ setValue: (value) => this.setValue(value),
3969
+ event
3970
+ });
3971
+ return true;
3972
+ } catch (error) {
3973
+ console.error(`OverType: Action "${actionId}" error:`, error);
3974
+ this.wrapper.dispatchEvent(new CustomEvent("button-error", {
3975
+ detail: { actionId, error }
3976
+ }));
3977
+ return false;
3978
+ }
3979
+ }
3924
3980
  /**
3925
3981
  * Get the rendered HTML of the current content
3926
3982
  * @param {Object} options - Rendering options
@@ -3977,7 +4033,17 @@ var _OverType = class _OverType {
3977
4033
  * @param {Object} options - New options to apply
3978
4034
  */
3979
4035
  reinit(options = {}) {
4036
+ var _a;
4037
+ const prevToolbarButtons = (_a = this.options) == null ? void 0 : _a.toolbarButtons;
3980
4038
  this.options = this._mergeOptions({ ...this.options, ...options });
4039
+ const toolbarNeedsRebuild = this.toolbar && this.options.toolbar && toolbarButtonsChanged(prevToolbarButtons, this.options.toolbarButtons);
4040
+ this._rebuildActionsMap();
4041
+ if (toolbarNeedsRebuild) {
4042
+ this._cleanupToolbarListeners();
4043
+ this.toolbar.destroy();
4044
+ this.toolbar = null;
4045
+ this._createToolbar();
4046
+ }
3981
4047
  this._applyOptions();
3982
4048
  this.updatePreview();
3983
4049
  }