overtype 2.3.10 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -11
- package/dist/overtype-webcomponent.esm.js +454 -96
- package/dist/overtype-webcomponent.esm.js.map +3 -3
- package/dist/overtype-webcomponent.js +454 -96
- package/dist/overtype-webcomponent.js.map +3 -3
- package/dist/overtype-webcomponent.min.js +57 -56
- package/dist/overtype.cjs +454 -96
- package/dist/overtype.cjs.map +3 -3
- package/dist/overtype.d.ts +12 -0
- package/dist/overtype.esm.js +454 -96
- package/dist/overtype.esm.js.map +3 -3
- package/dist/overtype.js +454 -96
- package/dist/overtype.js.map +3 -3
- package/dist/overtype.min.js +53 -52
- package/package.json +3 -3
- package/src/link-tooltip.js +18 -2
- package/src/overtype.d.ts +12 -0
- package/src/overtype.js +196 -70
- package/src/shortcuts.js +12 -0
- package/src/toolbar-buttons.js +10 -0
- package/src/toolbar.js +308 -49
package/dist/overtype.esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OverType v2.
|
|
2
|
+
* OverType v2.4.0
|
|
3
3
|
* A lightweight markdown editor library with perfect WYSIWYG alignment
|
|
4
4
|
* @license MIT
|
|
5
5
|
* @author David Miranda
|
|
@@ -758,6 +758,16 @@ var ShortcutsManager = class {
|
|
|
758
758
|
const modKey = isMac ? event.metaKey : event.ctrlKey;
|
|
759
759
|
if (!modKey)
|
|
760
760
|
return false;
|
|
761
|
+
if (event.key === "]") {
|
|
762
|
+
event.preventDefault();
|
|
763
|
+
this.editor.indentSelection();
|
|
764
|
+
return true;
|
|
765
|
+
}
|
|
766
|
+
if (event.key === "[") {
|
|
767
|
+
event.preventDefault();
|
|
768
|
+
this.editor.outdentSelection();
|
|
769
|
+
return true;
|
|
770
|
+
}
|
|
761
771
|
let actionId = null;
|
|
762
772
|
switch (event.key.toLowerCase()) {
|
|
763
773
|
case "b":
|
|
@@ -2870,6 +2880,10 @@ var Toolbar = class {
|
|
|
2870
2880
|
this.editor = editor;
|
|
2871
2881
|
this.container = null;
|
|
2872
2882
|
this.buttons = {};
|
|
2883
|
+
this.currentItemIndex = 0;
|
|
2884
|
+
this.handleDocumentClick = null;
|
|
2885
|
+
this.activeDropdown = null;
|
|
2886
|
+
this.activeDropdownButton = null;
|
|
2873
2887
|
this.toolbarButtons = options.toolbarButtons || [];
|
|
2874
2888
|
}
|
|
2875
2889
|
/**
|
|
@@ -2878,8 +2892,10 @@ var Toolbar = class {
|
|
|
2878
2892
|
create() {
|
|
2879
2893
|
this.container = document.createElement("div");
|
|
2880
2894
|
this.container.className = "overtype-toolbar";
|
|
2895
|
+
this.container.id = this.getInstanceElementId("toolbar");
|
|
2881
2896
|
this.container.setAttribute("role", "toolbar");
|
|
2882
2897
|
this.container.setAttribute("aria-label", "Formatting toolbar");
|
|
2898
|
+
this.container.setAttribute("aria-controls", this.editor.textarea.id);
|
|
2883
2899
|
this.toolbarButtons.forEach((buttonConfig) => {
|
|
2884
2900
|
if (buttonConfig.name === "separator") {
|
|
2885
2901
|
const separator = this.createSeparator();
|
|
@@ -2890,8 +2906,116 @@ var Toolbar = class {
|
|
|
2890
2906
|
this.container.appendChild(button);
|
|
2891
2907
|
}
|
|
2892
2908
|
});
|
|
2909
|
+
this.setupRovingTabIndex();
|
|
2910
|
+
this.updateButtonStates();
|
|
2893
2911
|
this.editor.container.insertBefore(this.container, this.editor.wrapper);
|
|
2894
2912
|
}
|
|
2913
|
+
/**
|
|
2914
|
+
* Build a stable id from the owning OverType instance
|
|
2915
|
+
*/
|
|
2916
|
+
getInstanceElementId(name) {
|
|
2917
|
+
return `overtype-${this.editor.instanceId}-${name}`;
|
|
2918
|
+
}
|
|
2919
|
+
/**
|
|
2920
|
+
* Configure toolbar focus management per the ARIA toolbar pattern
|
|
2921
|
+
*/
|
|
2922
|
+
setupRovingTabIndex() {
|
|
2923
|
+
const toolbarItems = this.getToolbarItems();
|
|
2924
|
+
if (toolbarItems.length === 0) {
|
|
2925
|
+
return;
|
|
2926
|
+
}
|
|
2927
|
+
this.currentItemIndex = this.getValidItemIndex(this.currentItemIndex);
|
|
2928
|
+
this.updateTabIndexes();
|
|
2929
|
+
this.container.addEventListener("keydown", (e) => {
|
|
2930
|
+
this.onToolbarKeydown(e);
|
|
2931
|
+
});
|
|
2932
|
+
this.container.addEventListener("focusin", (e) => {
|
|
2933
|
+
this.onToolbarFocusin(e);
|
|
2934
|
+
});
|
|
2935
|
+
}
|
|
2936
|
+
/**
|
|
2937
|
+
* Get toolbar buttons in DOM order for keyboard navigation
|
|
2938
|
+
*/
|
|
2939
|
+
getToolbarItems() {
|
|
2940
|
+
if (!this.container) {
|
|
2941
|
+
return [];
|
|
2942
|
+
}
|
|
2943
|
+
return Array.from(this.container.querySelectorAll(".overtype-toolbar-button"));
|
|
2944
|
+
}
|
|
2945
|
+
/**
|
|
2946
|
+
* Handle keyboard navigation within the toolbar
|
|
2947
|
+
*/
|
|
2948
|
+
onToolbarKeydown(e) {
|
|
2949
|
+
const toolbarItems = this.getToolbarItems();
|
|
2950
|
+
if (!toolbarItems.includes(e.target)) {
|
|
2951
|
+
return;
|
|
2952
|
+
}
|
|
2953
|
+
switch (e.key) {
|
|
2954
|
+
case "ArrowRight":
|
|
2955
|
+
e.preventDefault();
|
|
2956
|
+
this.focusItem(this.currentItemIndex + 1);
|
|
2957
|
+
break;
|
|
2958
|
+
case "ArrowLeft":
|
|
2959
|
+
e.preventDefault();
|
|
2960
|
+
this.focusItem(this.currentItemIndex - 1);
|
|
2961
|
+
break;
|
|
2962
|
+
case "Home":
|
|
2963
|
+
e.preventDefault();
|
|
2964
|
+
this.focusItem(0);
|
|
2965
|
+
break;
|
|
2966
|
+
case "End":
|
|
2967
|
+
e.preventDefault();
|
|
2968
|
+
this.focusItem(toolbarItems.length - 1);
|
|
2969
|
+
break;
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
/**
|
|
2973
|
+
* Remember the focused toolbar item as the toolbar tab stop
|
|
2974
|
+
*/
|
|
2975
|
+
onToolbarFocusin(e) {
|
|
2976
|
+
const focusedItemIndex = this.getToolbarItems().indexOf(e.target);
|
|
2977
|
+
if (focusedItemIndex === -1) {
|
|
2978
|
+
return;
|
|
2979
|
+
}
|
|
2980
|
+
this.currentItemIndex = focusedItemIndex;
|
|
2981
|
+
this.updateTabIndexes();
|
|
2982
|
+
}
|
|
2983
|
+
/**
|
|
2984
|
+
* Move focus to a toolbar item and make it the only tab stop
|
|
2985
|
+
*/
|
|
2986
|
+
focusItem(index) {
|
|
2987
|
+
const toolbarItems = this.getToolbarItems();
|
|
2988
|
+
if (toolbarItems.length === 0) {
|
|
2989
|
+
return;
|
|
2990
|
+
}
|
|
2991
|
+
this.currentItemIndex = this.getValidItemIndex(index, toolbarItems);
|
|
2992
|
+
this.updateTabIndexes();
|
|
2993
|
+
toolbarItems[this.currentItemIndex].focus();
|
|
2994
|
+
}
|
|
2995
|
+
/**
|
|
2996
|
+
* Normalize toolbar item indexes with wrapping
|
|
2997
|
+
*/
|
|
2998
|
+
getValidItemIndex(index, toolbarItems = this.getToolbarItems()) {
|
|
2999
|
+
const itemCount = toolbarItems.length;
|
|
3000
|
+
if (itemCount === 0) {
|
|
3001
|
+
return 0;
|
|
3002
|
+
}
|
|
3003
|
+
if (index < 0) {
|
|
3004
|
+
return itemCount - 1;
|
|
3005
|
+
}
|
|
3006
|
+
if (index >= itemCount) {
|
|
3007
|
+
return 0;
|
|
3008
|
+
}
|
|
3009
|
+
return index;
|
|
3010
|
+
}
|
|
3011
|
+
/**
|
|
3012
|
+
* Keep exactly one toolbar item in the page tab sequence
|
|
3013
|
+
*/
|
|
3014
|
+
updateTabIndexes() {
|
|
3015
|
+
this.getToolbarItems().forEach((item, index) => {
|
|
3016
|
+
item.tabIndex = index === this.currentItemIndex ? 0 : -1;
|
|
3017
|
+
});
|
|
3018
|
+
}
|
|
2895
3019
|
/**
|
|
2896
3020
|
* Create a toolbar separator
|
|
2897
3021
|
*/
|
|
@@ -2915,10 +3039,22 @@ var Toolbar = class {
|
|
|
2915
3039
|
if (buttonConfig.name === "viewMode") {
|
|
2916
3040
|
button.classList.add("has-dropdown");
|
|
2917
3041
|
button.dataset.dropdown = "true";
|
|
2918
|
-
button.
|
|
3042
|
+
button.setAttribute("aria-haspopup", "menu");
|
|
3043
|
+
button.setAttribute("aria-expanded", "false");
|
|
3044
|
+
button._clickHandler = (e) => {
|
|
2919
3045
|
e.preventDefault();
|
|
2920
3046
|
this.toggleViewModeDropdown(button);
|
|
2921
|
-
}
|
|
3047
|
+
};
|
|
3048
|
+
button._keydownHandler = (e) => {
|
|
3049
|
+
if (!["ArrowDown", "ArrowUp", "Enter", " "].includes(e.key)) {
|
|
3050
|
+
return;
|
|
3051
|
+
}
|
|
3052
|
+
e.preventDefault();
|
|
3053
|
+
const placement = e.key === "ArrowUp" ? "last" : "current";
|
|
3054
|
+
this.openViewModeDropdown(button, placement);
|
|
3055
|
+
};
|
|
3056
|
+
button.addEventListener("click", button._clickHandler);
|
|
3057
|
+
button.addEventListener("keydown", button._keydownHandler);
|
|
2922
3058
|
return button;
|
|
2923
3059
|
}
|
|
2924
3060
|
button._clickHandler = (e) => {
|
|
@@ -2973,12 +3109,17 @@ var Toolbar = class {
|
|
|
2973
3109
|
* Not exposed to users - viewMode button behavior is fixed
|
|
2974
3110
|
*/
|
|
2975
3111
|
toggleViewModeDropdown(button) {
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
existingDropdown.remove();
|
|
2979
|
-
button.classList.remove("dropdown-active");
|
|
3112
|
+
if (this.activeDropdown) {
|
|
3113
|
+
this.closeViewModeDropdown(button);
|
|
2980
3114
|
return;
|
|
2981
3115
|
}
|
|
3116
|
+
this.openViewModeDropdown(button);
|
|
3117
|
+
}
|
|
3118
|
+
/**
|
|
3119
|
+
* Open the view mode dropdown
|
|
3120
|
+
*/
|
|
3121
|
+
openViewModeDropdown(button, focusPlacement = null) {
|
|
3122
|
+
this.closeViewModeDropdown(button);
|
|
2982
3123
|
button.classList.add("dropdown-active");
|
|
2983
3124
|
const dropdown = this.createViewModeDropdown(button);
|
|
2984
3125
|
const rect = button.getBoundingClientRect();
|
|
@@ -2986,16 +3127,42 @@ var Toolbar = class {
|
|
|
2986
3127
|
dropdown.style.top = `${rect.bottom + 5}px`;
|
|
2987
3128
|
dropdown.style.left = `${rect.left}px`;
|
|
2988
3129
|
document.body.appendChild(dropdown);
|
|
3130
|
+
this.activeDropdown = dropdown;
|
|
3131
|
+
this.activeDropdownButton = button;
|
|
3132
|
+
button.setAttribute("aria-controls", dropdown.id);
|
|
3133
|
+
button.setAttribute("aria-expanded", "true");
|
|
2989
3134
|
this.handleDocumentClick = (e) => {
|
|
2990
3135
|
if (!dropdown.contains(e.target) && !button.contains(e.target)) {
|
|
2991
|
-
|
|
2992
|
-
button.classList.remove("dropdown-active");
|
|
2993
|
-
document.removeEventListener("click", this.handleDocumentClick);
|
|
3136
|
+
this.closeViewModeDropdown(button);
|
|
2994
3137
|
}
|
|
2995
3138
|
};
|
|
2996
3139
|
setTimeout(() => {
|
|
2997
3140
|
document.addEventListener("click", this.handleDocumentClick);
|
|
2998
3141
|
}, 0);
|
|
3142
|
+
if (focusPlacement) {
|
|
3143
|
+
this.focusViewModeMenuItem(dropdown, focusPlacement);
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
/**
|
|
3147
|
+
* Close the view mode dropdown
|
|
3148
|
+
*/
|
|
3149
|
+
closeViewModeDropdown(button = this.activeDropdownButton, returnFocus = false) {
|
|
3150
|
+
if (this.activeDropdown) {
|
|
3151
|
+
this.activeDropdown.remove();
|
|
3152
|
+
this.activeDropdown = null;
|
|
3153
|
+
}
|
|
3154
|
+
if (button) {
|
|
3155
|
+
button.classList.remove("dropdown-active");
|
|
3156
|
+
button.setAttribute("aria-expanded", "false");
|
|
3157
|
+
}
|
|
3158
|
+
if (this.handleDocumentClick) {
|
|
3159
|
+
document.removeEventListener("click", this.handleDocumentClick);
|
|
3160
|
+
this.handleDocumentClick = null;
|
|
3161
|
+
}
|
|
3162
|
+
this.activeDropdownButton = null;
|
|
3163
|
+
if (returnFocus && button) {
|
|
3164
|
+
button.focus();
|
|
3165
|
+
}
|
|
2999
3166
|
}
|
|
3000
3167
|
/**
|
|
3001
3168
|
* Create view mode dropdown menu (internal implementation)
|
|
@@ -3003,6 +3170,12 @@ var Toolbar = class {
|
|
|
3003
3170
|
createViewModeDropdown(button) {
|
|
3004
3171
|
const dropdown = document.createElement("div");
|
|
3005
3172
|
dropdown.className = "overtype-dropdown-menu";
|
|
3173
|
+
dropdown.id = this.getInstanceElementId("toolbar-view-mode-menu");
|
|
3174
|
+
dropdown.setAttribute("role", "menu");
|
|
3175
|
+
dropdown.setAttribute("aria-label", "View mode");
|
|
3176
|
+
dropdown.addEventListener("keydown", (e) => {
|
|
3177
|
+
this.onViewModeMenuKeydown(e, button);
|
|
3178
|
+
});
|
|
3006
3179
|
const items = [
|
|
3007
3180
|
{ id: "normal", label: "Normal Edit", icon: "\u2713" },
|
|
3008
3181
|
{ id: "plain", label: "Plain Textarea", icon: "\u2713" },
|
|
@@ -3013,12 +3186,15 @@ var Toolbar = class {
|
|
|
3013
3186
|
const menuItem = document.createElement("button");
|
|
3014
3187
|
menuItem.className = "overtype-dropdown-item";
|
|
3015
3188
|
menuItem.type = "button";
|
|
3189
|
+
menuItem.tabIndex = -1;
|
|
3190
|
+
menuItem.setAttribute("role", "menuitemradio");
|
|
3191
|
+
menuItem.setAttribute("aria-checked", String(item.id === currentMode));
|
|
3016
3192
|
menuItem.textContent = item.label;
|
|
3017
3193
|
if (item.id === currentMode) {
|
|
3018
3194
|
menuItem.classList.add("active");
|
|
3019
|
-
menuItem.setAttribute("aria-current", "true");
|
|
3020
3195
|
const checkmark = document.createElement("span");
|
|
3021
3196
|
checkmark.className = "overtype-dropdown-icon";
|
|
3197
|
+
checkmark.setAttribute("aria-hidden", "true");
|
|
3022
3198
|
checkmark.textContent = item.icon;
|
|
3023
3199
|
menuItem.prepend(checkmark);
|
|
3024
3200
|
}
|
|
@@ -3036,14 +3212,77 @@ var Toolbar = class {
|
|
|
3036
3212
|
this.editor.showNormalEditMode();
|
|
3037
3213
|
break;
|
|
3038
3214
|
}
|
|
3039
|
-
|
|
3040
|
-
button.classList.remove("dropdown-active");
|
|
3041
|
-
document.removeEventListener("click", this.handleDocumentClick);
|
|
3215
|
+
this.closeViewModeDropdown(button, true);
|
|
3042
3216
|
});
|
|
3043
3217
|
dropdown.appendChild(menuItem);
|
|
3044
3218
|
});
|
|
3045
3219
|
return dropdown;
|
|
3046
3220
|
}
|
|
3221
|
+
/**
|
|
3222
|
+
* Handle keyboard navigation inside the view mode menu
|
|
3223
|
+
*/
|
|
3224
|
+
onViewModeMenuKeydown(e, button) {
|
|
3225
|
+
const menuItems = this.getViewModeMenuItems();
|
|
3226
|
+
const currentIndex = menuItems.indexOf(e.target);
|
|
3227
|
+
if (currentIndex === -1) {
|
|
3228
|
+
return;
|
|
3229
|
+
}
|
|
3230
|
+
switch (e.key) {
|
|
3231
|
+
case "ArrowDown":
|
|
3232
|
+
e.preventDefault();
|
|
3233
|
+
this.focusViewModeMenuItem(this.activeDropdown, currentIndex + 1);
|
|
3234
|
+
break;
|
|
3235
|
+
case "ArrowUp":
|
|
3236
|
+
e.preventDefault();
|
|
3237
|
+
this.focusViewModeMenuItem(this.activeDropdown, currentIndex - 1);
|
|
3238
|
+
break;
|
|
3239
|
+
case "Home":
|
|
3240
|
+
e.preventDefault();
|
|
3241
|
+
this.focusViewModeMenuItem(this.activeDropdown, "first");
|
|
3242
|
+
break;
|
|
3243
|
+
case "End":
|
|
3244
|
+
e.preventDefault();
|
|
3245
|
+
this.focusViewModeMenuItem(this.activeDropdown, "last");
|
|
3246
|
+
break;
|
|
3247
|
+
case "Escape":
|
|
3248
|
+
e.preventDefault();
|
|
3249
|
+
this.closeViewModeDropdown(button, true);
|
|
3250
|
+
break;
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
/**
|
|
3254
|
+
* Focus a view mode menu item by index or placement
|
|
3255
|
+
*/
|
|
3256
|
+
focusViewModeMenuItem(dropdown, placement) {
|
|
3257
|
+
const menuItems = this.getViewModeMenuItems(dropdown);
|
|
3258
|
+
if (menuItems.length === 0) {
|
|
3259
|
+
return;
|
|
3260
|
+
}
|
|
3261
|
+
let index = placement;
|
|
3262
|
+
if (placement === "first") {
|
|
3263
|
+
index = 0;
|
|
3264
|
+
} else if (placement === "last") {
|
|
3265
|
+
index = menuItems.length - 1;
|
|
3266
|
+
} else if (placement === "current") {
|
|
3267
|
+
index = menuItems.findIndex((item) => item.getAttribute("aria-checked") === "true");
|
|
3268
|
+
}
|
|
3269
|
+
if (index < 0) {
|
|
3270
|
+
index = menuItems.length - 1;
|
|
3271
|
+
}
|
|
3272
|
+
if (index >= menuItems.length) {
|
|
3273
|
+
index = 0;
|
|
3274
|
+
}
|
|
3275
|
+
menuItems[index].focus();
|
|
3276
|
+
}
|
|
3277
|
+
/**
|
|
3278
|
+
* Get the current view mode menu items
|
|
3279
|
+
*/
|
|
3280
|
+
getViewModeMenuItems(dropdown = this.activeDropdown) {
|
|
3281
|
+
if (!dropdown) {
|
|
3282
|
+
return [];
|
|
3283
|
+
}
|
|
3284
|
+
return Array.from(dropdown.querySelectorAll('[role="menuitemradio"]'));
|
|
3285
|
+
}
|
|
3047
3286
|
/**
|
|
3048
3287
|
* Update active states of toolbar buttons
|
|
3049
3288
|
*/
|
|
@@ -3057,39 +3296,14 @@ var Toolbar = class {
|
|
|
3057
3296
|
Object.entries(this.buttons).forEach(([name, button]) => {
|
|
3058
3297
|
if (name === "viewMode")
|
|
3059
3298
|
return;
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
isActive = activeFormats.includes("bold");
|
|
3064
|
-
break;
|
|
3065
|
-
case "italic":
|
|
3066
|
-
isActive = activeFormats.includes("italic");
|
|
3067
|
-
break;
|
|
3068
|
-
case "code":
|
|
3069
|
-
isActive = false;
|
|
3070
|
-
break;
|
|
3071
|
-
case "bulletList":
|
|
3072
|
-
isActive = activeFormats.includes("bullet-list");
|
|
3073
|
-
break;
|
|
3074
|
-
case "orderedList":
|
|
3075
|
-
isActive = activeFormats.includes("numbered-list");
|
|
3076
|
-
break;
|
|
3077
|
-
case "taskList":
|
|
3078
|
-
isActive = activeFormats.includes("task-list");
|
|
3079
|
-
break;
|
|
3080
|
-
case "quote":
|
|
3081
|
-
isActive = activeFormats.includes("quote");
|
|
3082
|
-
break;
|
|
3083
|
-
case "h1":
|
|
3084
|
-
isActive = activeFormats.includes("header");
|
|
3085
|
-
break;
|
|
3086
|
-
case "h2":
|
|
3087
|
-
isActive = activeFormats.includes("header-2");
|
|
3088
|
-
break;
|
|
3089
|
-
case "h3":
|
|
3090
|
-
isActive = activeFormats.includes("header-3");
|
|
3091
|
-
break;
|
|
3299
|
+
const buttonConfig = this.toolbarButtons.find((buttonConfig2) => buttonConfig2.name === name);
|
|
3300
|
+
if (!(buttonConfig == null ? void 0 : buttonConfig.isActive)) {
|
|
3301
|
+
return;
|
|
3092
3302
|
}
|
|
3303
|
+
const isActive = Boolean(buttonConfig.isActive({
|
|
3304
|
+
editor: this.editor,
|
|
3305
|
+
activeFormats
|
|
3306
|
+
}));
|
|
3093
3307
|
button.classList.toggle("active", isActive);
|
|
3094
3308
|
button.setAttribute("aria-pressed", isActive.toString());
|
|
3095
3309
|
});
|
|
@@ -3111,14 +3325,21 @@ var Toolbar = class {
|
|
|
3111
3325
|
*/
|
|
3112
3326
|
destroy() {
|
|
3113
3327
|
if (this.container) {
|
|
3114
|
-
if (this.
|
|
3328
|
+
if (this.activeDropdown) {
|
|
3329
|
+
this.closeViewModeDropdown();
|
|
3330
|
+
} else if (this.handleDocumentClick) {
|
|
3115
3331
|
document.removeEventListener("click", this.handleDocumentClick);
|
|
3332
|
+
this.handleDocumentClick = null;
|
|
3116
3333
|
}
|
|
3117
3334
|
Object.values(this.buttons).forEach((button) => {
|
|
3118
3335
|
if (button._clickHandler) {
|
|
3119
3336
|
button.removeEventListener("click", button._clickHandler);
|
|
3120
3337
|
delete button._clickHandler;
|
|
3121
3338
|
}
|
|
3339
|
+
if (button._keydownHandler) {
|
|
3340
|
+
button.removeEventListener("keydown", button._keydownHandler);
|
|
3341
|
+
delete button._keydownHandler;
|
|
3342
|
+
}
|
|
3122
3343
|
});
|
|
3123
3344
|
this.container.remove();
|
|
3124
3345
|
this.container = null;
|
|
@@ -4385,7 +4606,10 @@ var LinkTooltip = class {
|
|
|
4385
4606
|
e.preventDefault();
|
|
4386
4607
|
e.stopPropagation();
|
|
4387
4608
|
if (this.currentLink) {
|
|
4388
|
-
|
|
4609
|
+
const safeUrl = MarkdownParser.sanitizeUrl(this.currentLink.url);
|
|
4610
|
+
if (safeUrl !== "#") {
|
|
4611
|
+
window.open(safeUrl, "_blank");
|
|
4612
|
+
}
|
|
4389
4613
|
this.hide();
|
|
4390
4614
|
}
|
|
4391
4615
|
});
|
|
@@ -4413,7 +4637,7 @@ var LinkTooltip = class {
|
|
|
4413
4637
|
if (position >= start && position <= end) {
|
|
4414
4638
|
return {
|
|
4415
4639
|
text: match[1],
|
|
4416
|
-
url: match[2],
|
|
4640
|
+
url: this.transformUrl(match[2]),
|
|
4417
4641
|
index: linkIndex,
|
|
4418
4642
|
start,
|
|
4419
4643
|
end
|
|
@@ -4423,6 +4647,18 @@ var LinkTooltip = class {
|
|
|
4423
4647
|
}
|
|
4424
4648
|
return null;
|
|
4425
4649
|
}
|
|
4650
|
+
transformUrl(url) {
|
|
4651
|
+
const transform = this.editor.options.transformLinkUrl;
|
|
4652
|
+
if (typeof transform !== "function")
|
|
4653
|
+
return url;
|
|
4654
|
+
try {
|
|
4655
|
+
const result = transform(url);
|
|
4656
|
+
return typeof result === "string" ? result : url;
|
|
4657
|
+
} catch (e) {
|
|
4658
|
+
console.warn("transformLinkUrl threw:", e);
|
|
4659
|
+
return url;
|
|
4660
|
+
}
|
|
4661
|
+
}
|
|
4426
4662
|
async show(linkInfo) {
|
|
4427
4663
|
this.currentLink = linkInfo;
|
|
4428
4664
|
this.cancelHide();
|
|
@@ -4574,6 +4810,7 @@ var toolbarButtons = {
|
|
|
4574
4810
|
actionId: "toggleBold",
|
|
4575
4811
|
icon: boldIcon,
|
|
4576
4812
|
title: "Bold (Ctrl+B)",
|
|
4813
|
+
isActive: ({ activeFormats }) => activeFormats.includes("bold"),
|
|
4577
4814
|
action: ({ editor }) => {
|
|
4578
4815
|
toggleBold(editor.textarea);
|
|
4579
4816
|
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4584,6 +4821,7 @@ var toolbarButtons = {
|
|
|
4584
4821
|
actionId: "toggleItalic",
|
|
4585
4822
|
icon: italicIcon,
|
|
4586
4823
|
title: "Italic (Ctrl+I)",
|
|
4824
|
+
isActive: ({ activeFormats }) => activeFormats.includes("italic"),
|
|
4587
4825
|
action: ({ editor }) => {
|
|
4588
4826
|
toggleItalic(editor.textarea);
|
|
4589
4827
|
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4594,6 +4832,7 @@ var toolbarButtons = {
|
|
|
4594
4832
|
actionId: "toggleCode",
|
|
4595
4833
|
icon: codeIcon,
|
|
4596
4834
|
title: "Inline Code",
|
|
4835
|
+
isActive: () => false,
|
|
4597
4836
|
action: ({ editor }) => {
|
|
4598
4837
|
toggleCode(editor.textarea);
|
|
4599
4838
|
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4618,6 +4857,7 @@ var toolbarButtons = {
|
|
|
4618
4857
|
actionId: "toggleH1",
|
|
4619
4858
|
icon: h1Icon,
|
|
4620
4859
|
title: "Heading 1",
|
|
4860
|
+
isActive: ({ activeFormats }) => activeFormats.includes("header"),
|
|
4621
4861
|
action: ({ editor }) => {
|
|
4622
4862
|
toggleH1(editor.textarea);
|
|
4623
4863
|
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4628,6 +4868,7 @@ var toolbarButtons = {
|
|
|
4628
4868
|
actionId: "toggleH2",
|
|
4629
4869
|
icon: h2Icon,
|
|
4630
4870
|
title: "Heading 2",
|
|
4871
|
+
isActive: ({ activeFormats }) => activeFormats.includes("header-2"),
|
|
4631
4872
|
action: ({ editor }) => {
|
|
4632
4873
|
toggleH2(editor.textarea);
|
|
4633
4874
|
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4638,6 +4879,7 @@ var toolbarButtons = {
|
|
|
4638
4879
|
actionId: "toggleH3",
|
|
4639
4880
|
icon: h3Icon,
|
|
4640
4881
|
title: "Heading 3",
|
|
4882
|
+
isActive: ({ activeFormats }) => activeFormats.includes("header-3"),
|
|
4641
4883
|
action: ({ editor }) => {
|
|
4642
4884
|
toggleH3(editor.textarea);
|
|
4643
4885
|
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4648,6 +4890,7 @@ var toolbarButtons = {
|
|
|
4648
4890
|
actionId: "toggleBulletList",
|
|
4649
4891
|
icon: bulletListIcon,
|
|
4650
4892
|
title: "Bullet List",
|
|
4893
|
+
isActive: ({ activeFormats }) => activeFormats.includes("bullet-list"),
|
|
4651
4894
|
action: ({ editor }) => {
|
|
4652
4895
|
toggleBulletList(editor.textarea);
|
|
4653
4896
|
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4658,6 +4901,7 @@ var toolbarButtons = {
|
|
|
4658
4901
|
actionId: "toggleNumberedList",
|
|
4659
4902
|
icon: orderedListIcon,
|
|
4660
4903
|
title: "Numbered List",
|
|
4904
|
+
isActive: ({ activeFormats }) => activeFormats.includes("numbered-list"),
|
|
4661
4905
|
action: ({ editor }) => {
|
|
4662
4906
|
toggleNumberedList(editor.textarea);
|
|
4663
4907
|
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4668,6 +4912,7 @@ var toolbarButtons = {
|
|
|
4668
4912
|
actionId: "toggleTaskList",
|
|
4669
4913
|
icon: taskListIcon,
|
|
4670
4914
|
title: "Task List",
|
|
4915
|
+
isActive: ({ activeFormats }) => activeFormats.includes("task-list"),
|
|
4671
4916
|
action: ({ editor }) => {
|
|
4672
4917
|
if (toggleTaskList) {
|
|
4673
4918
|
toggleTaskList(editor.textarea);
|
|
@@ -4680,6 +4925,7 @@ var toolbarButtons = {
|
|
|
4680
4925
|
actionId: "toggleQuote",
|
|
4681
4926
|
icon: quoteIcon,
|
|
4682
4927
|
title: "Quote",
|
|
4928
|
+
isActive: ({ activeFormats }) => activeFormats.includes("quote"),
|
|
4683
4929
|
action: ({ editor }) => {
|
|
4684
4930
|
toggleQuote(editor.textarea);
|
|
4685
4931
|
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4741,6 +4987,17 @@ var defaultToolbarButtons = [
|
|
|
4741
4987
|
];
|
|
4742
4988
|
|
|
4743
4989
|
// src/overtype.js
|
|
4990
|
+
var _isSafariCache;
|
|
4991
|
+
function isSafariBrowser() {
|
|
4992
|
+
if (_isSafariCache !== void 0)
|
|
4993
|
+
return _isSafariCache;
|
|
4994
|
+
_isSafariCache = false;
|
|
4995
|
+
if (typeof navigator !== "undefined") {
|
|
4996
|
+
const ua = navigator.userAgent || "";
|
|
4997
|
+
_isSafariCache = /^((?!chrome|android|crios|fxios|edg|opr).)*safari/i.test(ua) || /iPad|iPhone|iPod/.test(ua) || navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1 && /Safari/.test(ua);
|
|
4998
|
+
}
|
|
4999
|
+
return _isSafariCache;
|
|
5000
|
+
}
|
|
4744
5001
|
function buildActionsMap(buttons) {
|
|
4745
5002
|
const map = {};
|
|
4746
5003
|
(buttons || []).forEach((btn) => {
|
|
@@ -4815,6 +5072,8 @@ var _OverType = class _OverType {
|
|
|
4815
5072
|
this.options = this._mergeOptions(options);
|
|
4816
5073
|
this.instanceId = ++_OverType.instanceCount;
|
|
4817
5074
|
this.initialized = false;
|
|
5075
|
+
this._isSafari = isSafariBrowser();
|
|
5076
|
+
this._safariReflowRaf = null;
|
|
4818
5077
|
_OverType.injectStyles();
|
|
4819
5078
|
_OverType.initGlobalListeners();
|
|
4820
5079
|
const container = element.querySelector(".overtype-container");
|
|
@@ -4889,8 +5148,10 @@ var _OverType = class _OverType {
|
|
|
4889
5148
|
// Enable smart list continuation
|
|
4890
5149
|
codeHighlighter: null,
|
|
4891
5150
|
// Per-instance code highlighter
|
|
4892
|
-
spellcheck: false
|
|
5151
|
+
spellcheck: false,
|
|
4893
5152
|
// Browser spellcheck (disabled by default)
|
|
5153
|
+
transformLinkUrl: null
|
|
5154
|
+
// Transform URLs shown/opened in the link tooltip
|
|
4894
5155
|
};
|
|
4895
5156
|
const { theme, colors, ...cleanOptions } = options;
|
|
4896
5157
|
return {
|
|
@@ -4943,6 +5204,8 @@ var _OverType = class _OverType {
|
|
|
4943
5204
|
this.wrapper._instance = this;
|
|
4944
5205
|
this._applyInstanceCSSVars();
|
|
4945
5206
|
this._configureTextarea();
|
|
5207
|
+
this._ensureTextareaId();
|
|
5208
|
+
this._syncPreviewInteractivity();
|
|
4946
5209
|
this._applyOptions();
|
|
4947
5210
|
}
|
|
4948
5211
|
/**
|
|
@@ -5006,6 +5269,7 @@ var _OverType = class _OverType {
|
|
|
5006
5269
|
}
|
|
5007
5270
|
});
|
|
5008
5271
|
}
|
|
5272
|
+
this._ensureTextareaId();
|
|
5009
5273
|
this.preview = document.createElement("div");
|
|
5010
5274
|
this.preview.className = "overtype-preview";
|
|
5011
5275
|
this.preview.setAttribute("aria-hidden", "true");
|
|
@@ -5029,6 +5293,7 @@ var _OverType = class _OverType {
|
|
|
5029
5293
|
} else {
|
|
5030
5294
|
this.container.classList.remove("overtype-auto-resize");
|
|
5031
5295
|
}
|
|
5296
|
+
this._syncPreviewInteractivity();
|
|
5032
5297
|
}
|
|
5033
5298
|
/**
|
|
5034
5299
|
* Configure textarea attributes
|
|
@@ -5043,6 +5308,31 @@ var _OverType = class _OverType {
|
|
|
5043
5308
|
this.textarea.setAttribute("data-gramm_editor", "false");
|
|
5044
5309
|
this.textarea.setAttribute("data-enable-grammarly", "false");
|
|
5045
5310
|
}
|
|
5311
|
+
/**
|
|
5312
|
+
* Ensure the textarea can be referenced by aria-controls
|
|
5313
|
+
* @private
|
|
5314
|
+
*/
|
|
5315
|
+
_ensureTextareaId() {
|
|
5316
|
+
if (!this.textarea.id) {
|
|
5317
|
+
this.textarea.id = `overtype-${this.instanceId}-input`;
|
|
5318
|
+
}
|
|
5319
|
+
}
|
|
5320
|
+
/**
|
|
5321
|
+
* Keep rendered preview content out of keyboard navigation until Preview mode.
|
|
5322
|
+
* @private
|
|
5323
|
+
*/
|
|
5324
|
+
_syncPreviewInteractivity() {
|
|
5325
|
+
if (!this.preview || !this.container)
|
|
5326
|
+
return;
|
|
5327
|
+
const isPreviewMode = this.container.dataset.mode === "preview";
|
|
5328
|
+
this.preview.inert = !isPreviewMode;
|
|
5329
|
+
this.preview.toggleAttribute("inert", !isPreviewMode);
|
|
5330
|
+
if (isPreviewMode) {
|
|
5331
|
+
this.preview.removeAttribute("aria-hidden");
|
|
5332
|
+
return;
|
|
5333
|
+
}
|
|
5334
|
+
this.preview.setAttribute("aria-hidden", "true");
|
|
5335
|
+
}
|
|
5046
5336
|
/**
|
|
5047
5337
|
* Create and setup toolbar
|
|
5048
5338
|
* @private
|
|
@@ -5381,6 +5671,29 @@ var _OverType = class _OverType {
|
|
|
5381
5671
|
handleInput(event) {
|
|
5382
5672
|
this.updatePreview();
|
|
5383
5673
|
this._notifyChange();
|
|
5674
|
+
this._scheduleSafariReflow();
|
|
5675
|
+
}
|
|
5676
|
+
/**
|
|
5677
|
+
* Force Safari to re-shape stale textarea text after an edit.
|
|
5678
|
+
* Safari can leave a textarea's glyph layout cached after incremental edits,
|
|
5679
|
+
* desyncing the caret/wrap from the styled preview overlay. Toggling
|
|
5680
|
+
* letter-spacing (with !important to beat the stylesheet rule) and reading
|
|
5681
|
+
* offsetHeight forces a synchronous re-shape. Safari-only, coalesced to one
|
|
5682
|
+
* run per animation frame.
|
|
5683
|
+
* @private
|
|
5684
|
+
*/
|
|
5685
|
+
_scheduleSafariReflow() {
|
|
5686
|
+
if (!this._isSafari || this._safariReflowRaf)
|
|
5687
|
+
return;
|
|
5688
|
+
this._safariReflowRaf = requestAnimationFrame(() => {
|
|
5689
|
+
this._safariReflowRaf = null;
|
|
5690
|
+
const ta = this.textarea;
|
|
5691
|
+
if (!ta)
|
|
5692
|
+
return;
|
|
5693
|
+
ta.style.setProperty("letter-spacing", "-0.001px", "important");
|
|
5694
|
+
void ta.offsetHeight;
|
|
5695
|
+
ta.style.removeProperty("letter-spacing");
|
|
5696
|
+
});
|
|
5384
5697
|
}
|
|
5385
5698
|
/**
|
|
5386
5699
|
* Handle focus events
|
|
@@ -5408,49 +5721,11 @@ var _OverType = class _OverType {
|
|
|
5408
5721
|
if (event.key === "Tab") {
|
|
5409
5722
|
const start = this.textarea.selectionStart;
|
|
5410
5723
|
const end = this.textarea.selectionEnd;
|
|
5411
|
-
|
|
5412
|
-
|
|
5724
|
+
if (start !== end && this._canEditTextarea()) {
|
|
5725
|
+
event.preventDefault();
|
|
5726
|
+
event.shiftKey ? this.outdentSelection() : this.indentSelection();
|
|
5413
5727
|
return;
|
|
5414
5728
|
}
|
|
5415
|
-
event.preventDefault();
|
|
5416
|
-
if (start !== end && event.shiftKey) {
|
|
5417
|
-
const before = value.substring(0, start);
|
|
5418
|
-
const selection = value.substring(start, end);
|
|
5419
|
-
const after = value.substring(end);
|
|
5420
|
-
const lines = selection.split("\n");
|
|
5421
|
-
const outdented = lines.map((line) => line.replace(/^ /, "")).join("\n");
|
|
5422
|
-
if (document.execCommand) {
|
|
5423
|
-
this.textarea.setSelectionRange(start, end);
|
|
5424
|
-
document.execCommand("insertText", false, outdented);
|
|
5425
|
-
} else {
|
|
5426
|
-
this.textarea.value = before + outdented + after;
|
|
5427
|
-
this.textarea.selectionStart = start;
|
|
5428
|
-
this.textarea.selectionEnd = start + outdented.length;
|
|
5429
|
-
}
|
|
5430
|
-
} else if (start !== end) {
|
|
5431
|
-
const before = value.substring(0, start);
|
|
5432
|
-
const selection = value.substring(start, end);
|
|
5433
|
-
const after = value.substring(end);
|
|
5434
|
-
const lines = selection.split("\n");
|
|
5435
|
-
const indented = lines.map((line) => " " + line).join("\n");
|
|
5436
|
-
if (document.execCommand) {
|
|
5437
|
-
this.textarea.setSelectionRange(start, end);
|
|
5438
|
-
document.execCommand("insertText", false, indented);
|
|
5439
|
-
} else {
|
|
5440
|
-
this.textarea.value = before + indented + after;
|
|
5441
|
-
this.textarea.selectionStart = start;
|
|
5442
|
-
this.textarea.selectionEnd = start + indented.length;
|
|
5443
|
-
}
|
|
5444
|
-
} else {
|
|
5445
|
-
if (document.execCommand) {
|
|
5446
|
-
document.execCommand("insertText", false, " ");
|
|
5447
|
-
} else {
|
|
5448
|
-
this.textarea.value = value.substring(0, start) + " " + value.substring(end);
|
|
5449
|
-
this.textarea.selectionStart = this.textarea.selectionEnd = start + 2;
|
|
5450
|
-
}
|
|
5451
|
-
}
|
|
5452
|
-
this.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
5453
|
-
return;
|
|
5454
5729
|
}
|
|
5455
5730
|
if (event.key === "Enter" && !event.shiftKey && !event.metaKey && !event.ctrlKey && this.options.smartLists) {
|
|
5456
5731
|
if (this.handleSmartListContinuation()) {
|
|
@@ -5587,6 +5862,7 @@ var _OverType = class _OverType {
|
|
|
5587
5862
|
}
|
|
5588
5863
|
if (didChange) {
|
|
5589
5864
|
this._notifyChange();
|
|
5865
|
+
this._scheduleSafariReflow();
|
|
5590
5866
|
}
|
|
5591
5867
|
}
|
|
5592
5868
|
/**
|
|
@@ -5647,6 +5923,63 @@ var _OverType = class _OverType {
|
|
|
5647
5923
|
getPreviewHTML() {
|
|
5648
5924
|
return this.preview.innerHTML;
|
|
5649
5925
|
}
|
|
5926
|
+
/**
|
|
5927
|
+
* Indent the current line or selected lines by two spaces.
|
|
5928
|
+
*/
|
|
5929
|
+
indentSelection() {
|
|
5930
|
+
this._replaceSelectedLines((line) => ` ${line}`);
|
|
5931
|
+
}
|
|
5932
|
+
/**
|
|
5933
|
+
* Outdent the current line or selected lines by up to two spaces or one tab.
|
|
5934
|
+
*/
|
|
5935
|
+
outdentSelection() {
|
|
5936
|
+
this._replaceSelectedLines((line) => line.replace(/^( {1,2}|\t)/, ""));
|
|
5937
|
+
}
|
|
5938
|
+
/**
|
|
5939
|
+
* Replace full lines touched by the current selection.
|
|
5940
|
+
* @private
|
|
5941
|
+
*/
|
|
5942
|
+
_replaceSelectedLines(transformLine) {
|
|
5943
|
+
if (!this._canEditTextarea())
|
|
5944
|
+
return false;
|
|
5945
|
+
const textarea = this.textarea;
|
|
5946
|
+
const { selectionStart, selectionEnd, value } = textarea;
|
|
5947
|
+
const lineStart = value.lastIndexOf("\n", selectionStart - 1) + 1;
|
|
5948
|
+
const effectiveEnd = this._effectiveSelectionEnd(value, selectionStart, selectionEnd);
|
|
5949
|
+
const lineEndOffset = value.indexOf("\n", effectiveEnd);
|
|
5950
|
+
const lineEnd = lineEndOffset === -1 ? value.length : lineEndOffset;
|
|
5951
|
+
const selectedLines = value.slice(lineStart, lineEnd);
|
|
5952
|
+
const replacement = selectedLines.split("\n").map(transformLine).join("\n");
|
|
5953
|
+
if (replacement === selectedLines)
|
|
5954
|
+
return false;
|
|
5955
|
+
textarea.setSelectionRange(lineStart, lineEnd);
|
|
5956
|
+
let inserted = false;
|
|
5957
|
+
try {
|
|
5958
|
+
inserted = document.execCommand("insertText", false, replacement);
|
|
5959
|
+
} catch (_) {
|
|
5960
|
+
}
|
|
5961
|
+
if (!inserted) {
|
|
5962
|
+
textarea.setRangeText(replacement, lineStart, lineEnd, "preserve");
|
|
5963
|
+
}
|
|
5964
|
+
textarea.setSelectionRange(lineStart, lineStart + replacement.length);
|
|
5965
|
+
textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
5966
|
+
return true;
|
|
5967
|
+
}
|
|
5968
|
+
/**
|
|
5969
|
+
* @private
|
|
5970
|
+
*/
|
|
5971
|
+
_effectiveSelectionEnd(value, selectionStart, selectionEnd) {
|
|
5972
|
+
if (selectionEnd > selectionStart && value[selectionEnd - 1] === "\n") {
|
|
5973
|
+
return selectionEnd - 1;
|
|
5974
|
+
}
|
|
5975
|
+
return selectionEnd;
|
|
5976
|
+
}
|
|
5977
|
+
/**
|
|
5978
|
+
* @private
|
|
5979
|
+
*/
|
|
5980
|
+
_canEditTextarea() {
|
|
5981
|
+
return this.textarea && !this.textarea.disabled && !this.textarea.readOnly;
|
|
5982
|
+
}
|
|
5650
5983
|
/**
|
|
5651
5984
|
* Get clean HTML without any OverType-specific markup
|
|
5652
5985
|
* Useful for exporting to other formats or storage
|
|
@@ -5870,6 +6203,7 @@ var _OverType = class _OverType {
|
|
|
5870
6203
|
*/
|
|
5871
6204
|
showNormalEditMode() {
|
|
5872
6205
|
this.container.dataset.mode = "normal";
|
|
6206
|
+
this._syncPreviewInteractivity();
|
|
5873
6207
|
this.updatePreview();
|
|
5874
6208
|
this._updateAutoHeight();
|
|
5875
6209
|
requestAnimationFrame(() => {
|
|
@@ -5884,6 +6218,7 @@ var _OverType = class _OverType {
|
|
|
5884
6218
|
*/
|
|
5885
6219
|
showPlainTextarea() {
|
|
5886
6220
|
this.container.dataset.mode = "plain";
|
|
6221
|
+
this._syncPreviewInteractivity();
|
|
5887
6222
|
this._updateAutoHeight();
|
|
5888
6223
|
if (this.toolbar) {
|
|
5889
6224
|
const toggleBtn = this.container.querySelector('[data-action="toggle-plain"]');
|
|
@@ -5900,6 +6235,7 @@ var _OverType = class _OverType {
|
|
|
5900
6235
|
*/
|
|
5901
6236
|
showPreviewMode() {
|
|
5902
6237
|
this.container.dataset.mode = "preview";
|
|
6238
|
+
this._syncPreviewInteractivity();
|
|
5903
6239
|
this.updatePreview();
|
|
5904
6240
|
this._updateAutoHeight();
|
|
5905
6241
|
return this;
|
|
@@ -5918,6 +6254,10 @@ var _OverType = class _OverType {
|
|
|
5918
6254
|
if (this.shortcuts) {
|
|
5919
6255
|
this.shortcuts.destroy();
|
|
5920
6256
|
}
|
|
6257
|
+
if (this._safariReflowRaf) {
|
|
6258
|
+
cancelAnimationFrame(this._safariReflowRaf);
|
|
6259
|
+
this._safariReflowRaf = null;
|
|
6260
|
+
}
|
|
5921
6261
|
if (this.wrapper) {
|
|
5922
6262
|
const content = this.getValue();
|
|
5923
6263
|
this.wrapper.remove();
|
|
@@ -5949,11 +6289,16 @@ var _OverType = class _OverType {
|
|
|
5949
6289
|
return elements.map((el) => {
|
|
5950
6290
|
const options = { ...defaults };
|
|
5951
6291
|
for (const attr of el.attributes) {
|
|
5952
|
-
if (attr.name.startsWith("data-ot-"))
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
6292
|
+
if (!attr.name.startsWith("data-ot-"))
|
|
6293
|
+
continue;
|
|
6294
|
+
const kebab = attr.name.slice(8);
|
|
6295
|
+
if (kebab.startsWith("textarea-") && kebab !== "textarea-props") {
|
|
6296
|
+
const propKey = kebab.slice(9).replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
6297
|
+
options.textareaProps = { ...options.textareaProps || {}, [propKey]: _OverType._parseDataValue(attr.value) };
|
|
6298
|
+
continue;
|
|
5956
6299
|
}
|
|
6300
|
+
const key = kebab.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
6301
|
+
options[key] = _OverType._parseDataValue(attr.value);
|
|
5957
6302
|
}
|
|
5958
6303
|
return new _OverType(el, options)[0];
|
|
5959
6304
|
});
|
|
@@ -5998,6 +6343,14 @@ var _OverType = class _OverType {
|
|
|
5998
6343
|
return null;
|
|
5999
6344
|
if (value !== "" && !isNaN(Number(value)))
|
|
6000
6345
|
return Number(value);
|
|
6346
|
+
const trimmed = value.trim();
|
|
6347
|
+
if (trimmed[0] === "{" || trimmed[0] === "[") {
|
|
6348
|
+
try {
|
|
6349
|
+
return JSON.parse(trimmed);
|
|
6350
|
+
} catch (e) {
|
|
6351
|
+
return value;
|
|
6352
|
+
}
|
|
6353
|
+
}
|
|
6001
6354
|
return value;
|
|
6002
6355
|
}
|
|
6003
6356
|
/**
|
|
@@ -6176,8 +6529,13 @@ var _OverType = class _OverType {
|
|
|
6176
6529
|
* Initialize global event listeners
|
|
6177
6530
|
*/
|
|
6178
6531
|
static initGlobalListeners() {
|
|
6179
|
-
|
|
6532
|
+
const globalScope = typeof window !== "undefined" ? window : globalThis;
|
|
6533
|
+
const globalListenersKey = "__overtypeGlobalListenersInitialized";
|
|
6534
|
+
if (_OverType.globalListenersInitialized || globalScope[globalListenersKey]) {
|
|
6535
|
+
_OverType.globalListenersInitialized = true;
|
|
6180
6536
|
return;
|
|
6537
|
+
}
|
|
6538
|
+
globalScope[globalListenersKey] = true;
|
|
6181
6539
|
document.addEventListener("input", (e) => {
|
|
6182
6540
|
if (e.target && e.target.classList && e.target.classList.contains("overtype-input")) {
|
|
6183
6541
|
const wrapper = e.target.closest(".overtype-wrapper");
|