@blankdotpage/cake 0.1.6 → 0.1.7

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/dist/index.cjs CHANGED
@@ -3,7 +3,6 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const require$$0 = require("react");
4
4
  const lucideReact = require("lucide-react");
5
5
  const TurndownService = require("turndown");
6
- const state = require("@codemirror/state");
7
6
  var jsxRuntime = { exports: {} };
8
7
  var reactJsxRuntime_production_min = {};
9
8
  /**
@@ -1305,14 +1304,14 @@ function createRuntime(extensions) {
1305
1304
  runtime
1306
1305
  };
1307
1306
  }
1308
- function applyEdit(command, state2) {
1307
+ function applyEdit(command, state) {
1309
1308
  while (true) {
1310
1309
  let delegated = false;
1311
1310
  for (const extension of extensions) {
1312
1311
  if (!extension.onEdit) {
1313
1312
  continue;
1314
1313
  }
1315
- const result = extension.onEdit(command, state2);
1314
+ const result = extension.onEdit(command, state);
1316
1315
  if (!result) {
1317
1316
  continue;
1318
1317
  }
@@ -1327,12 +1326,12 @@ function createRuntime(extensions) {
1327
1326
  break;
1328
1327
  }
1329
1328
  }
1330
- const selection = normalizeSelection$1(state2.selection);
1329
+ const selection = normalizeSelection$1(state.selection);
1331
1330
  if (isStructuralEdit(command)) {
1332
- const structural = applyStructuralEdit(command, state2.doc, selection);
1331
+ const structural = applyStructuralEdit(command, state.doc, selection);
1333
1332
  if (!structural) {
1334
1333
  if (command.type === "delete-backward" || command.type === "delete-forward") {
1335
- const cursorLength = state2.map.cursorLength;
1334
+ const cursorLength = state.map.cursorLength;
1336
1335
  const cursorStart = Math.max(
1337
1336
  0,
1338
1337
  Math.min(cursorLength, Math.min(selection.start, selection.end))
@@ -1343,22 +1342,22 @@ function createRuntime(extensions) {
1343
1342
  );
1344
1343
  if (cursorStart === cursorEnd) {
1345
1344
  if (command.type === "delete-backward" && cursorStart === 0) {
1346
- return state2;
1345
+ return state;
1347
1346
  }
1348
1347
  if (command.type === "delete-forward" && cursorStart === cursorLength) {
1349
- return state2;
1348
+ return state;
1350
1349
  }
1351
1350
  }
1352
1351
  const range = cursorStart === cursorEnd ? command.type === "delete-backward" ? { start: cursorStart - 1, end: cursorStart } : { start: cursorStart, end: cursorStart + 1 } : { start: cursorStart, end: cursorEnd };
1353
1352
  const fullDocDelete = range.start === 0 && range.end === cursorLength;
1354
- const from = fullDocDelete ? 0 : state2.map.cursorToSource(range.start, "backward");
1355
- const to = fullDocDelete ? state2.source.length : state2.map.cursorToSource(range.end, "forward");
1356
- const fromClamped = Math.max(0, Math.min(from, state2.source.length));
1353
+ const from = fullDocDelete ? 0 : state.map.cursorToSource(range.start, "backward");
1354
+ const to = fullDocDelete ? state.source.length : state.map.cursorToSource(range.end, "forward");
1355
+ const fromClamped = Math.max(0, Math.min(from, state.source.length));
1357
1356
  const toClamped = Math.max(
1358
1357
  fromClamped,
1359
- Math.min(to, state2.source.length)
1358
+ Math.min(to, state.source.length)
1360
1359
  );
1361
- const nextSource = state2.source.slice(0, fromClamped) + state2.source.slice(toClamped);
1360
+ const nextSource = state.source.slice(0, fromClamped) + state.source.slice(toClamped);
1362
1361
  const next2 = createState(nextSource);
1363
1362
  const caretCursor2 = next2.map.sourceToCursor(fromClamped, "forward");
1364
1363
  return {
@@ -1371,7 +1370,7 @@ function createRuntime(extensions) {
1371
1370
  };
1372
1371
  }
1373
1372
  if (command.type === "insert" || command.type === "insert-line-break") {
1374
- const cursorLength = state2.map.cursorLength;
1373
+ const cursorLength = state.map.cursorLength;
1375
1374
  const cursorStart = Math.max(
1376
1375
  0,
1377
1376
  Math.min(cursorLength, Math.min(selection.start, selection.end))
@@ -1382,15 +1381,15 @@ function createRuntime(extensions) {
1382
1381
  );
1383
1382
  const range = { start: cursorStart, end: cursorEnd };
1384
1383
  const fullDocReplace = range.start === 0 && range.end === cursorLength;
1385
- const from = fullDocReplace ? 0 : state2.map.cursorToSource(range.start, "backward");
1386
- const to = fullDocReplace ? state2.source.length : state2.map.cursorToSource(range.end, "forward");
1387
- const fromClamped = Math.max(0, Math.min(from, state2.source.length));
1384
+ const from = fullDocReplace ? 0 : state.map.cursorToSource(range.start, "backward");
1385
+ const to = fullDocReplace ? state.source.length : state.map.cursorToSource(range.end, "forward");
1386
+ const fromClamped = Math.max(0, Math.min(from, state.source.length));
1388
1387
  const toClamped = Math.max(
1389
1388
  fromClamped,
1390
- Math.min(to, state2.source.length)
1389
+ Math.min(to, state.source.length)
1391
1390
  );
1392
1391
  const insertText = command.type === "insert" ? command.text : "\n";
1393
- const nextSource = state2.source.slice(0, fromClamped) + insertText + state2.source.slice(toClamped);
1392
+ const nextSource = state.source.slice(0, fromClamped) + insertText + state.source.slice(toClamped);
1394
1393
  const next2 = createState(nextSource);
1395
1394
  const caretSource2 = fromClamped + insertText.length;
1396
1395
  const caretCursor2 = next2.map.sourceToCursor(caretSource2, "forward");
@@ -1403,7 +1402,7 @@ function createRuntime(extensions) {
1403
1402
  }
1404
1403
  };
1405
1404
  }
1406
- return state2;
1405
+ return state;
1407
1406
  }
1408
1407
  const interim = createStateFromDoc(structural.doc);
1409
1408
  const interimAffinity = structural.nextAffinity ?? "forward";
@@ -1423,15 +1422,15 @@ function createRuntime(extensions) {
1423
1422
  };
1424
1423
  }
1425
1424
  if (command.type === "indent" || command.type === "outdent") {
1426
- return state2;
1425
+ return state;
1427
1426
  }
1428
1427
  if (command.type === "toggle-bullet-list" || command.type === "toggle-numbered-list") {
1429
- return state2;
1428
+ return state;
1430
1429
  }
1431
1430
  if (command.type === "toggle-inline") {
1432
- return applyInlineToggle(state2, command.marker);
1431
+ return applyInlineToggle(state, command.marker);
1433
1432
  }
1434
- return state2;
1433
+ return state;
1435
1434
  }
1436
1435
  function applyStructuralEdit(command, doc, selection) {
1437
1436
  var _a;
@@ -2210,16 +2209,16 @@ function createRuntime(extensions) {
2210
2209
  }
2211
2210
  return true;
2212
2211
  }
2213
- function applyInlineToggle(state2, marker) {
2214
- const selection = normalizeSelection$1(state2.selection);
2215
- const source = state2.source;
2216
- const map = state2.map;
2212
+ function applyInlineToggle(state, marker) {
2213
+ const selection = normalizeSelection$1(state.selection);
2214
+ const source = state.source;
2215
+ const map = state.map;
2217
2216
  if (selection.start === selection.end) {
2218
2217
  const caret = selection.start;
2219
2218
  const markerLen2 = marker.length;
2220
2219
  const markerKind2 = toggleMarkerToKind.get(marker) ?? null;
2221
2220
  if (markerKind2) {
2222
- const around = marksAroundCursor(state2.doc, caret);
2221
+ const around = marksAroundCursor(state.doc, caret);
2223
2222
  if (isMarksPrefix(around.right, around.left) && around.left.length > around.right.length) {
2224
2223
  const exiting = around.left.slice(around.right.length);
2225
2224
  if (exiting.some((mark) => mark.kind === markerKind2)) {
@@ -2249,7 +2248,7 @@ function createRuntime(extensions) {
2249
2248
  }
2250
2249
  }
2251
2250
  return {
2252
- ...state2,
2251
+ ...state,
2253
2252
  selection: {
2254
2253
  start: caret,
2255
2254
  end: caret,
@@ -2295,12 +2294,12 @@ function createRuntime(extensions) {
2295
2294
  const selectedText = source.slice(from, to);
2296
2295
  const markerLen = marker.length;
2297
2296
  const markerKind = toggleMarkerToKind.get(marker) ?? null;
2298
- const linesForSelection = flattenDocToLines(state2.doc);
2297
+ const linesForSelection = flattenDocToLines(state.doc);
2299
2298
  const commonMarks = markerKind ? commonMarksAcrossSelection(
2300
2299
  linesForSelection,
2301
2300
  cursorStart,
2302
2301
  cursorEnd,
2303
- state2.doc
2302
+ state.doc
2304
2303
  ) : [];
2305
2304
  const hasCommonMark = markerKind !== null && commonMarks.some((mark) => mark.kind === markerKind);
2306
2305
  const canUnwrap = markerKind ? hasCommonMark : true;
@@ -2375,7 +2374,7 @@ function createRuntime(extensions) {
2375
2374
  }
2376
2375
  }
2377
2376
  if (edits.length === 0) {
2378
- return state2;
2377
+ return state;
2379
2378
  }
2380
2379
  edits.sort((a, b) => b.from - a.from);
2381
2380
  let newSource2 = source;
@@ -2417,15 +2416,15 @@ function createRuntime(extensions) {
2417
2416
  }
2418
2417
  };
2419
2418
  }
2420
- function updateSelection(state2, selection, options) {
2419
+ function updateSelection(state, selection, options) {
2421
2420
  const normalized = normalizeSelection$1(selection);
2422
- const cursorLength = state2.map.cursorLength;
2421
+ const cursorLength = state.map.cursorLength;
2423
2422
  const start = Math.max(0, Math.min(cursorLength, normalized.start));
2424
2423
  const end = Math.max(0, Math.min(cursorLength, normalized.end));
2425
2424
  const kind = (options == null ? void 0 : options.kind) ?? "programmatic";
2426
2425
  let affinity = normalized.affinity ?? "forward";
2427
2426
  if (start === end) {
2428
- const around = marksAroundCursor(state2.doc, start);
2427
+ const around = marksAroundCursor(state.doc, start);
2429
2428
  if (kind === "keyboard") {
2430
2429
  affinity = preferredTypingAffinityAtGap(
2431
2430
  around.left,
@@ -2444,13 +2443,13 @@ function createRuntime(extensions) {
2444
2443
  }
2445
2444
  }
2446
2445
  return {
2447
- ...state2,
2446
+ ...state,
2448
2447
  selection: { start, end, affinity }
2449
2448
  };
2450
2449
  }
2451
- function serializeSelection(state2, selection) {
2450
+ function serializeSelection(state, selection) {
2452
2451
  const normalized = normalizeSelection$1(selection);
2453
- const lines = flattenDocToLines(state2.doc);
2452
+ const lines = flattenDocToLines(state.doc);
2454
2453
  const docCursorLength = cursorLengthForLines(lines);
2455
2454
  const cursorStart = Math.max(
2456
2455
  0,
@@ -2471,7 +2470,7 @@ function createRuntime(extensions) {
2471
2470
  if (!line) {
2472
2471
  continue;
2473
2472
  }
2474
- const block = getBlockAtPath(state2.doc.blocks, line.path);
2473
+ const block = getBlockAtPath(state.doc.blocks, line.path);
2475
2474
  if (!block || block.type !== "paragraph") {
2476
2475
  continue;
2477
2476
  }
@@ -2483,7 +2482,7 @@ function createRuntime(extensions) {
2483
2482
  const paragraph = { type: "paragraph", content };
2484
2483
  if (line.path.length > 1) {
2485
2484
  const wrapperPath = line.path.slice(0, -1);
2486
- const wrapper = getBlockAtPath(state2.doc.blocks, wrapperPath);
2485
+ const wrapper = getBlockAtPath(state.doc.blocks, wrapperPath);
2487
2486
  if (wrapper && wrapper.type === "block-wrapper") {
2488
2487
  blocks.push({
2489
2488
  type: "block-wrapper",
@@ -2526,9 +2525,9 @@ function createRuntime(extensions) {
2526
2525
  }
2527
2526
  return html;
2528
2527
  }
2529
- function serializeSelectionToHtml(state2, selection) {
2528
+ function serializeSelectionToHtml(state, selection) {
2530
2529
  const normalized = normalizeSelection$1(selection);
2531
- const lines = flattenDocToLines(state2.doc);
2530
+ const lines = flattenDocToLines(state.doc);
2532
2531
  const docCursorLength = cursorLengthForLines(lines);
2533
2532
  const cursorStart = Math.max(
2534
2533
  0,
@@ -2564,7 +2563,7 @@ function createRuntime(extensions) {
2564
2563
  if (!line) {
2565
2564
  continue;
2566
2565
  }
2567
- const block = getBlockAtPath(state2.doc.blocks, line.path);
2566
+ const block = getBlockAtPath(state.doc.blocks, line.path);
2568
2567
  if (!block || block.type !== "paragraph") {
2569
2568
  continue;
2570
2569
  }
@@ -2576,7 +2575,7 @@ function createRuntime(extensions) {
2576
2575
  let wrapperData;
2577
2576
  if (line.path.length > 1) {
2578
2577
  const wrapperPath = line.path.slice(0, -1);
2579
- const wrapper = getBlockAtPath(state2.doc.blocks, wrapperPath);
2578
+ const wrapper = getBlockAtPath(state.doc.blocks, wrapperPath);
2580
2579
  if (wrapper && wrapper.type === "block-wrapper") {
2581
2580
  wrapperKind = wrapper.kind;
2582
2581
  wrapperData = wrapper.data;
@@ -3375,10 +3374,16 @@ const boldExtension = defineExtension({
3375
3374
  name: "bold",
3376
3375
  toggleInline: { kind: BOLD_KIND$1, markers: ["**"] },
3377
3376
  keybindings: [
3378
- { key: "b", meta: true, command: { type: "toggle-inline", marker: "**" } },
3379
- { key: "b", ctrl: true, command: { type: "toggle-inline", marker: "**" } }
3377
+ { key: "b", meta: true, command: { type: "toggle-bold" } },
3378
+ { key: "b", ctrl: true, command: { type: "toggle-bold" } }
3380
3379
  ],
3381
3380
  inlineWrapperAffinity: [{ kind: BOLD_KIND$1, inclusive: true }],
3381
+ onEdit(command) {
3382
+ if (command.type === "toggle-bold") {
3383
+ return { type: "toggle-inline", marker: "**" };
3384
+ }
3385
+ return null;
3386
+ },
3382
3387
  parseInline(source, start, end, context) {
3383
3388
  if (source.slice(start, start + 3) === "***") {
3384
3389
  const close2 = source.indexOf("***", start + 3);
@@ -3559,14 +3564,14 @@ function CakeLinkPopover(params) {
3559
3564
  const anchorRef = require$$0.useRef(null);
3560
3565
  const popoverRef = require$$0.useRef(null);
3561
3566
  const inputRef = require$$0.useRef(null);
3562
- const [state2, setState] = require$$0.useState({ status: "closed" });
3563
- const isEditing = state2.status === "open" ? state2.isEditing : false;
3567
+ const [state, setState] = require$$0.useState({ status: "closed" });
3568
+ const isEditing = state.status === "open" ? state.isEditing : false;
3564
3569
  const close = require$$0.useCallback(() => {
3565
3570
  anchorRef.current = null;
3566
3571
  setState({ status: "closed" });
3567
3572
  }, []);
3568
3573
  const reposition = require$$0.useCallback(() => {
3569
- if (state2.status !== "open") {
3574
+ if (state.status !== "open") {
3570
3575
  return;
3571
3576
  }
3572
3577
  const anchor = anchorRef.current;
@@ -3583,7 +3588,7 @@ function CakeLinkPopover(params) {
3583
3588
  position: getPopoverPosition({ anchor, toOverlayRect })
3584
3589
  };
3585
3590
  });
3586
- }, [close, state2.status, toOverlayRect]);
3591
+ }, [close, state.status, toOverlayRect]);
3587
3592
  const openForLink = require$$0.useCallback(
3588
3593
  (link, options) => {
3589
3594
  anchorRef.current = link;
@@ -3599,18 +3604,18 @@ function CakeLinkPopover(params) {
3599
3604
  [toOverlayRect]
3600
3605
  );
3601
3606
  require$$0.useEffect(() => {
3602
- if (state2.status !== "open") {
3607
+ if (state.status !== "open") {
3603
3608
  return;
3604
3609
  }
3605
3610
  reposition();
3606
- }, [reposition, state2.status, isEditing]);
3611
+ }, [reposition, state.status, isEditing]);
3607
3612
  require$$0.useEffect(() => {
3608
3613
  var _a;
3609
- if (state2.status !== "open" || !isEditing) {
3614
+ if (state.status !== "open" || !isEditing) {
3610
3615
  return;
3611
3616
  }
3612
3617
  (_a = inputRef.current) == null ? void 0 : _a.focus();
3613
- }, [state2.status, isEditing]);
3618
+ }, [state.status, isEditing]);
3614
3619
  require$$0.useEffect(() => {
3615
3620
  function handleContentClick(event) {
3616
3621
  const link = getLinkFromEventTarget(event.target);
@@ -3653,7 +3658,7 @@ function CakeLinkPopover(params) {
3653
3658
  };
3654
3659
  }, [contentRoot, openForLink]);
3655
3660
  require$$0.useEffect(() => {
3656
- if (state2.status !== "open") {
3661
+ if (state.status !== "open") {
3657
3662
  return;
3658
3663
  }
3659
3664
  container.addEventListener("scroll", close, { passive: true });
@@ -3662,7 +3667,7 @@ function CakeLinkPopover(params) {
3662
3667
  container.removeEventListener("scroll", close);
3663
3668
  window.removeEventListener("resize", reposition);
3664
3669
  };
3665
- }, [close, container, reposition, state2.status]);
3670
+ }, [close, container, reposition, state.status]);
3666
3671
  const handleMouseDown = require$$0.useCallback(
3667
3672
  (event) => {
3668
3673
  event.stopPropagation();
@@ -3673,10 +3678,10 @@ function CakeLinkPopover(params) {
3673
3678
  },
3674
3679
  []
3675
3680
  );
3676
- if (state2.status !== "open") {
3681
+ if (state.status !== "open") {
3677
3682
  return null;
3678
3683
  }
3679
- const displayUrl = ensureHttpsProtocol(state2.url);
3684
+ const displayUrl = ensureHttpsProtocol(state.url);
3680
3685
  const handleEdit = () => {
3681
3686
  setState((current) => {
3682
3687
  if (current.status !== "open") {
@@ -3695,10 +3700,10 @@ function CakeLinkPopover(params) {
3695
3700
  };
3696
3701
  const handleSave = () => {
3697
3702
  var _a;
3698
- if (state2.status !== "open") {
3703
+ if (state.status !== "open") {
3699
3704
  return;
3700
3705
  }
3701
- const draftValue = ((_a = inputRef.current) == null ? void 0 : _a.value) ?? state2.draftUrl;
3706
+ const draftValue = ((_a = inputRef.current) == null ? void 0 : _a.value) ?? state.draftUrl;
3702
3707
  const trimmed = draftValue.trim();
3703
3708
  if (!trimmed) {
3704
3709
  close();
@@ -3712,7 +3717,7 @@ function CakeLinkPopover(params) {
3712
3717
  url: nextUrl,
3713
3718
  isEditing: false,
3714
3719
  draftUrl: nextUrl,
3715
- position: state2.position
3720
+ position: state.position
3716
3721
  });
3717
3722
  };
3718
3723
  const handleOpen = () => {
@@ -3744,13 +3749,13 @@ function CakeLinkPopover(params) {
3744
3749
  ref: popoverRef,
3745
3750
  style: {
3746
3751
  position: "absolute",
3747
- top: state2.position.top,
3748
- left: state2.position.left,
3752
+ top: state.position.top,
3753
+ left: state.position.left,
3749
3754
  pointerEvents: "auto"
3750
3755
  },
3751
3756
  onMouseDown: handleMouseDown,
3752
3757
  onClick: (event) => event.stopPropagation(),
3753
- children: state2.isEditing ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
3758
+ children: state.isEditing ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
3754
3759
  "form",
3755
3760
  {
3756
3761
  className: "cake-link-editor",
@@ -3764,7 +3769,7 @@ function CakeLinkPopover(params) {
3764
3769
  {
3765
3770
  className: "cake-link-input",
3766
3771
  type: "text",
3767
- value: state2.draftUrl,
3772
+ value: state.draftUrl,
3768
3773
  ref: inputRef,
3769
3774
  onChange: (event) => {
3770
3775
  setState((current) => {
@@ -4036,8 +4041,8 @@ const linkExtension = defineExtension({
4036
4041
  key: "u",
4037
4042
  meta: true,
4038
4043
  shift: true,
4039
- command: (state2) => {
4040
- if (state2.selection.start === state2.selection.end) {
4044
+ command: (state) => {
4045
+ if (state.selection.start === state.selection.end) {
4041
4046
  return null;
4042
4047
  }
4043
4048
  return { type: "wrap-link", openPopover: true };
@@ -4047,19 +4052,19 @@ const linkExtension = defineExtension({
4047
4052
  key: "u",
4048
4053
  ctrl: true,
4049
4054
  shift: true,
4050
- command: (state2) => {
4051
- if (state2.selection.start === state2.selection.end) {
4055
+ command: (state) => {
4056
+ if (state.selection.start === state.selection.end) {
4052
4057
  return null;
4053
4058
  }
4054
4059
  return { type: "wrap-link", openPopover: true };
4055
4060
  }
4056
4061
  }
4057
4062
  ],
4058
- onEdit(command, state2) {
4063
+ onEdit(command, state) {
4059
4064
  if (command.type === "unlink") {
4060
4065
  const cursorPos = command.start;
4061
- const sourcePos = state2.map.cursorToSource(cursorPos, "forward");
4062
- const source = state2.source;
4066
+ const sourcePos = state.map.cursorToSource(cursorPos, "forward");
4067
+ const source = state.source;
4063
4068
  let linkStart = sourcePos;
4064
4069
  while (linkStart > 0 && source[linkStart] !== "[") {
4065
4070
  linkStart--;
@@ -4077,7 +4082,7 @@ const linkExtension = defineExtension({
4077
4082
  }
4078
4083
  const label2 = source.slice(linkStart + 1, labelClose);
4079
4084
  const nextSource2 = source.slice(0, linkStart) + label2 + source.slice(urlClose + 1);
4080
- const newState = state2.runtime.createState(nextSource2);
4085
+ const newState = state.runtime.createState(nextSource2);
4081
4086
  const labelEndSource = linkStart + label2.length;
4082
4087
  const newCursor = newState.map.sourceToCursor(labelEndSource, "forward");
4083
4088
  return {
@@ -4092,21 +4097,21 @@ const linkExtension = defineExtension({
4092
4097
  if (command.type !== "wrap-link") {
4093
4098
  return null;
4094
4099
  }
4095
- const selection = state2.selection;
4100
+ const selection = state.selection;
4096
4101
  const cursorStart = Math.min(selection.start, selection.end);
4097
4102
  const cursorEnd = Math.max(selection.start, selection.end);
4098
4103
  if (cursorStart === cursorEnd) {
4099
4104
  return null;
4100
4105
  }
4101
- const from = state2.map.cursorToSource(cursorStart, "forward");
4102
- const to = state2.map.cursorToSource(cursorEnd, "backward");
4106
+ const from = state.map.cursorToSource(cursorStart, "forward");
4107
+ const to = state.map.cursorToSource(cursorEnd, "backward");
4103
4108
  if (from === to) {
4104
4109
  return null;
4105
4110
  }
4106
- const label = state2.source.slice(from, to);
4111
+ const label = state.source.slice(from, to);
4107
4112
  const url = command.url ?? "";
4108
4113
  const linkMarkdown = `[${label}](${url})`;
4109
- const nextSource = state2.source.slice(0, from) + linkMarkdown + state2.source.slice(to);
4114
+ const nextSource = state.source.slice(0, from) + linkMarkdown + state.source.slice(to);
4110
4115
  return {
4111
4116
  source: nextSource,
4112
4117
  selection: {
@@ -4116,16 +4121,16 @@ const linkExtension = defineExtension({
4116
4121
  }
4117
4122
  };
4118
4123
  },
4119
- onPasteText(text, state2) {
4124
+ onPasteText(text, state) {
4120
4125
  if (!isUrl(text)) {
4121
4126
  return null;
4122
4127
  }
4123
4128
  const url = ensureHttpsProtocol(text.trim());
4124
- const selection = state2.selection;
4129
+ const selection = state.selection;
4125
4130
  const start = Math.min(selection.start, selection.end);
4126
4131
  const end = Math.max(selection.start, selection.end);
4127
4132
  if (start !== end) {
4128
- const lines = getDocLines(state2.doc);
4133
+ const lines = getDocLines(state.doc);
4129
4134
  const visibleText = getVisibleText(lines);
4130
4135
  const visibleStart = cursorOffsetToVisibleOffset(lines, start);
4131
4136
  const visibleEnd = cursorOffsetToVisibleOffset(lines, end);
@@ -4297,8 +4302,61 @@ const pipeLinkExtension = defineExtension({
4297
4302
  });
4298
4303
  const BLOCKQUOTE_KIND = "blockquote";
4299
4304
  const PREFIX = "> ";
4305
+ const BLOCKQUOTE_PATTERN = /^> /;
4306
+ function findLineStartInSource$1(source, sourceOffset) {
4307
+ let lineStart = sourceOffset;
4308
+ while (lineStart > 0 && source[lineStart - 1] !== "\n") {
4309
+ lineStart--;
4310
+ }
4311
+ return lineStart;
4312
+ }
4313
+ function handleToggleBlockquote(state) {
4314
+ const { source, selection, map, runtime } = state;
4315
+ const cursorPos = Math.min(selection.start, selection.end);
4316
+ const sourcePos = map.cursorToSource(
4317
+ cursorPos,
4318
+ selection.affinity ?? "forward"
4319
+ );
4320
+ const lineStart = findLineStartInSource$1(source, sourcePos);
4321
+ let lineEnd = source.indexOf("\n", lineStart);
4322
+ if (lineEnd === -1) {
4323
+ lineEnd = source.length;
4324
+ }
4325
+ const lineContent = source.slice(lineStart, lineEnd);
4326
+ const blockquoteMatch = lineContent.match(BLOCKQUOTE_PATTERN);
4327
+ let newSource;
4328
+ let newCursorOffset;
4329
+ if (blockquoteMatch) {
4330
+ newSource = source.slice(0, lineStart) + lineContent.slice(PREFIX.length) + source.slice(lineEnd);
4331
+ const cursorLineOffset = sourcePos - lineStart;
4332
+ if (cursorLineOffset >= PREFIX.length) {
4333
+ newCursorOffset = sourcePos - PREFIX.length;
4334
+ } else {
4335
+ newCursorOffset = lineStart;
4336
+ }
4337
+ } else {
4338
+ newSource = source.slice(0, lineStart) + PREFIX + lineContent + source.slice(lineEnd);
4339
+ newCursorOffset = sourcePos + PREFIX.length;
4340
+ }
4341
+ const next = runtime.createState(newSource);
4342
+ const caretCursor = next.map.sourceToCursor(newCursorOffset, "forward");
4343
+ return {
4344
+ source: newSource,
4345
+ selection: {
4346
+ start: caretCursor.cursorOffset,
4347
+ end: caretCursor.cursorOffset,
4348
+ affinity: "forward"
4349
+ }
4350
+ };
4351
+ }
4300
4352
  const blockquoteExtension = defineExtension({
4301
4353
  name: "blockquote",
4354
+ onEdit(command, state) {
4355
+ if (command.type === "toggle-blockquote") {
4356
+ return handleToggleBlockquote(state);
4357
+ }
4358
+ return null;
4359
+ },
4302
4360
  parseBlock(source, start, context) {
4303
4361
  if (source.slice(start, start + PREFIX.length) !== PREFIX) {
4304
4362
  return null;
@@ -4361,6 +4419,7 @@ const blockquoteExtension = defineExtension({
4361
4419
  return null;
4362
4420
  }
4363
4421
  const element = document.createElement("blockquote");
4422
+ element.setAttribute("data-block-wrapper", BLOCKQUOTE_KIND);
4364
4423
  for (const node of context.renderBlocks(block.blocks)) {
4365
4424
  element.append(node);
4366
4425
  }
@@ -4372,10 +4431,16 @@ const italicExtension = defineExtension({
4372
4431
  name: "italic",
4373
4432
  toggleInline: { kind: ITALIC_KIND, markers: ["*", "_"] },
4374
4433
  keybindings: [
4375
- { key: "i", meta: true, command: { type: "toggle-inline", marker: "*" } },
4376
- { key: "i", ctrl: true, command: { type: "toggle-inline", marker: "*" } }
4434
+ { key: "i", meta: true, command: { type: "toggle-italic" } },
4435
+ { key: "i", ctrl: true, command: { type: "toggle-italic" } }
4377
4436
  ],
4378
4437
  inlineWrapperAffinity: [{ kind: ITALIC_KIND, inclusive: true }],
4438
+ onEdit(command) {
4439
+ if (command.type === "toggle-italic") {
4440
+ return { type: "toggle-inline", marker: "*" };
4441
+ }
4442
+ return null;
4443
+ },
4379
4444
  parseInline(source, start, end, context) {
4380
4445
  const char = source[start];
4381
4446
  if (char !== "_" && char !== "*") {
@@ -4448,8 +4513,8 @@ function findLineStartInSource(source, sourceOffset) {
4448
4513
  }
4449
4514
  return lineStart;
4450
4515
  }
4451
- function handleDeleteBackward$1(state2) {
4452
- const { source, selection, map } = state2;
4516
+ function handleDeleteBackward$1(state) {
4517
+ const { source, selection, map } = state;
4453
4518
  if (selection.start !== selection.end) {
4454
4519
  return null;
4455
4520
  }
@@ -4476,8 +4541,8 @@ function handleDeleteBackward$1(state2) {
4476
4541
  }
4477
4542
  };
4478
4543
  }
4479
- function handleMultilineInsertInHeading(state2, text) {
4480
- const { source, selection, map, runtime } = state2;
4544
+ function handleMultilineInsertInHeading(state, text) {
4545
+ const { source, selection, map, runtime } = state;
4481
4546
  const normalizedText = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
4482
4547
  if (!normalizedText.includes("\n")) {
4483
4548
  return null;
@@ -4518,8 +4583,8 @@ function handleMultilineInsertInHeading(state2, text) {
4518
4583
  }
4519
4584
  };
4520
4585
  }
4521
- function shouldExitHeadingOnLineBreak(state2) {
4522
- const { source, selection, map } = state2;
4586
+ function shouldExitHeadingOnLineBreak(state) {
4587
+ const { source, selection, map } = state;
4523
4588
  if (selection.start !== selection.end) {
4524
4589
  return false;
4525
4590
  }
@@ -4539,20 +4604,78 @@ function shouldExitHeadingOnLineBreak(state2) {
4539
4604
  const contentStart = lineStart + marker.length;
4540
4605
  return sourcePos >= contentStart && sourcePos <= lineEnd;
4541
4606
  }
4607
+ function handleToggleHeading(state, targetLevel) {
4608
+ const { source, selection, map, runtime } = state;
4609
+ const cursorPos = Math.min(selection.start, selection.end);
4610
+ const sourcePos = map.cursorToSource(
4611
+ cursorPos,
4612
+ selection.affinity ?? "forward"
4613
+ );
4614
+ const lineStart = findLineStartInSource(source, sourcePos);
4615
+ let lineEnd = source.indexOf("\n", lineStart);
4616
+ if (lineEnd === -1) {
4617
+ lineEnd = source.length;
4618
+ }
4619
+ const lineContent = source.slice(lineStart, lineEnd);
4620
+ const headingMatch = lineContent.match(HEADING_PATTERN);
4621
+ let newSource;
4622
+ let newCursorOffset;
4623
+ if (headingMatch) {
4624
+ const currentLevel = headingMatch[1].length;
4625
+ const existingMarker = headingMatch[0];
4626
+ if (currentLevel === targetLevel) {
4627
+ newSource = source.slice(0, lineStart) + lineContent.slice(existingMarker.length) + source.slice(lineEnd);
4628
+ const cursorLineOffset = sourcePos - lineStart;
4629
+ if (cursorLineOffset >= existingMarker.length) {
4630
+ newCursorOffset = sourcePos - existingMarker.length;
4631
+ } else {
4632
+ newCursorOffset = lineStart;
4633
+ }
4634
+ } else {
4635
+ const newMarker = "#".repeat(targetLevel) + " ";
4636
+ newSource = source.slice(0, lineStart) + newMarker + lineContent.slice(existingMarker.length) + source.slice(lineEnd);
4637
+ const markerDiff = newMarker.length - existingMarker.length;
4638
+ const cursorLineOffset = sourcePos - lineStart;
4639
+ if (cursorLineOffset >= existingMarker.length) {
4640
+ newCursorOffset = sourcePos + markerDiff;
4641
+ } else {
4642
+ newCursorOffset = lineStart + newMarker.length;
4643
+ }
4644
+ }
4645
+ } else {
4646
+ const newMarker = "#".repeat(targetLevel) + " ";
4647
+ newSource = source.slice(0, lineStart) + newMarker + lineContent + source.slice(lineEnd);
4648
+ newCursorOffset = sourcePos + newMarker.length;
4649
+ }
4650
+ const next = runtime.createState(newSource);
4651
+ const caretCursor = next.map.sourceToCursor(newCursorOffset, "forward");
4652
+ return {
4653
+ source: newSource,
4654
+ selection: {
4655
+ start: caretCursor.cursorOffset,
4656
+ end: caretCursor.cursorOffset,
4657
+ affinity: "forward"
4658
+ }
4659
+ };
4660
+ }
4542
4661
  const headingExtension = defineExtension({
4543
4662
  name: "heading",
4544
- onEdit(command, state2) {
4663
+ onEdit(command, state) {
4664
+ if (command.type === "toggle-heading") {
4665
+ const level = command.level ?? 1;
4666
+ return handleToggleHeading(state, level);
4667
+ }
4545
4668
  if (command.type === "delete-backward") {
4546
- return handleDeleteBackward$1(state2);
4669
+ return handleDeleteBackward$1(state);
4547
4670
  }
4548
4671
  if (command.type === "insert-line-break") {
4549
- if (shouldExitHeadingOnLineBreak(state2)) {
4672
+ if (shouldExitHeadingOnLineBreak(state)) {
4550
4673
  return { type: "exit-block-wrapper" };
4551
4674
  }
4552
4675
  return null;
4553
4676
  }
4554
4677
  if (command.type === "insert") {
4555
- const multiline = handleMultilineInsertInHeading(state2, command.text);
4678
+ const multiline = handleMultilineInsertInHeading(state, command.text);
4556
4679
  if (multiline) {
4557
4680
  return multiline;
4558
4681
  }
@@ -4560,7 +4683,7 @@ const headingExtension = defineExtension({
4560
4683
  if (command.type !== "insert" || command.text !== " ") {
4561
4684
  return null;
4562
4685
  }
4563
- const { source, selection, map } = state2;
4686
+ const { source, selection, map } = state;
4564
4687
  if (selection.start !== selection.end) {
4565
4688
  return null;
4566
4689
  }
@@ -4795,13 +4918,13 @@ const imageExtension = defineExtension({
4795
4918
  return element;
4796
4919
  }
4797
4920
  });
4798
- const LIST_LINE_REGEX$2 = /^(\s*)([-*+]|\d+\.)( )(.*)$/;
4921
+ const LIST_LINE_REGEX$1 = /^(\s*)([-*+]|\d+\.)( )(.*)$/;
4799
4922
  const INDENT_SIZE = 2;
4800
4923
  function parseMarkerType(marker) {
4801
4924
  return /^\d+\.$/.test(marker) ? "numbered" : "bullet";
4802
4925
  }
4803
4926
  function parseLine(line) {
4804
- const match = line.match(LIST_LINE_REGEX$2);
4927
+ const match = line.match(LIST_LINE_REGEX$1);
4805
4928
  if (!match) {
4806
4929
  return { type: "plain", content: line };
4807
4930
  }
@@ -4881,14 +5004,14 @@ function getLineInfo(source, offset) {
4881
5004
  };
4882
5005
  }
4883
5006
  function getListPrefixLength(line) {
4884
- const match = line.match(LIST_LINE_REGEX$2);
5007
+ const match = line.match(LIST_LINE_REGEX$1);
4885
5008
  if (!match) {
4886
5009
  return null;
4887
5010
  }
4888
5011
  return match[1].length + match[2].length + match[3].length;
4889
5012
  }
4890
5013
  function isListLine(line) {
4891
- return LIST_LINE_REGEX$2.test(line);
5014
+ return LIST_LINE_REGEX$1.test(line);
4892
5015
  }
4893
5016
  function parseListItem(line) {
4894
5017
  const parsed = parseLine(line);
@@ -4908,9 +5031,9 @@ function countNumberedItemsBefore(source, beforeLineIndex) {
4908
5031
  }
4909
5032
  return count;
4910
5033
  }
4911
- const LIST_LINE_REGEX$1 = /^(\s*)([-*+]|\d+\.)( )(.*)$/;
5034
+ const LIST_LINE_REGEX = /^(\s*)([-*+]|\d+\.)( )(.*)$/;
4912
5035
  function matchListLine(line) {
4913
- const match = line.match(LIST_LINE_REGEX$1);
5036
+ const match = line.match(LIST_LINE_REGEX);
4914
5037
  if (!match) {
4915
5038
  return null;
4916
5039
  }
@@ -4989,8 +5112,8 @@ function getSelectionLineRange(source, selection) {
4989
5112
  );
4990
5113
  return { startLine: startInfo.lineIndex, endLine: endInfo.lineIndex };
4991
5114
  }
4992
- function handleInsertLineBreak(state2) {
4993
- const { source, selection, map, runtime } = state2;
5115
+ function handleInsertLineBreak(state) {
5116
+ const { source, selection, map, runtime } = state;
4994
5117
  let workingSource = source;
4995
5118
  let cursorPos = selection.start;
4996
5119
  let cursorSourcePos = map.cursorToSource(cursorPos, "forward");
@@ -5110,8 +5233,8 @@ function handleInsertLineBreak(state2) {
5110
5233
  }
5111
5234
  };
5112
5235
  }
5113
- function handleDeleteBackward(state2) {
5114
- const { source, selection, map, runtime } = state2;
5236
+ function handleDeleteBackward(state) {
5237
+ const { source, selection, map, runtime } = state;
5115
5238
  const resultAtSource = (nextSource, sourceOffset, bias = "forward") => {
5116
5239
  const next = runtime.createState(nextSource);
5117
5240
  const cursor = next.map.sourceToCursor(sourceOffset, bias);
@@ -5165,9 +5288,14 @@ function handleDeleteBackward(state2) {
5165
5288
  if (cursorPos === 0) {
5166
5289
  return null;
5167
5290
  }
5168
- const cursorSourcePos = map.cursorToSource(cursorPos, "backward");
5169
- const lineInfo = getLineInfo(source, cursorSourcePos);
5170
- const prefixLength = getListPrefixLength(lineInfo.line);
5291
+ const cursorSourcePosBackward = map.cursorToSource(cursorPos, "backward");
5292
+ const cursorSourcePosForward = map.cursorToSource(cursorPos, "forward");
5293
+ const lineInfoBackward = getLineInfo(source, cursorSourcePosBackward);
5294
+ const lineInfoForward = getLineInfo(source, cursorSourcePosForward);
5295
+ const forwardPrefixLength = getListPrefixLength(lineInfoForward.line);
5296
+ const backwardPrefixLength = getListPrefixLength(lineInfoBackward.line);
5297
+ const lineInfo = forwardPrefixLength !== null && lineInfoForward.offsetInLine === forwardPrefixLength ? lineInfoForward : lineInfoBackward;
5298
+ const prefixLength = lineInfo === lineInfoForward ? forwardPrefixLength : backwardPrefixLength;
5171
5299
  if (prefixLength === null) {
5172
5300
  if (lineInfo.offsetInLine === 0 && lineInfo.lineIndex > 0) {
5173
5301
  const lines = source.split("\n");
@@ -5261,8 +5389,8 @@ function handleDeleteBackward(state2) {
5261
5389
  }
5262
5390
  return null;
5263
5391
  }
5264
- function handleDeleteForward(state2) {
5265
- const { source, selection, map, runtime } = state2;
5392
+ function handleDeleteForward(state) {
5393
+ const { source, selection, map, runtime } = state;
5266
5394
  if (selection.start !== selection.end) {
5267
5395
  return null;
5268
5396
  }
@@ -5304,8 +5432,8 @@ function handleDeleteForward(state2) {
5304
5432
  }
5305
5433
  return null;
5306
5434
  }
5307
- function handleIndent(state2) {
5308
- const { source, selection } = state2;
5435
+ function handleIndent(state) {
5436
+ const { source, selection } = state;
5309
5437
  const { startLine, endLine } = getSelectionLineRange(source, selection);
5310
5438
  const lines = getSourceLines(source);
5311
5439
  let hasListLine = false;
@@ -5339,8 +5467,8 @@ function handleIndent(state2) {
5339
5467
  selection: { start: newStart, end: newEnd, affinity: "forward" }
5340
5468
  };
5341
5469
  }
5342
- function handleOutdent(state2) {
5343
- const { source, selection } = state2;
5470
+ function handleOutdent(state) {
5471
+ const { source, selection } = state;
5344
5472
  const { startLine, endLine } = getSelectionLineRange(source, selection);
5345
5473
  const lines = getSourceLines(source);
5346
5474
  let hasListLine = false;
@@ -5413,8 +5541,8 @@ function handleOutdent(state2) {
5413
5541
  selection: { start: newStart, end: newEnd, affinity: "forward" }
5414
5542
  };
5415
5543
  }
5416
- function handleToggleList(state2, isBullet) {
5417
- const { source, selection } = state2;
5544
+ function handleToggleList(state, isBullet) {
5545
+ const { source, selection } = state;
5418
5546
  const { startLine, endLine } = getSelectionLineRange(source, selection);
5419
5547
  const lines = getSourceLines(source);
5420
5548
  const bulletPattern = /^(\s*)([-*+])( )/;
@@ -5502,8 +5630,8 @@ function handleToggleList(state2, isBullet) {
5502
5630
  }
5503
5631
  };
5504
5632
  }
5505
- function handleInsertListMarkerWithSelection(state2, marker) {
5506
- const { source, selection } = state2;
5633
+ function handleInsertListMarkerWithSelection(state, marker) {
5634
+ const { source, selection } = state;
5507
5635
  if (selection.start === selection.end) {
5508
5636
  return null;
5509
5637
  }
@@ -5557,14 +5685,14 @@ function handleInsertListMarkerWithSelection(state2, marker) {
5557
5685
  selection: { start: cursorPos, end: cursorPos, affinity: "forward" }
5558
5686
  };
5559
5687
  }
5560
- function handleMarkerSwitch(state2, insertedChar) {
5561
- const { source, selection } = state2;
5688
+ function handleMarkerSwitch(state, insertedChar) {
5689
+ const { source, selection } = state;
5562
5690
  if (selection.start !== selection.end) {
5563
5691
  const { startLine, endLine } = getSelectionLineRange(source, selection);
5564
5692
  if (startLine !== endLine && (insertedChar === "-" || insertedChar === "*" || insertedChar === "+")) {
5565
5693
  return { type: "toggle-bullet-list" };
5566
5694
  }
5567
- return handleInsertListMarkerWithSelection(state2, insertedChar);
5695
+ return handleInsertListMarkerWithSelection(state, insertedChar);
5568
5696
  }
5569
5697
  if (insertedChar !== "-" && insertedChar !== "*" && insertedChar !== "+") {
5570
5698
  return null;
@@ -5641,30 +5769,30 @@ const listExtension = defineExtension({
5641
5769
  command: { type: "toggle-numbered-list" }
5642
5770
  }
5643
5771
  ],
5644
- onEdit(command, state2) {
5772
+ onEdit(command, state) {
5645
5773
  if (command.type === "insert-line-break") {
5646
- return handleInsertLineBreak(state2);
5774
+ return handleInsertLineBreak(state);
5647
5775
  }
5648
5776
  if (command.type === "delete-backward") {
5649
- return handleDeleteBackward(state2);
5777
+ return handleDeleteBackward(state);
5650
5778
  }
5651
5779
  if (command.type === "delete-forward") {
5652
- return handleDeleteForward(state2);
5780
+ return handleDeleteForward(state);
5653
5781
  }
5654
5782
  if (command.type === "indent") {
5655
- return handleIndent(state2);
5783
+ return handleIndent(state);
5656
5784
  }
5657
5785
  if (command.type === "outdent") {
5658
- return handleOutdent(state2);
5786
+ return handleOutdent(state);
5659
5787
  }
5660
5788
  if (command.type === "toggle-bullet-list") {
5661
- return handleToggleList(state2, true);
5789
+ return handleToggleList(state, true);
5662
5790
  }
5663
5791
  if (command.type === "toggle-numbered-list") {
5664
- return handleToggleList(state2, false);
5792
+ return handleToggleList(state, false);
5665
5793
  }
5666
5794
  if (command.type === "insert" && command.text.length === 1) {
5667
- return handleMarkerSwitch(state2, command.text);
5795
+ return handleMarkerSwitch(state, command.text);
5668
5796
  }
5669
5797
  return null;
5670
5798
  },
@@ -5710,7 +5838,7 @@ const THUMB_MIN_HEIGHT = 30;
5710
5838
  const SCROLL_HIDE_DELAY = 500;
5711
5839
  const TRACK_PADDING = 8;
5712
5840
  function ScrollbarOverlay({ container }) {
5713
- const [state2, setState] = require$$0.useState({
5841
+ const [state, setState] = require$$0.useState({
5714
5842
  scrollTop: 0,
5715
5843
  scrollHeight: 0,
5716
5844
  clientHeight: 0
@@ -5723,7 +5851,7 @@ function ScrollbarOverlay({ container }) {
5723
5851
  null
5724
5852
  );
5725
5853
  const scrollTimeoutRef = require$$0.useRef(null);
5726
- const { scrollTop, scrollHeight, clientHeight } = state2;
5854
+ const { scrollTop, scrollHeight, clientHeight } = state;
5727
5855
  const hasOverflow = scrollHeight > clientHeight;
5728
5856
  const trackHeight = clientHeight - TRACK_PADDING * 2;
5729
5857
  const rawThumbHeight = hasOverflow ? clientHeight / scrollHeight * trackHeight : 0;
@@ -5957,16 +6085,22 @@ const strikethroughExtension = defineExtension({
5957
6085
  key: "x",
5958
6086
  meta: true,
5959
6087
  shift: true,
5960
- command: { type: "toggle-inline", marker: "~~" }
6088
+ command: { type: "toggle-strikethrough" }
5961
6089
  },
5962
6090
  {
5963
6091
  key: "x",
5964
6092
  ctrl: true,
5965
6093
  shift: true,
5966
- command: { type: "toggle-inline", marker: "~~" }
6094
+ command: { type: "toggle-strikethrough" }
5967
6095
  }
5968
6096
  ],
5969
6097
  inlineWrapperAffinity: [{ kind: STRIKE_KIND, inclusive: true }],
6098
+ onEdit(command) {
6099
+ if (command.type === "toggle-strikethrough") {
6100
+ return { type: "toggle-inline", marker: "~~" };
6101
+ }
6102
+ return null;
6103
+ },
5970
6104
  parseInline(source, start, end, context) {
5971
6105
  if (source.slice(start, start + 2) !== "~~") {
5972
6106
  return null;
@@ -6065,27 +6199,23 @@ function mergeDomRects(rects) {
6065
6199
  });
6066
6200
  return new DOMRect(left, top, right - left, bottom - top);
6067
6201
  }
6068
- function rectsOverlapVertically(a, b) {
6069
- const aBottom = a.top + a.height;
6070
- const bBottom = b.top + b.height;
6071
- return a.top < bBottom && b.top < aBottom;
6072
- }
6073
6202
  function groupDomRectsByRow(rects) {
6074
6203
  if (rects.length === 0) {
6075
6204
  return [];
6076
6205
  }
6206
+ const ROW_TOP_EPS_PX = 1;
6077
6207
  const sorted = [...rects].sort(
6078
6208
  (a, b) => a.top === b.top ? a.left - b.left : a.top - b.top
6079
6209
  );
6080
6210
  const grouped = [];
6081
- sorted.forEach((rect) => {
6211
+ for (const rect of sorted) {
6082
6212
  const last = grouped[grouped.length - 1];
6083
- if (last && rectsOverlapVertically(last, rect)) {
6213
+ if (last && Math.abs(rect.top - last.top) <= ROW_TOP_EPS_PX) {
6084
6214
  grouped[grouped.length - 1] = mergeDomRects([last, rect]) ?? last;
6085
- return;
6215
+ continue;
6086
6216
  }
6087
6217
  grouped.push(rect);
6088
- });
6218
+ }
6089
6219
  return grouped;
6090
6220
  }
6091
6221
  function cursorOffsetToCodeUnit(cursorToCodeUnit, offset) {
@@ -6149,11 +6279,26 @@ function measureCharacterRect(params) {
6149
6279
  );
6150
6280
  const startPosition = params.resolveDomPosition(startCodeUnit);
6151
6281
  const endPosition = params.resolveDomPosition(endCodeUnit);
6152
- params.range.setStart(startPosition.node, startPosition.offset);
6153
- params.range.setEnd(endPosition.node, endPosition.offset);
6282
+ if (startPosition.node !== endPosition.node && startPosition.node instanceof Text && endPosition.node instanceof Text && startPosition.offset === startPosition.node.length && endPosition.offset > 0) {
6283
+ params.range.setStart(endPosition.node, 0);
6284
+ params.range.setEnd(endPosition.node, endPosition.offset);
6285
+ } else {
6286
+ params.range.setStart(startPosition.node, startPosition.offset);
6287
+ params.range.setEnd(endPosition.node, endPosition.offset);
6288
+ }
6154
6289
  const rects = params.range.getClientRects();
6155
6290
  if (rects.length > 0) {
6156
- return rects[0] ?? null;
6291
+ const list = Array.from(rects);
6292
+ let best = list[0] ?? null;
6293
+ let bestArea = best ? best.width * best.height : 0;
6294
+ for (const rect2 of list) {
6295
+ const area = rect2.width * rect2.height;
6296
+ if (area > bestArea) {
6297
+ best = rect2;
6298
+ bestArea = area;
6299
+ }
6300
+ }
6301
+ return bestArea > 0 ? best : list[0] ?? null;
6157
6302
  }
6158
6303
  const rect = params.range.getBoundingClientRect();
6159
6304
  if (rect.width === 0 && rect.height === 0) {
@@ -6185,7 +6330,9 @@ function measureLineRows(params) {
6185
6330
  const fullLineEnd = resolvePosition(params.codeUnitLength);
6186
6331
  scratchRange.setStart(fullLineStart.node, fullLineStart.offset);
6187
6332
  scratchRange.setEnd(fullLineEnd.node, fullLineEnd.offset);
6188
- const fullLineRects = groupDomRectsByRow(Array.from(scratchRange.getClientRects()));
6333
+ const fullLineRects = groupDomRectsByRow(
6334
+ Array.from(scratchRange.getClientRects())
6335
+ );
6189
6336
  if (fullLineRects.length === 0) {
6190
6337
  return [
6191
6338
  {
@@ -6195,7 +6342,15 @@ function measureLineRows(params) {
6195
6342
  }
6196
6343
  ];
6197
6344
  }
6345
+ const rowRects = fullLineRects.map((rect, index) => {
6346
+ var _a2;
6347
+ const nextTop = ((_a2 = fullLineRects[index + 1]) == null ? void 0 : _a2.top) ?? params.lineRect.bottom;
6348
+ const bottom = Math.max(rect.top, nextTop);
6349
+ const height = Math.max(0, bottom - rect.top);
6350
+ return new DOMRect(rect.left, rect.top, rect.width, height);
6351
+ });
6198
6352
  function offsetToTop(offset) {
6353
+ var _a2;
6199
6354
  if (topCache.has(offset)) {
6200
6355
  return topCache.get(offset) ?? null;
6201
6356
  }
@@ -6207,7 +6362,22 @@ function measureLineRows(params) {
6207
6362
  resolveDomPosition: resolvePosition,
6208
6363
  range: scratchRange
6209
6364
  });
6210
- const top = rect ? rect.top : null;
6365
+ let top = rect ? rect.top : null;
6366
+ if (top === null) {
6367
+ const codeUnitOffset = cursorOffsetToCodeUnit(params.cursorToCodeUnit, offset);
6368
+ const position = resolvePosition(codeUnitOffset);
6369
+ scratchRange.setStart(position.node, position.offset);
6370
+ scratchRange.setEnd(position.node, position.offset);
6371
+ const rects = scratchRange.getClientRects();
6372
+ if (rects.length > 0) {
6373
+ top = ((_a2 = rects[0]) == null ? void 0 : _a2.top) ?? null;
6374
+ } else {
6375
+ const caretRect = scratchRange.getBoundingClientRect();
6376
+ if (!(caretRect.width === 0 && caretRect.height === 0)) {
6377
+ top = caretRect.top;
6378
+ }
6379
+ }
6380
+ }
6211
6381
  topCache.set(offset, top);
6212
6382
  return top;
6213
6383
  }
@@ -6275,7 +6445,7 @@ function measureLineRows(params) {
6275
6445
  while (currentRowStart < params.lineLength) {
6276
6446
  const nextRowStart = findNextRowStartOffset(searchFrom, currentRowTop);
6277
6447
  const currentRowEnd = nextRowStart ?? params.lineLength;
6278
- const domRect = fullLineRects[rowIndex] ?? params.lineRect;
6448
+ const domRect = rowRects[rowIndex] ?? params.lineRect;
6279
6449
  rows.push({
6280
6450
  startOffset: currentRowStart,
6281
6451
  endOffset: currentRowEnd,
@@ -6462,6 +6632,249 @@ function createOffsetToXMeasurer(params) {
6462
6632
  function cursorOffsetToDomOffset(cursorToCodeUnit, offset) {
6463
6633
  return cursorOffsetToCodeUnit(cursorToCodeUnit, offset);
6464
6634
  }
6635
+ function hitTestFromLayout(params) {
6636
+ const { clientX, clientY, root, container, lines } = params;
6637
+ const layout = measureLayoutModelFromDom({ lines, root, container });
6638
+ if (!layout || layout.lines.length === 0) {
6639
+ return null;
6640
+ }
6641
+ const containerRect = container.getBoundingClientRect();
6642
+ const scroll = { top: container.scrollTop, left: container.scrollLeft };
6643
+ const relativeX = clientX - containerRect.left + scroll.left;
6644
+ const relativeY = clientY - containerRect.top + scroll.top;
6645
+ const allRows = [];
6646
+ for (const lineLayout of layout.lines) {
6647
+ for (const row2 of lineLayout.rows) {
6648
+ const centerY = row2.rect.top + row2.rect.height / 2;
6649
+ allRows.push({
6650
+ lineIndex: lineLayout.lineIndex,
6651
+ lineStartOffset: lineLayout.lineStartOffset,
6652
+ row: row2,
6653
+ centerY
6654
+ });
6655
+ }
6656
+ }
6657
+ if (allRows.length === 0) {
6658
+ return null;
6659
+ }
6660
+ let targetRowInfo = allRows[0];
6661
+ let smallestCenterDistance = Math.abs(relativeY - targetRowInfo.centerY);
6662
+ for (let i = 1; i < allRows.length; i++) {
6663
+ const rowInfo = allRows[i];
6664
+ const distance = Math.abs(relativeY - rowInfo.centerY);
6665
+ if (distance < smallestCenterDistance) {
6666
+ smallestCenterDistance = distance;
6667
+ targetRowInfo = rowInfo;
6668
+ }
6669
+ }
6670
+ const { lineIndex, lineStartOffset, row } = targetRowInfo;
6671
+ const lineInfo = lines[lineIndex];
6672
+ if (!lineInfo) {
6673
+ return null;
6674
+ }
6675
+ const lineElement = getLineElement(root, lineIndex);
6676
+ if (!lineElement) {
6677
+ return null;
6678
+ }
6679
+ const resolvePosition = createDomPositionResolver(lineElement);
6680
+ const scratchRange = document.createRange();
6681
+ const rowTop = row.rect.top;
6682
+ const approximateX = (cursorOffsetInLine) => {
6683
+ const clamped = Math.max(
6684
+ row.startOffset,
6685
+ Math.min(cursorOffsetInLine, row.endOffset)
6686
+ );
6687
+ const rowLength = row.endOffset - row.startOffset;
6688
+ if (rowLength <= 0) {
6689
+ return row.rect.left;
6690
+ }
6691
+ const fraction = (clamped - row.startOffset) / rowLength;
6692
+ return row.rect.left + row.rect.width * fraction;
6693
+ };
6694
+ const measureCaretXOnRow = (cursorOffsetInLine) => {
6695
+ const maxRowTopDelta = Math.max(2, row.rect.height / 2);
6696
+ const measureCharEdgeX = (from, to, edge) => {
6697
+ const fromCodeUnit = cursorOffsetToCodeUnit(lineInfo.cursorToCodeUnit, from);
6698
+ const toCodeUnit = cursorOffsetToCodeUnit(lineInfo.cursorToCodeUnit, to);
6699
+ const fromPos = resolvePosition(fromCodeUnit);
6700
+ const toPos = resolvePosition(toCodeUnit);
6701
+ if (fromPos.node !== toPos.node && fromPos.node instanceof Text && toPos.node instanceof Text && fromPos.offset === fromPos.node.length && toPos.offset > 0) {
6702
+ scratchRange.setStart(toPos.node, 0);
6703
+ scratchRange.setEnd(toPos.node, toPos.offset);
6704
+ } else {
6705
+ scratchRange.setStart(fromPos.node, fromPos.offset);
6706
+ scratchRange.setEnd(toPos.node, toPos.offset);
6707
+ }
6708
+ const rects2 = scratchRange.getClientRects();
6709
+ const list = rects2.length > 0 ? Array.from(rects2) : (() => {
6710
+ const rect = scratchRange.getBoundingClientRect();
6711
+ return rect.width === 0 && rect.height === 0 ? [] : [rect];
6712
+ })();
6713
+ if (list.length === 0) {
6714
+ return null;
6715
+ }
6716
+ const DIST_EPS = 0.01;
6717
+ let bestTopDistance = Number.POSITIVE_INFINITY;
6718
+ const candidates2 = [];
6719
+ for (const rect of list) {
6720
+ const top = rect.top - containerRect.top + scroll.top;
6721
+ const distance = Math.abs(top - rowTop);
6722
+ if (distance + DIST_EPS < bestTopDistance) {
6723
+ bestTopDistance = distance;
6724
+ candidates2.length = 0;
6725
+ candidates2.push(rect);
6726
+ } else if (Math.abs(distance - bestTopDistance) <= DIST_EPS) {
6727
+ candidates2.push(rect);
6728
+ }
6729
+ }
6730
+ if (candidates2.length === 0 || bestTopDistance > maxRowTopDelta) {
6731
+ return null;
6732
+ }
6733
+ if (edge === "left") {
6734
+ let left = candidates2[0].left;
6735
+ for (const rect of candidates2) {
6736
+ left = Math.min(left, rect.left);
6737
+ }
6738
+ return left - containerRect.left + scroll.left;
6739
+ }
6740
+ let right = candidates2[0].right;
6741
+ for (const rect of candidates2) {
6742
+ right = Math.max(right, rect.right);
6743
+ }
6744
+ return right - containerRect.left + scroll.left;
6745
+ };
6746
+ const prevChar = cursorOffsetInLine > 0 ? lineInfo.text[cursorOffsetInLine - 1] ?? "" : "";
6747
+ const preferNextForPrevWhitespace = cursorOffsetInLine > row.startOffset && cursorOffsetInLine < row.endOffset && /\s/.test(prevChar);
6748
+ if (preferNextForPrevWhitespace) {
6749
+ const xNext = measureCharEdgeX(
6750
+ cursorOffsetInLine,
6751
+ cursorOffsetInLine + 1,
6752
+ "left"
6753
+ );
6754
+ if (xNext !== null) {
6755
+ return xNext;
6756
+ }
6757
+ }
6758
+ if (cursorOffsetInLine > row.startOffset) {
6759
+ const xPrev = measureCharEdgeX(
6760
+ cursorOffsetInLine - 1,
6761
+ cursorOffsetInLine,
6762
+ "right"
6763
+ );
6764
+ if (xPrev !== null) {
6765
+ return xPrev;
6766
+ }
6767
+ }
6768
+ if (cursorOffsetInLine < row.endOffset) {
6769
+ const xNext = measureCharEdgeX(
6770
+ cursorOffsetInLine,
6771
+ cursorOffsetInLine + 1,
6772
+ "left"
6773
+ );
6774
+ if (xNext !== null) {
6775
+ return xNext;
6776
+ }
6777
+ }
6778
+ const codeUnitOffset = cursorOffsetToCodeUnit(
6779
+ lineInfo.cursorToCodeUnit,
6780
+ cursorOffsetInLine
6781
+ );
6782
+ const position = resolvePosition(codeUnitOffset);
6783
+ scratchRange.setStart(position.node, position.offset);
6784
+ scratchRange.setEnd(position.node, position.offset);
6785
+ const rects = scratchRange.getClientRects();
6786
+ const candidates = rects.length > 0 ? Array.from(rects) : [scratchRange.getBoundingClientRect()];
6787
+ if (candidates.length === 0) {
6788
+ return null;
6789
+ }
6790
+ let best = candidates[0];
6791
+ let bestDistance = Number.POSITIVE_INFINITY;
6792
+ for (const rect of candidates) {
6793
+ const top = rect.top - containerRect.top + scroll.top;
6794
+ const distance = Math.abs(top - rowTop);
6795
+ if (distance < bestDistance) {
6796
+ bestDistance = distance;
6797
+ best = rect;
6798
+ }
6799
+ }
6800
+ if (bestDistance > maxRowTopDelta) {
6801
+ return null;
6802
+ }
6803
+ if (best.height <= 0) {
6804
+ return null;
6805
+ }
6806
+ return best.left - containerRect.left + scroll.left;
6807
+ };
6808
+ const caretX = (cursorOffsetInLine) => {
6809
+ return measureCaretXOnRow(cursorOffsetInLine) ?? approximateX(cursorOffsetInLine);
6810
+ };
6811
+ let low = row.startOffset;
6812
+ let high = row.endOffset;
6813
+ while (low < high) {
6814
+ const mid = low + high >>> 1;
6815
+ const xMid = caretX(mid);
6816
+ if (xMid < relativeX) {
6817
+ low = mid + 1;
6818
+ } else {
6819
+ high = mid;
6820
+ }
6821
+ }
6822
+ const candidateA = Math.max(row.startOffset, Math.min(low, row.endOffset));
6823
+ const candidateB = Math.max(
6824
+ row.startOffset,
6825
+ Math.min(candidateA - 1, row.endOffset)
6826
+ );
6827
+ const xA = caretX(candidateA);
6828
+ const xB = caretX(candidateB);
6829
+ const distA = Math.abs(relativeX - xA);
6830
+ const distB = Math.abs(relativeX - xB);
6831
+ const DIST_EPS_PX = 0.5;
6832
+ let closestOffset = (() => {
6833
+ if (distB + DIST_EPS_PX < distA) {
6834
+ return candidateB;
6835
+ }
6836
+ if (distA + DIST_EPS_PX < distB) {
6837
+ return candidateA;
6838
+ }
6839
+ const mid = (xA + xB) / 2;
6840
+ return relativeX >= mid ? candidateA : candidateB;
6841
+ })();
6842
+ const endX = caretX(row.endOffset);
6843
+ {
6844
+ const baseMeasuredX = measureCaretXOnRow(closestOffset);
6845
+ if (baseMeasuredX !== null) {
6846
+ const baseCodeUnit = cursorOffsetToCodeUnit(
6847
+ lineInfo.cursorToCodeUnit,
6848
+ closestOffset
6849
+ );
6850
+ const COLLAPSE_EPS_PX = 0.25;
6851
+ while (closestOffset > row.startOffset) {
6852
+ const prev = closestOffset - 1;
6853
+ const prevCodeUnit = cursorOffsetToCodeUnit(lineInfo.cursorToCodeUnit, prev);
6854
+ if (prevCodeUnit !== baseCodeUnit) {
6855
+ break;
6856
+ }
6857
+ const prevMeasuredX = measureCaretXOnRow(prev);
6858
+ if (prevMeasuredX === null) {
6859
+ break;
6860
+ }
6861
+ if (Math.abs(prevMeasuredX - baseMeasuredX) > COLLAPSE_EPS_PX) {
6862
+ break;
6863
+ }
6864
+ closestOffset = prev;
6865
+ }
6866
+ }
6867
+ }
6868
+ const boundaryX = caretX(closestOffset);
6869
+ const choseRightEdge = closestOffset > row.startOffset && relativeX < boundaryX - 0.01;
6870
+ const isEndOfLine = row.endOffset === lineInfo.cursorLength;
6871
+ const atLineEnd = closestOffset === row.endOffset && isEndOfLine;
6872
+ const pastRowEnd = !atLineEnd && choseRightEdge || !atLineEnd && closestOffset === row.endOffset && row.endOffset < lineInfo.cursorLength && relativeX > endX + 0.5;
6873
+ return {
6874
+ cursorOffset: lineStartOffset + closestOffset,
6875
+ pastRowEnd
6876
+ };
6877
+ }
6465
6878
  function rectRight$1(rect) {
6466
6879
  return rect.left + rect.width;
6467
6880
  }
@@ -6771,7 +7184,14 @@ function getCaretRect(params) {
6771
7184
  backRange.setEnd(backEnd.node, backEnd.offset);
6772
7185
  const backRects = backRange.getClientRects();
6773
7186
  if (backRects.length > 0) {
6774
- backwardRect = backRects[backRects.length - 1];
7187
+ let bestRect = backRects[backRects.length - 1];
7188
+ for (let i = 0; i < backRects.length; i += 1) {
7189
+ const rect = backRects[i];
7190
+ if (rect.width > 0 && (bestRect.width === 0 || rect.top < bestRect.top)) {
7191
+ bestRect = rect;
7192
+ }
7193
+ }
7194
+ backwardRect = bestRect;
6775
7195
  }
6776
7196
  }
6777
7197
  if (canProbeForward) {
@@ -6788,7 +7208,14 @@ function getCaretRect(params) {
6788
7208
  fwdRange.setEnd(fwdEnd.node, fwdEnd.offset);
6789
7209
  const fwdRects = fwdRange.getClientRects();
6790
7210
  if (fwdRects.length > 0) {
6791
- forwardRect = fwdRects[0];
7211
+ let bestRect = fwdRects[0];
7212
+ for (let i = 1; i < fwdRects.length; i += 1) {
7213
+ const rect = fwdRects[i];
7214
+ if (rect.width > 0 && (bestRect.width === 0 || rect.top > bestRect.top)) {
7215
+ bestRect = rect;
7216
+ }
7217
+ }
7218
+ forwardRect = bestRect;
6792
7219
  }
6793
7220
  }
6794
7221
  const atWrapBoundary = backwardRect && forwardRect && Math.abs(backwardRect.top - forwardRect.top) > 5;
@@ -6796,8 +7223,43 @@ function getCaretRect(params) {
6796
7223
  let useRightEdge = false;
6797
7224
  if (atWrapBoundary) {
6798
7225
  if (affinity === "backward" && backwardRect) {
6799
- probeRect = backwardRect;
6800
- useRightEdge = true;
7226
+ if (forwardRect) {
7227
+ const startPos = resolveDomPosition(
7228
+ lineElement,
7229
+ cursorOffsetToDomOffset(lineInfo.cursorToCodeUnit, 0)
7230
+ );
7231
+ const endPos = resolveDomPosition(
7232
+ lineElement,
7233
+ cursorOffsetToDomOffset(lineInfo.cursorToCodeUnit, lineInfo.cursorLength)
7234
+ );
7235
+ const lineRange = document.createRange();
7236
+ lineRange.setStart(startPos.node, startPos.offset);
7237
+ lineRange.setEnd(endPos.node, endPos.offset);
7238
+ const rowRects = groupDomRectsByRow(Array.from(lineRange.getClientRects()));
7239
+ const ROW_EPS_PX = 1;
7240
+ let previousRow = null;
7241
+ for (const rowRect of rowRects) {
7242
+ if (rowRect.top < forwardRect.top - ROW_EPS_PX) {
7243
+ previousRow = rowRect;
7244
+ } else {
7245
+ break;
7246
+ }
7247
+ }
7248
+ if (previousRow) {
7249
+ caretRect = new DOMRect(
7250
+ previousRow.right,
7251
+ previousRow.top,
7252
+ 0,
7253
+ previousRow.height
7254
+ );
7255
+ } else {
7256
+ probeRect = backwardRect;
7257
+ useRightEdge = true;
7258
+ }
7259
+ } else {
7260
+ probeRect = backwardRect;
7261
+ useRightEdge = true;
7262
+ }
6801
7263
  } else if (forwardRect) {
6802
7264
  probeRect = forwardRect;
6803
7265
  useRightEdge = false;
@@ -6818,6 +7280,37 @@ function getCaretRect(params) {
6818
7280
  const left = useRightEdge ? probeRect.right : probeRect.left;
6819
7281
  caretRect = new DOMRect(left, probeRect.top, 0, probeRect.height);
6820
7282
  }
7283
+ if (affinity === "backward" && forwardRect) {
7284
+ const startPos = resolveDomPosition(
7285
+ lineElement,
7286
+ cursorOffsetToDomOffset(lineInfo.cursorToCodeUnit, 0)
7287
+ );
7288
+ const endPos = resolveDomPosition(
7289
+ lineElement,
7290
+ cursorOffsetToDomOffset(lineInfo.cursorToCodeUnit, lineInfo.cursorLength)
7291
+ );
7292
+ const lineRange = document.createRange();
7293
+ lineRange.setStart(startPos.node, startPos.offset);
7294
+ lineRange.setEnd(endPos.node, endPos.offset);
7295
+ const rowRects = groupDomRectsByRow(Array.from(lineRange.getClientRects()));
7296
+ const ROW_EPS_PX = 1;
7297
+ let previousRow = null;
7298
+ for (const rowRect of rowRects) {
7299
+ if (rowRect.top < forwardRect.top - ROW_EPS_PX) {
7300
+ previousRow = rowRect;
7301
+ } else {
7302
+ break;
7303
+ }
7304
+ }
7305
+ if (previousRow && caretRect.top >= forwardRect.top - ROW_EPS_PX) {
7306
+ caretRect = new DOMRect(
7307
+ previousRow.right,
7308
+ previousRow.top,
7309
+ 0,
7310
+ previousRow.height
7311
+ );
7312
+ }
7313
+ }
6821
7314
  }
6822
7315
  if (caretRect.height === 0 && lineRect.height === 0) {
6823
7316
  return null;
@@ -7656,6 +8149,8 @@ class CakeEngine {
7656
8149
  this.handleCompositionStartBound = this.handleCompositionStart.bind(this);
7657
8150
  this.handleCompositionEndBound = this.handleCompositionEnd.bind(this);
7658
8151
  this.handleSelectionChangeBound = this.handleSelectionChange.bind(this);
8152
+ this.handleFocusInBound = this.handleFocusIn.bind(this);
8153
+ this.handleFocusOutBound = this.handleFocusOut.bind(this);
7659
8154
  this.handleScrollBound = this.handleScroll.bind(this);
7660
8155
  this.handleResizeBound = this.handleResize.bind(this);
7661
8156
  this.handleClickBound = this.handleClick.bind(this);
@@ -7753,6 +8248,9 @@ class CakeEngine {
7753
8248
  getContentRoot() {
7754
8249
  return this.contentRoot;
7755
8250
  }
8251
+ getLines() {
8252
+ return getDocLines(this.state.doc);
8253
+ }
7756
8254
  getOverlayRoot() {
7757
8255
  return this.ensureExtensionsRoot();
7758
8256
  }
@@ -7872,7 +8370,7 @@ class CakeEngine {
7872
8370
  canRedo() {
7873
8371
  return this.history.redoStack.length > 0;
7874
8372
  }
7875
- executeCommand(command) {
8373
+ executeCommand(command, options) {
7876
8374
  var _a;
7877
8375
  const shouldOpenLinkPopover = "openPopover" in command && command.openPopover === true;
7878
8376
  const nextState = this.runtime.applyEdit(command, this.state);
@@ -7885,10 +8383,13 @@ class CakeEngine {
7885
8383
  (_a = this.onChange) == null ? void 0 : _a.call(this, this.state.source, this.state.selection);
7886
8384
  this.scheduleScrollCaretIntoView();
7887
8385
  if (shouldOpenLinkPopover) {
7888
- queueMicrotask(() => {
8386
+ window.requestAnimationFrame(() => {
7889
8387
  this.openLinkPopoverForSelection(true);
7890
8388
  });
7891
8389
  }
8390
+ if (options == null ? void 0 : options.restoreFocus) {
8391
+ this.focus();
8392
+ }
7892
8393
  return true;
7893
8394
  }
7894
8395
  attachListeners() {
@@ -7902,6 +8403,8 @@ class CakeEngine {
7902
8403
  "compositionend",
7903
8404
  this.handleCompositionEndBound
7904
8405
  );
8406
+ this.container.addEventListener("focusin", this.handleFocusInBound);
8407
+ this.container.addEventListener("focusout", this.handleFocusOutBound);
7905
8408
  document.addEventListener(
7906
8409
  "selectionchange",
7907
8410
  this.handleSelectionChangeBound
@@ -7958,6 +8461,8 @@ class CakeEngine {
7958
8461
  "compositionend",
7959
8462
  this.handleCompositionEndBound
7960
8463
  );
8464
+ this.container.removeEventListener("focusin", this.handleFocusInBound);
8465
+ this.container.removeEventListener("focusout", this.handleFocusOutBound);
7961
8466
  document.removeEventListener(
7962
8467
  "selectionchange",
7963
8468
  this.handleSelectionChangeBound
@@ -7982,6 +8487,16 @@ class CakeEngine {
7982
8487
  this.container.removeEventListener("pointerup", this.handlePointerUpBound);
7983
8488
  this.detachDragListeners();
7984
8489
  }
8490
+ handleFocusIn() {
8491
+ queueMicrotask(() => {
8492
+ this.scheduleOverlayUpdate();
8493
+ });
8494
+ }
8495
+ handleFocusOut() {
8496
+ queueMicrotask(() => {
8497
+ this.scheduleOverlayUpdate();
8498
+ });
8499
+ }
7985
8500
  render() {
7986
8501
  const perfEnabled = this.container.dataset.cakePerf === "1";
7987
8502
  let perfStart = 0;
@@ -8037,7 +8552,7 @@ class CakeEngine {
8037
8552
  this.contentRoot
8038
8553
  );
8039
8554
  const existingChildren = Array.from(this.contentRoot.childNodes);
8040
- const isManagedChild = (node) => node instanceof Element && node.hasAttribute("data-line-index");
8555
+ const isManagedChild = (node) => node instanceof Element && (node.hasAttribute("data-line-index") || node.hasAttribute("data-block-wrapper"));
8041
8556
  const existingManagedChildren = existingChildren.filter(isManagedChild);
8042
8557
  const preservedChildren = existingChildren.filter((node) => !isManagedChild(node));
8043
8558
  const needsUpdate = content.length !== existingManagedChildren.length || content.some((node, i) => node !== existingManagedChildren[i]);
@@ -8283,7 +8798,7 @@ class CakeEngine {
8283
8798
  };
8284
8799
  }
8285
8800
  handleClick(event) {
8286
- var _a, _b, _c, _d;
8801
+ var _a, _b, _c, _d, _e;
8287
8802
  if (this.isComposing) {
8288
8803
  return;
8289
8804
  }
@@ -8338,6 +8853,29 @@ class CakeEngine {
8338
8853
  }, 0);
8339
8854
  return;
8340
8855
  }
8856
+ if (!pendingHit) {
8857
+ const hit2 = this.hitTestFromClientPoint(event.clientX, event.clientY);
8858
+ if (!hit2) {
8859
+ return;
8860
+ }
8861
+ const newSelection = {
8862
+ start: hit2.cursorOffset,
8863
+ end: hit2.cursorOffset,
8864
+ affinity: hit2.affinity
8865
+ };
8866
+ this.pendingClickHit = null;
8867
+ this.suppressSelectionChange = true;
8868
+ this.state = this.runtime.updateSelection(this.state, newSelection, {
8869
+ kind: "dom"
8870
+ });
8871
+ this.applySelection(this.state.selection);
8872
+ (_c = this.onSelectionChange) == null ? void 0 : _c.call(this, this.state.selection);
8873
+ this.scheduleOverlayUpdate();
8874
+ setTimeout(() => {
8875
+ this.suppressSelectionChange = false;
8876
+ }, 0);
8877
+ return;
8878
+ }
8341
8879
  this.pendingClickHit = null;
8342
8880
  setTimeout(() => {
8343
8881
  this.suppressSelectionChange = false;
@@ -8373,7 +8911,7 @@ class CakeEngine {
8373
8911
  kind: "dom"
8374
8912
  });
8375
8913
  this.applySelection(this.state.selection);
8376
- (_c = this.onSelectionChange) == null ? void 0 : _c.call(this, this.state.selection);
8914
+ (_d = this.onSelectionChange) == null ? void 0 : _d.call(this, this.state.selection);
8377
8915
  this.suppressSelectionChange = false;
8378
8916
  return;
8379
8917
  }
@@ -8397,7 +8935,7 @@ class CakeEngine {
8397
8935
  kind: "dom"
8398
8936
  });
8399
8937
  this.applySelection(this.state.selection);
8400
- (_d = this.onSelectionChange) == null ? void 0 : _d.call(this, this.state.selection);
8938
+ (_e = this.onSelectionChange) == null ? void 0 : _e.call(this, this.state.selection);
8401
8939
  this.suppressSelectionChange = false;
8402
8940
  }
8403
8941
  }
@@ -8622,13 +9160,15 @@ class CakeEngine {
8622
9160
  }
8623
9161
  }
8624
9162
  resolveExtensionKeybinding(event) {
9163
+ const eventKey = event.key.length === 1 ? event.key.toLowerCase() : event.key;
8625
9164
  for (const extension of this.extensions) {
8626
9165
  const bindings = extension.keybindings;
8627
9166
  if (!bindings) {
8628
9167
  continue;
8629
9168
  }
8630
9169
  for (const binding of bindings) {
8631
- if (binding.key !== event.key) {
9170
+ const bindingKey = binding.key.length === 1 ? binding.key.toLowerCase() : binding.key;
9171
+ if (bindingKey !== eventKey) {
8632
9172
  continue;
8633
9173
  }
8634
9174
  if (binding.meta !== void 0 && binding.meta !== event.metaKey) {
@@ -10103,78 +10643,22 @@ class CakeEngine {
10103
10643
  }
10104
10644
  }
10105
10645
  hitTestFromClientPoint(clientX, clientY) {
10106
- var _a, _b;
10107
- let node = null;
10108
- let offset = 0;
10109
- let pastRowEnd = false;
10110
- const position = caretPositionFromPoint(clientX, clientY);
10111
- if (position) {
10112
- node = position.offsetNode;
10113
- offset = position.offset;
10114
- } else {
10115
- const range = caretRangeFromPoint(clientX, clientY);
10116
- if (range) {
10117
- node = range.startContainer;
10118
- offset = range.startOffset;
10119
- }
10120
- }
10121
- if (!node || !this.container.contains(node)) {
10122
- const closestLine = this.findClosestLineByY(clientY);
10123
- const textNode = closestLine ? findFirstTextNode(closestLine) : null;
10124
- if (textNode) {
10125
- node = textNode;
10126
- const hit = findOffsetInTextNode(textNode, clientX, clientY);
10127
- offset = hit.offset;
10128
- pastRowEnd = hit.pastRowEnd;
10129
- }
10130
- }
10131
- if (!node || !this.container.contains(node)) {
10646
+ if (!this.contentRoot) {
10132
10647
  return null;
10133
10648
  }
10134
- const lineElement = node instanceof Element ? node.closest(".cake-line") : (_a = node.parentElement) == null ? void 0 : _a.closest(".cake-line");
10135
- if (lineElement) {
10136
- const lineRect = lineElement.getBoundingClientRect();
10137
- const isClickOutsideLine = clientY < lineRect.top || clientY > lineRect.bottom;
10138
- if (isClickOutsideLine) {
10139
- const closestLine = this.findClosestLineByY(clientY);
10140
- if (closestLine && closestLine !== lineElement) {
10141
- const textNode = findFirstTextNode(closestLine);
10142
- if (textNode) {
10143
- node = textNode;
10144
- const hit = findOffsetInTextNode(textNode, clientX, clientY);
10145
- offset = hit.offset;
10146
- pastRowEnd = hit.pastRowEnd;
10147
- }
10148
- }
10149
- }
10150
- }
10151
- if (node instanceof Element) {
10152
- const resolved = resolveTextPoint(node, offset);
10153
- if (resolved) {
10154
- node = resolved.node;
10155
- offset = resolved.offset;
10156
- }
10157
- }
10158
- if (node instanceof Text) {
10159
- const hit = findOffsetInTextNode(node, clientX, clientY);
10160
- offset = hit.offset;
10161
- pastRowEnd = hit.pastRowEnd;
10162
- }
10163
- if (!pastRowEnd) {
10164
- const lineElement2 = node instanceof Element ? node.closest(".cake-line") : (_b = node.parentElement) == null ? void 0 : _b.closest(".cake-line");
10165
- if (lineElement2) {
10166
- const lineRect = lineElement2.getBoundingClientRect();
10167
- pastRowEnd = clientX > lineRect.right;
10168
- }
10169
- }
10170
- const cursor = this.cursorFromDom(node, offset);
10171
- if (!cursor) {
10649
+ const lines = getDocLines(this.state.doc);
10650
+ const hit = hitTestFromLayout({
10651
+ clientX,
10652
+ clientY,
10653
+ root: this.contentRoot,
10654
+ container: this.container,
10655
+ lines
10656
+ });
10657
+ if (!hit) {
10172
10658
  return null;
10173
10659
  }
10174
- if (!pastRowEnd) {
10175
- return cursor;
10176
- }
10177
- return { cursorOffset: cursor.cursorOffset, affinity: "backward" };
10660
+ const affinity = hit.pastRowEnd ? "backward" : "forward";
10661
+ return { cursorOffset: hit.cursorOffset, affinity };
10178
10662
  }
10179
10663
  handlePointerDown(event) {
10180
10664
  var _a, _b, _c;
@@ -10886,178 +11370,6 @@ function findTextNodeAtOrAfter(nodes, start) {
10886
11370
  }
10887
11371
  return null;
10888
11372
  }
10889
- function findOffsetInTextNode(textNode, clientX, clientY) {
10890
- const text = textNode.textContent ?? "";
10891
- if (text.length === 0) {
10892
- return { offset: 0, pastRowEnd: false };
10893
- }
10894
- let closestOffset = 0;
10895
- let closestDistance = Infinity;
10896
- let closestYDistance = Infinity;
10897
- let closestCaretX = 0;
10898
- let selectedViaRightEdge = false;
10899
- const rowInfo = /* @__PURE__ */ new Map();
10900
- const range = document.createRange();
10901
- let lastCharRect = null;
10902
- for (let i = 0; i <= text.length; i += 1) {
10903
- if (i < text.length) {
10904
- range.setStart(textNode, i);
10905
- range.setEnd(textNode, i + 1);
10906
- } else {
10907
- range.setStart(textNode, i);
10908
- range.setEnd(textNode, i);
10909
- }
10910
- let rects = range.getClientRects();
10911
- if (rects.length === 0 && i === text.length && lastCharRect) {
10912
- const syntheticRect = new DOMRect(
10913
- lastCharRect.right,
10914
- lastCharRect.top,
10915
- 0,
10916
- lastCharRect.height
10917
- );
10918
- rects = [syntheticRect];
10919
- }
10920
- if (rects.length === 0) {
10921
- continue;
10922
- }
10923
- if (i < text.length) {
10924
- lastCharRect = rects[0];
10925
- }
10926
- let bestRect = rects[0];
10927
- for (let r = 1; r < rects.length; r += 1) {
10928
- const rect = rects[r];
10929
- const bestCenterY = bestRect.top + bestRect.height / 2;
10930
- const rectCenterY = rect.top + rect.height / 2;
10931
- if (Math.abs(clientY - rectCenterY) < Math.abs(clientY - bestCenterY)) {
10932
- bestRect = rect;
10933
- }
10934
- }
10935
- const rowKey = Math.round(bestRect.top);
10936
- if (!rowInfo.has(rowKey)) {
10937
- rowInfo.set(rowKey, {
10938
- startOffset: i,
10939
- endOffset: i,
10940
- left: bestRect.left,
10941
- right: bestRect.right,
10942
- top: bestRect.top,
10943
- bottom: bestRect.bottom
10944
- });
10945
- } else {
10946
- const row = rowInfo.get(rowKey);
10947
- if (row) {
10948
- row.startOffset = Math.min(row.startOffset, i);
10949
- row.endOffset = Math.max(row.endOffset, i);
10950
- row.left = Math.min(row.left, bestRect.left);
10951
- row.right = Math.max(row.right, bestRect.right);
10952
- row.top = Math.min(row.top, bestRect.top);
10953
- row.bottom = Math.max(row.bottom, bestRect.bottom);
10954
- }
10955
- }
10956
- const centerY = bestRect.top + bestRect.height / 2;
10957
- const yDistance = Math.abs(clientY - centerY);
10958
- const isWithinRowBounds = clientY >= bestRect.top && clientY <= bestRect.bottom;
10959
- const isSameRow = isWithinRowBounds;
10960
- const caretX = bestRect.left;
10961
- const xDistance = Math.abs(clientX - caretX);
10962
- if (isSameRow) {
10963
- if (xDistance <= closestDistance) {
10964
- closestDistance = xDistance;
10965
- closestOffset = i;
10966
- closestCaretX = caretX;
10967
- bestRect.top;
10968
- closestYDistance = yDistance;
10969
- selectedViaRightEdge = false;
10970
- }
10971
- if (i < text.length) {
10972
- const rightEdgeX = bestRect.right;
10973
- const rightEdgeDistance = Math.abs(clientX - rightEdgeX);
10974
- if (rightEdgeDistance < closestDistance) {
10975
- closestDistance = rightEdgeDistance;
10976
- closestOffset = i + 1;
10977
- closestCaretX = rightEdgeX;
10978
- bestRect.top;
10979
- closestYDistance = yDistance;
10980
- selectedViaRightEdge = true;
10981
- }
10982
- }
10983
- } else if (yDistance < closestYDistance || yDistance === closestYDistance && xDistance < closestDistance) {
10984
- closestYDistance = yDistance;
10985
- closestDistance = xDistance;
10986
- closestOffset = i;
10987
- closestCaretX = caretX;
10988
- bestRect.top;
10989
- }
10990
- }
10991
- let closestRow = null;
10992
- for (const row of rowInfo.values()) {
10993
- if (clientY >= row.top && clientY <= row.bottom) {
10994
- closestRow = row;
10995
- break;
10996
- }
10997
- }
10998
- if (!closestRow) {
10999
- let smallestDistance = Infinity;
11000
- for (const row of rowInfo.values()) {
11001
- const centerY = row.top + (row.bottom - row.top) / 2;
11002
- const distance = Math.abs(clientY - centerY);
11003
- if (distance < smallestDistance) {
11004
- smallestDistance = distance;
11005
- closestRow = row;
11006
- }
11007
- }
11008
- }
11009
- if (closestRow) {
11010
- if (clientX < closestRow.left) {
11011
- closestOffset = closestRow.startOffset;
11012
- closestCaretX = closestRow.left;
11013
- closestRow.top;
11014
- } else if (clientX > closestRow.right) {
11015
- closestOffset = Math.min(closestRow.endOffset + 1, text.length);
11016
- closestCaretX = closestRow.right;
11017
- closestRow.top;
11018
- } else if (clientY < closestRow.top || clientY > closestRow.bottom) {
11019
- let bestXDistance = Infinity;
11020
- const range2 = document.createRange();
11021
- for (let i = closestRow.startOffset; i <= closestRow.endOffset; i += 1) {
11022
- if (i < text.length) {
11023
- range2.setStart(textNode, i);
11024
- range2.setEnd(textNode, i + 1);
11025
- } else {
11026
- range2.setStart(textNode, i);
11027
- range2.setEnd(textNode, i);
11028
- }
11029
- const rects = range2.getClientRects();
11030
- if (rects.length === 0) continue;
11031
- const rect = rects[0];
11032
- const xDist = Math.abs(clientX - rect.left);
11033
- if (xDist <= bestXDistance) {
11034
- bestXDistance = xDist;
11035
- closestOffset = i;
11036
- closestCaretX = rect.left;
11037
- closestRow.top;
11038
- }
11039
- }
11040
- }
11041
- }
11042
- const pastRowEnd = selectedViaRightEdge || closestRow !== null && clientX > closestRow.right;
11043
- if (Math.abs(clientX - closestCaretX) <= 2 && closestOffset < text.length && text[closestOffset] === "\n") {
11044
- closestOffset = Math.max(0, closestOffset - 1);
11045
- }
11046
- return { offset: closestOffset, pastRowEnd };
11047
- }
11048
- function caretPositionFromPoint(x, y) {
11049
- const doc = document;
11050
- if (typeof doc.caretPositionFromPoint === "function") {
11051
- return doc.caretPositionFromPoint(x, y);
11052
- }
11053
- return null;
11054
- }
11055
- function caretRangeFromPoint(x, y) {
11056
- if (typeof document.caretRangeFromPoint === "function") {
11057
- return document.caretRangeFromPoint(x, y);
11058
- }
11059
- return null;
11060
- }
11061
11373
  function getVisualRowBoundaries(params) {
11062
11374
  const { lines, layout, offset, affinity } = params;
11063
11375
  if (!layout || layout.lines.length === 0) {
@@ -11152,302 +11464,6 @@ function findTextNodeAtOrBefore(nodes, start) {
11152
11464
  }
11153
11465
  return null;
11154
11466
  }
11155
- const toggleBold = ({ state: state$1, dispatch }) => {
11156
- const changes = state$1.changeByRange((range) => {
11157
- const isBoldBefore = state$1.sliceDoc(range.from - 2, range.from) === "**";
11158
- const isBoldAfter = state$1.sliceDoc(range.to, range.to + 2) === "**";
11159
- const changes2 = [];
11160
- changes2.push(
11161
- isBoldBefore ? {
11162
- from: range.from - 2,
11163
- to: range.from,
11164
- insert: ""
11165
- } : {
11166
- from: range.from,
11167
- insert: "**"
11168
- }
11169
- );
11170
- changes2.push(
11171
- isBoldAfter ? {
11172
- from: range.to,
11173
- to: range.to + 2,
11174
- insert: ""
11175
- } : {
11176
- from: range.to,
11177
- insert: "**"
11178
- }
11179
- );
11180
- const extendBefore = isBoldBefore ? -2 : 2;
11181
- const extendAfter = isBoldAfter ? -2 : 2;
11182
- return {
11183
- changes: changes2,
11184
- range: state.EditorSelection.range(
11185
- range.from + extendBefore,
11186
- range.to + extendAfter
11187
- )
11188
- };
11189
- });
11190
- dispatch(
11191
- state$1.update(changes, {
11192
- scrollIntoView: true,
11193
- annotations: state.Transaction.userEvent.of("input")
11194
- })
11195
- );
11196
- return true;
11197
- };
11198
- const toggleItalic = ({ state: state$1, dispatch }) => {
11199
- const changes = state$1.changeByRange((range) => {
11200
- const isItalicBefore = state$1.sliceDoc(range.from - 1, range.from) === "*";
11201
- const isItalicAfter = state$1.sliceDoc(range.to, range.to + 1) === "*";
11202
- const changes2 = [];
11203
- changes2.push(
11204
- isItalicBefore ? {
11205
- from: range.from - 1,
11206
- to: range.from,
11207
- insert: ""
11208
- } : {
11209
- from: range.from,
11210
- insert: "*"
11211
- }
11212
- );
11213
- changes2.push(
11214
- isItalicAfter ? {
11215
- from: range.to,
11216
- to: range.to + 1,
11217
- insert: ""
11218
- } : {
11219
- from: range.to,
11220
- insert: "*"
11221
- }
11222
- );
11223
- const extendBefore = isItalicBefore ? -1 : 1;
11224
- const extendAfter = isItalicAfter ? -1 : 1;
11225
- return {
11226
- changes: changes2,
11227
- range: state.EditorSelection.range(
11228
- range.from + extendBefore,
11229
- range.to + extendAfter
11230
- )
11231
- };
11232
- });
11233
- dispatch(
11234
- state$1.update(changes, {
11235
- scrollIntoView: true,
11236
- annotations: state.Transaction.userEvent.of("input")
11237
- })
11238
- );
11239
- return true;
11240
- };
11241
- const toggleStrikethrough = ({ state: state$1, dispatch }) => {
11242
- const changes = state$1.changeByRange((range) => {
11243
- const isStrikethroughBefore = state$1.sliceDoc(range.from - 2, range.from) === "~~";
11244
- const isStrikethroughAfter = state$1.sliceDoc(range.to, range.to + 2) === "~~";
11245
- const changes2 = [];
11246
- changes2.push(
11247
- isStrikethroughBefore ? {
11248
- from: range.from - 2,
11249
- to: range.from,
11250
- insert: ""
11251
- } : {
11252
- from: range.from,
11253
- insert: "~~"
11254
- }
11255
- );
11256
- changes2.push(
11257
- isStrikethroughAfter ? {
11258
- from: range.to,
11259
- to: range.to + 2,
11260
- insert: ""
11261
- } : {
11262
- from: range.to,
11263
- insert: "~~"
11264
- }
11265
- );
11266
- const extendBefore = isStrikethroughBefore ? -2 : 2;
11267
- const extendAfter = isStrikethroughAfter ? -2 : 2;
11268
- return {
11269
- changes: changes2,
11270
- range: state.EditorSelection.range(
11271
- range.from + extendBefore,
11272
- range.to + extendAfter
11273
- )
11274
- };
11275
- });
11276
- dispatch(
11277
- state$1.update(changes, {
11278
- scrollIntoView: true,
11279
- annotations: state.Transaction.userEvent.of("input")
11280
- })
11281
- );
11282
- return true;
11283
- };
11284
- const toggleLink = ({ state: state$1, dispatch }) => {
11285
- const changes = state$1.changeByRange((range) => {
11286
- const changes2 = [];
11287
- const selectedText = state$1.sliceDoc(range.from, range.to);
11288
- const linkRegex = /^\[([^\]]*)\]\(([^)]*)\)$/;
11289
- const linkMatch = selectedText.match(linkRegex);
11290
- if (linkMatch) {
11291
- const linkText = linkMatch[1];
11292
- changes2.push({
11293
- from: range.from,
11294
- to: range.to,
11295
- insert: linkText
11296
- });
11297
- return {
11298
- changes: changes2,
11299
- range: state.EditorSelection.range(range.from, range.from + linkText.length)
11300
- };
11301
- } else {
11302
- changes2.push({
11303
- from: range.from,
11304
- insert: "["
11305
- });
11306
- changes2.push({
11307
- from: range.to,
11308
- insert: "]()"
11309
- });
11310
- const newCursorPos = range.to + 3;
11311
- return {
11312
- changes: changes2,
11313
- range: state.EditorSelection.cursor(newCursorPos)
11314
- // Place cursor inside ()
11315
- };
11316
- }
11317
- });
11318
- dispatch(
11319
- state$1.update(changes, {
11320
- scrollIntoView: true,
11321
- annotations: state.Transaction.userEvent.of("input")
11322
- })
11323
- );
11324
- return true;
11325
- };
11326
- const LIST_LINE_REGEX = /^(\s*)([-*+]|(\d+)\.)(\s+)(.*)/;
11327
- const toggleBulletList = ({ state: state$1, dispatch }) => {
11328
- const changes = state$1.changeByRange((range) => {
11329
- const changes2 = [];
11330
- if (range.from === range.to) {
11331
- changes2.push({
11332
- from: range.from,
11333
- insert: "-"
11334
- });
11335
- return {
11336
- changes: changes2,
11337
- range: state.EditorSelection.cursor(range.from + 1)
11338
- };
11339
- }
11340
- const startLine = state$1.doc.lineAt(range.from);
11341
- const endLine = state$1.doc.lineAt(range.to);
11342
- let rangeDelta = 0;
11343
- for (let i = startLine.number; i <= endLine.number; i++) {
11344
- const line = state$1.doc.line(i);
11345
- const lineText = line.text;
11346
- const match = lineText.match(LIST_LINE_REGEX);
11347
- if (match) {
11348
- const [, indent, , numberPart, space] = match;
11349
- if (numberPart) {
11350
- const prefixLength = indent.length + numberPart.length + 1 + space.length;
11351
- const newPrefix = `${indent}- `;
11352
- changes2.push({
11353
- from: line.from,
11354
- to: line.from + prefixLength,
11355
- insert: newPrefix
11356
- });
11357
- rangeDelta += newPrefix.length - prefixLength;
11358
- }
11359
- } else {
11360
- const indentMatch = lineText.match(/^(\s*)/);
11361
- const indent = indentMatch ? indentMatch[1] : "";
11362
- changes2.push({
11363
- from: line.from + indent.length,
11364
- insert: "- "
11365
- });
11366
- rangeDelta += 2;
11367
- }
11368
- }
11369
- return {
11370
- changes: changes2,
11371
- range: state.EditorSelection.range(range.from, range.to + rangeDelta)
11372
- };
11373
- });
11374
- dispatch(
11375
- state$1.update(changes, {
11376
- scrollIntoView: true,
11377
- annotations: state.Transaction.userEvent.of("input")
11378
- })
11379
- );
11380
- return true;
11381
- };
11382
- const toggleNumberedList = ({ state: state$1, dispatch }) => {
11383
- const changes = state$1.changeByRange((range) => {
11384
- const changes2 = [];
11385
- if (range.from === range.to) {
11386
- changes2.push({
11387
- from: range.from,
11388
- insert: "1. "
11389
- });
11390
- return {
11391
- changes: changes2,
11392
- range: state.EditorSelection.cursor(range.from + 3)
11393
- };
11394
- }
11395
- const startLine = state$1.doc.lineAt(range.from);
11396
- const endLine = state$1.doc.lineAt(range.to);
11397
- let listNumber = 1;
11398
- let rangeDelta = 0;
11399
- for (let i = startLine.number; i <= endLine.number; i++) {
11400
- const line = state$1.doc.line(i);
11401
- const lineText = line.text;
11402
- const match = lineText.match(LIST_LINE_REGEX);
11403
- if (match) {
11404
- const [, indent, bullet, numberPart, space] = match;
11405
- if (!numberPart) {
11406
- const prefixLength = indent.length + bullet.length + space.length;
11407
- const newPrefix = `${indent}${listNumber}. `;
11408
- changes2.push({
11409
- from: line.from,
11410
- to: line.from + prefixLength,
11411
- insert: newPrefix
11412
- });
11413
- rangeDelta += newPrefix.length - prefixLength;
11414
- listNumber++;
11415
- } else {
11416
- const prefixLength = indent.length + numberPart.length + 1 + space.length;
11417
- const newPrefix = `${indent}${listNumber}. `;
11418
- changes2.push({
11419
- from: line.from,
11420
- to: line.from + prefixLength,
11421
- insert: newPrefix
11422
- });
11423
- rangeDelta += newPrefix.length - prefixLength;
11424
- listNumber++;
11425
- }
11426
- } else {
11427
- const indentMatch = lineText.match(/^(\s*)/);
11428
- const indent = indentMatch ? indentMatch[1] : "";
11429
- const newPrefix = `${listNumber}. `;
11430
- changes2.push({
11431
- from: line.from + indent.length,
11432
- insert: newPrefix
11433
- });
11434
- rangeDelta += newPrefix.length;
11435
- listNumber++;
11436
- }
11437
- }
11438
- return {
11439
- changes: changes2,
11440
- range: state.EditorSelection.range(range.from, range.to + rangeDelta)
11441
- };
11442
- });
11443
- dispatch(
11444
- state$1.update(changes, {
11445
- scrollIntoView: true,
11446
- annotations: state.Transaction.userEvent.of("input")
11447
- })
11448
- );
11449
- return true;
11450
- };
11451
11467
  function toEngineSelection(selection) {
11452
11468
  if (!selection) {
11453
11469
  return { start: 0, end: 0, affinity: "forward" };
@@ -11458,30 +11474,6 @@ function toEngineSelection(selection) {
11458
11474
  affinity: selection.affinity
11459
11475
  };
11460
11476
  }
11461
- const BOLD_MARKER = "**";
11462
- const ITALIC_MARKER = "*";
11463
- const STRIKETHROUGH_MARKER = "~~";
11464
- function mapCommandToEditCommand(command) {
11465
- if (command === toggleBold) {
11466
- return { type: "toggle-inline", marker: BOLD_MARKER };
11467
- }
11468
- if (command === toggleItalic) {
11469
- return { type: "toggle-inline", marker: ITALIC_MARKER };
11470
- }
11471
- if (command === toggleStrikethrough) {
11472
- return { type: "toggle-inline", marker: STRIKETHROUGH_MARKER };
11473
- }
11474
- if (command === toggleLink) {
11475
- return { type: "wrap-link", openPopover: true };
11476
- }
11477
- if (command === toggleBulletList) {
11478
- return { type: "toggle-bullet-list" };
11479
- }
11480
- if (command === toggleNumberedList) {
11481
- return { type: "toggle-numbered-list" };
11482
- }
11483
- return null;
11484
- }
11485
11477
  const CakeEditor = require$$0.forwardRef(
11486
11478
  function CakeEditor2(props, outerRef) {
11487
11479
  const containerRef = require$$0.useRef(null);
@@ -11600,15 +11592,11 @@ const CakeEditor = require$$0.forwardRef(
11600
11592
  var _a;
11601
11593
  (_a = engineRef.current) == null ? void 0 : _a.selectAll();
11602
11594
  },
11603
- executeCommand: (command) => {
11595
+ executeCommand: (command, options) => {
11604
11596
  if (!engineRef.current) {
11605
11597
  return false;
11606
11598
  }
11607
- const editCommand = mapCommandToEditCommand(command);
11608
- if (!editCommand) {
11609
- return false;
11610
- }
11611
- return engineRef.current.executeCommand(editCommand);
11599
+ return engineRef.current.executeCommand(command, options);
11612
11600
  },
11613
11601
  applyUpdate: (update) => {
11614
11602
  if (!engineRef.current) {