markdown-actions 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.js CHANGED
@@ -161,113 +161,77 @@ export function insertHeader(textarea, level = 1, toggle = false) {
161
161
  if (!textarea || textarea.disabled || textarea.readOnly) return
162
162
  if (level < 1 || level > 6) level = 1
163
163
 
164
- // Save original cursor position before any expansion
165
- const originalStart = textarea.selectionStart
166
- const originalEnd = textarea.selectionEnd
167
- const noInitialSelection = originalStart === originalEnd
168
-
169
164
  const headerKey = `header${level === 1 ? '1' : level}`
170
165
  const style = mergeWithDefaults(FORMATS[headerKey] || FORMATS.header1)
171
166
 
172
- // Select current line
173
- const value = textarea.value
174
- let lineStart = originalStart
175
- let lineEnd = originalStart
176
-
177
- // Find line boundaries
178
- while (lineStart > 0 && value[lineStart - 1] !== '\n') {
179
- lineStart--
180
- }
181
- while (lineEnd < value.length && value[lineEnd] !== '\n') {
182
- lineEnd++
183
- }
184
-
185
- textarea.selectionStart = lineStart
186
- textarea.selectionEnd = lineEnd
187
-
188
- const currentLine = value.slice(lineStart, lineEnd)
189
-
190
- // Check if we're removing or changing existing header
191
- const existingHeaderMatch = currentLine.match(/^(#{1,6})\s*/)
192
- const existingPrefixLength = existingHeaderMatch ? existingHeaderMatch[0].length : 0
193
- const existingLevel = existingHeaderMatch ? existingHeaderMatch[1].length : 0
194
-
195
- // Remove any existing header formatting
196
- const cleanedLine = currentLine.replace(/^#{1,6}\s*/, '')
197
-
198
- let newLine
199
- let isRemoving = false
200
-
201
- // If toggle mode and current line has the same header level, remove it
202
- if (toggle && existingLevel === level) {
203
- newLine = cleanedLine
204
- isRemoving = true
205
- } else {
206
- // Apply new header
207
- newLine = style.prefix + cleanedLine
208
- }
209
-
210
- let selectionStart, selectionEnd
167
+ // Save original positions before any operations
168
+ const originalStart = textarea.selectionStart
169
+ const originalEnd = textarea.selectionEnd
211
170
 
212
- if (noInitialSelection) {
213
- // No selection - just restore cursor position
214
- const cursorOffsetInLine = originalStart - lineStart
215
-
216
- if (isRemoving) {
217
- // We're removing the header
218
- if (cursorOffsetInLine < existingPrefixLength) {
219
- // Cursor was in the header prefix, move to start of line
220
- selectionStart = lineStart
171
+ // Use applyLineOperation for consistent behavior
172
+ const result = applyLineOperation(
173
+ textarea,
174
+ (ta) => {
175
+ const currentLine = ta.value.slice(ta.selectionStart, ta.selectionEnd)
176
+
177
+ // Check if we're removing or changing existing header
178
+ const existingHeaderMatch = currentLine.match(/^(#{1,6})\s*/)
179
+ const existingLevel = existingHeaderMatch ? existingHeaderMatch[1].length : 0
180
+
181
+ // Remove any existing header formatting
182
+ const cleanedLine = currentLine.replace(/^#{1,6}\s*/, '')
183
+
184
+ let newLine
185
+
186
+ // If toggle mode and current line has the same header level, remove it
187
+ if (toggle && existingLevel === level) {
188
+ newLine = cleanedLine
221
189
  } else {
222
- // Cursor was in the text, move back by prefix length
223
- selectionStart = originalStart - existingPrefixLength
190
+ // Apply new header
191
+ newLine = style.prefix + cleanedLine
224
192
  }
225
- } else if (existingPrefixLength > 0) {
226
- // We're replacing an existing header
227
- if (cursorOffsetInLine < existingPrefixLength) {
228
- // Cursor was in the header prefix, keep it at the same position
229
- selectionStart = lineStart + Math.min(cursorOffsetInLine, style.prefix.length)
230
- } else {
231
- // Cursor was in the text, adjust by the difference in prefix lengths
232
- const prefixDiff = style.prefix.length - existingPrefixLength
233
- selectionStart = originalStart + prefixDiff
193
+
194
+ return {
195
+ text: newLine,
196
+ selectionStart: ta.selectionStart,
197
+ selectionEnd: ta.selectionEnd
198
+ }
199
+ },
200
+ {
201
+ prefix: style.prefix,
202
+ // Custom handler for header-specific logic
203
+ adjustSelection: (isRemoving, selStart, selEnd, lineStart) => {
204
+ const currentLine = textarea.value.slice(lineStart, textarea.selectionEnd)
205
+ const existingHeaderMatch = currentLine.match(/^(#{1,6})\s*/)
206
+ const existingPrefixLength = existingHeaderMatch ? existingHeaderMatch[0].length : 0
207
+ const existingLevel = existingHeaderMatch ? existingHeaderMatch[1].length : 0
208
+
209
+ // Check if we're actually removing (toggle off)
210
+ const actuallyRemoving = toggle && existingLevel === level
211
+
212
+ if (actuallyRemoving) {
213
+ // Removing the header entirely
214
+ return {
215
+ start: Math.max(selStart - existingPrefixLength, lineStart),
216
+ end: Math.max(selEnd - existingPrefixLength, lineStart)
217
+ }
218
+ } else if (existingPrefixLength > 0) {
219
+ // Replacing existing header with new one
220
+ const prefixDiff = style.prefix.length - existingPrefixLength
221
+ return {
222
+ start: selStart + prefixDiff,
223
+ end: selEnd + prefixDiff
224
+ }
225
+ } else {
226
+ // Adding new header
227
+ return {
228
+ start: selStart + style.prefix.length,
229
+ end: selEnd + style.prefix.length
230
+ }
231
+ }
234
232
  }
235
- } else {
236
- // We're adding a new header
237
- // Move cursor by the length of the new prefix
238
- selectionStart = originalStart + style.prefix.length
239
- }
240
-
241
- // Ensure cursor doesn't go past end of line
242
- selectionStart = Math.min(selectionStart, lineStart + newLine.length)
243
- selectionEnd = selectionStart
244
- } else {
245
- // Had a selection - preserve it with adjustment
246
- if (isRemoving) {
247
- // When removing header, shift selection back
248
- selectionStart = Math.max(originalStart - existingPrefixLength, lineStart)
249
- selectionEnd = Math.max(originalEnd - existingPrefixLength, lineStart)
250
- } else if (existingPrefixLength > 0) {
251
- // We're replacing an existing header
252
- const prefixDiff = style.prefix.length - existingPrefixLength
253
- selectionStart = originalStart + prefixDiff
254
- selectionEnd = originalEnd + prefixDiff
255
- } else {
256
- // We're adding a new header
257
- selectionStart = originalStart + style.prefix.length
258
- selectionEnd = originalEnd + style.prefix.length
259
233
  }
260
-
261
- // Ensure selection doesn't go past end of line
262
- selectionStart = Math.min(selectionStart, lineStart + newLine.length)
263
- selectionEnd = Math.min(selectionEnd, lineStart + newLine.length)
264
- }
265
-
266
- const result = {
267
- text: newLine,
268
- selectionStart,
269
- selectionEnd
270
- }
234
+ )
271
235
 
272
236
  insertText(textarea, result)
273
237
  }