@jvs-milkdown/crepe 1.2.29 → 1.2.30

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.
Files changed (38) hide show
  1. package/lib/cjs/builder.js +2 -1
  2. package/lib/cjs/builder.js.map +1 -1
  3. package/lib/cjs/feature/toolbar/index.js +84 -62
  4. package/lib/cjs/feature/toolbar/index.js.map +1 -1
  5. package/lib/cjs/index.js +1121 -988
  6. package/lib/cjs/index.js.map +1 -1
  7. package/lib/esm/builder.js +2 -1
  8. package/lib/esm/builder.js.map +1 -1
  9. package/lib/esm/feature/toolbar/index.js +84 -62
  10. package/lib/esm/feature/toolbar/index.js.map +1 -1
  11. package/lib/esm/index.js +1143 -1010
  12. package/lib/esm/index.js.map +1 -1
  13. package/lib/theme/common/image-block.css +5 -1
  14. package/lib/theme/common/reset.css +1 -1
  15. package/lib/theme/common/table.css +5 -0
  16. package/lib/theme/common/toolbar.css +23 -0
  17. package/lib/tsconfig.tsbuildinfo +1 -1
  18. package/lib/types/feature/fixed-toolbar/component.d.ts +2 -2
  19. package/lib/types/feature/fixed-toolbar/component.d.ts.map +1 -1
  20. package/lib/types/feature/fixed-toolbar/index.d.ts +2 -0
  21. package/lib/types/feature/fixed-toolbar/index.d.ts.map +1 -1
  22. package/lib/types/feature/fixed-toolbar/outline-panel.d.ts.map +1 -1
  23. package/lib/types/feature/fixed-toolbar/view-menu-state.d.ts +3 -0
  24. package/lib/types/feature/fixed-toolbar/view-menu-state.d.ts.map +1 -1
  25. package/lib/types/feature/toolbar/component.d.ts +2 -2
  26. package/lib/types/feature/toolbar/component.d.ts.map +1 -1
  27. package/lib/types/feature/toolbar/index.d.ts.map +1 -1
  28. package/package.json +4 -4
  29. package/src/feature/fixed-toolbar/component.tsx +203 -110
  30. package/src/feature/fixed-toolbar/index.ts +30 -8
  31. package/src/feature/fixed-toolbar/outline-panel.tsx +1 -2
  32. package/src/feature/fixed-toolbar/view-menu-state.ts +2 -0
  33. package/src/feature/toolbar/component.tsx +57 -44
  34. package/src/feature/toolbar/index.ts +9 -13
  35. package/src/theme/common/image-block.css +6 -1
  36. package/src/theme/common/reset.css +1 -1
  37. package/src/theme/common/table.css +5 -0
  38. package/src/theme/common/toolbar.css +30 -0
package/lib/cjs/index.js CHANGED
@@ -4032,12 +4032,12 @@ var __accessCheck$5 = (obj, member, msg) => member.has(obj) || __typeError$5("Ca
4032
4032
  var __privateGet$5 = (obj, member, getter) => (__accessCheck$5(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
4033
4033
  var __privateAdd$5 = (obj, member, value) => member.has(obj) ? __typeError$5("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
4034
4034
  var __privateSet$5 = (obj, member, value, setter) => (__accessCheck$5(obj, member, "write to private field"), member.set(obj, value), value);
4035
- var _content$3, _provider$1, _state, _app$3, _ctx$1, _syncIcon;
4035
+ var _content$3, _provider$1, _state$2, _app$3, _ctx$1, _syncIcon;
4036
4036
  class BlockHandleView {
4037
4037
  constructor(ctx, config) {
4038
4038
  __privateAdd$5(this, _content$3);
4039
4039
  __privateAdd$5(this, _provider$1);
4040
- __privateAdd$5(this, _state, vue.reactive({ icon: textIcon }));
4040
+ __privateAdd$5(this, _state$2, vue.reactive({ icon: textIcon }));
4041
4041
  __privateAdd$5(this, _app$3);
4042
4042
  __privateAdd$5(this, _ctx$1);
4043
4043
  this.update = () => {
@@ -4062,17 +4062,17 @@ class BlockHandleView {
4062
4062
  __privateGet$5(this, _syncIcon).call(this, node);
4063
4063
  } else {
4064
4064
  __privateGet$5(this, _content$3).classList.remove("empty-block");
4065
- __privateGet$5(this, _state).icon = textIcon;
4065
+ __privateGet$5(this, _state$2).icon = textIcon;
4066
4066
  }
4067
4067
  };
4068
4068
  __privateAdd$5(this, _syncIcon, (node) => {
4069
4069
  var _a;
4070
4070
  if (node.type.name.includes("image")) {
4071
- __privateGet$5(this, _state).icon = imageIcon;
4071
+ __privateGet$5(this, _state$2).icon = imageIcon;
4072
4072
  return;
4073
4073
  }
4074
4074
  if (node.type.name.includes("attachment")) {
4075
- __privateGet$5(this, _state).icon = fileLinkIcon;
4075
+ __privateGet$5(this, _state$2).icon = fileLinkIcon;
4076
4076
  return;
4077
4077
  }
4078
4078
  switch (node.type.name) {
@@ -4087,40 +4087,40 @@ class BlockHandleView {
4087
4087
  h5Icon,
4088
4088
  h6Icon
4089
4089
  ];
4090
- __privateGet$5(this, _state).icon = (_a = headingIcons[level]) != null ? _a : textIcon;
4090
+ __privateGet$5(this, _state$2).icon = (_a = headingIcons[level]) != null ? _a : textIcon;
4091
4091
  break;
4092
4092
  }
4093
4093
  case "blockquote":
4094
- __privateGet$5(this, _state).icon = quoteIcon;
4094
+ __privateGet$5(this, _state$2).icon = quoteIcon;
4095
4095
  break;
4096
4096
  case "code_block":
4097
- __privateGet$5(this, _state).icon = codeIcon;
4097
+ __privateGet$5(this, _state$2).icon = codeIcon;
4098
4098
  break;
4099
4099
  case "math_display":
4100
4100
  case "math_inline":
4101
- __privateGet$5(this, _state).icon = functionsIcon;
4101
+ __privateGet$5(this, _state$2).icon = functionsIcon;
4102
4102
  break;
4103
4103
  case "hr":
4104
- __privateGet$5(this, _state).icon = dividerIcon;
4104
+ __privateGet$5(this, _state$2).icon = dividerIcon;
4105
4105
  break;
4106
4106
  case "table":
4107
- __privateGet$5(this, _state).icon = tableIcon;
4107
+ __privateGet$5(this, _state$2).icon = tableIcon;
4108
4108
  break;
4109
4109
  case "list_item":
4110
4110
  if (node.attrs.checked != null) {
4111
- __privateGet$5(this, _state).icon = todoListIcon;
4111
+ __privateGet$5(this, _state$2).icon = todoListIcon;
4112
4112
  } else {
4113
- __privateGet$5(this, _state).icon = bulletListIcon;
4113
+ __privateGet$5(this, _state$2).icon = bulletListIcon;
4114
4114
  }
4115
4115
  break;
4116
4116
  case "bullet_list":
4117
- __privateGet$5(this, _state).icon = bulletListIcon;
4117
+ __privateGet$5(this, _state$2).icon = bulletListIcon;
4118
4118
  break;
4119
4119
  case "ordered_list":
4120
- __privateGet$5(this, _state).icon = orderedListIcon;
4120
+ __privateGet$5(this, _state$2).icon = orderedListIcon;
4121
4121
  break;
4122
4122
  default:
4123
- __privateGet$5(this, _state).icon = textIcon;
4123
+ __privateGet$5(this, _state$2).icon = textIcon;
4124
4124
  }
4125
4125
  });
4126
4126
  this.destroy = () => {
@@ -4183,7 +4183,7 @@ class BlockHandleView {
4183
4183
  addIcon: (_a = config == null ? void 0 : config.handleAddIcon) != null ? _a : plusIcon,
4184
4184
  handleIcon: (_b = config == null ? void 0 : config.handleDragIcon) != null ? _b : menuIcon,
4185
4185
  ctx: __privateGet$5(this, _ctx$1),
4186
- state: __privateGet$5(this, _state)
4186
+ state: __privateGet$5(this, _state$2)
4187
4187
  });
4188
4188
  app.mount(content);
4189
4189
  __privateSet$5(this, _app$3, app);
@@ -4240,7 +4240,7 @@ class BlockHandleView {
4240
4240
  }
4241
4241
  _content$3 = new WeakMap();
4242
4242
  _provider$1 = new WeakMap();
4243
- _state = new WeakMap();
4243
+ _state$2 = new WeakMap();
4244
4244
  _app$3 = new WeakMap();
4245
4245
  _ctx$1 = new WeakMap();
4246
4246
  _syncIcon = new WeakMap();
@@ -4472,8 +4472,33 @@ const diffBlockFeature = (editor, config = {}) => {
4472
4472
  }).use(diffBlock.diffBlock);
4473
4473
  };
4474
4474
 
4475
- const remarkHighlightMarkPlugin = utils.$remark(
4476
- "remarkHighlightMark",
4475
+ const supportedFontsCache = /* @__PURE__ */ new Map();
4476
+ const isFontSupported = (fontFamily) => {
4477
+ if (!fontFamily) return true;
4478
+ const normalizedFont = fontFamily.replace(/['"]/g, "");
4479
+ if (supportedFontsCache.has(normalizedFont)) {
4480
+ return supportedFontsCache.get(normalizedFont);
4481
+ }
4482
+ if (typeof document === "undefined") return true;
4483
+ const canvas = document.createElement("canvas");
4484
+ const context = canvas.getContext("2d");
4485
+ if (!context) return true;
4486
+ const text = "abcdefghijklmnopqrstuvwxyz0123456789";
4487
+ const size = "72px";
4488
+ context.font = `${size} monospace`;
4489
+ const baseMono = context.measureText(text).width;
4490
+ context.font = `${size} sans-serif`;
4491
+ const baseSans = context.measureText(text).width;
4492
+ context.font = `${size} "${normalizedFont}", monospace`;
4493
+ const testMono = context.measureText(text).width;
4494
+ context.font = `${size} "${normalizedFont}", sans-serif`;
4495
+ const testSans = context.measureText(text).width;
4496
+ const supported = testMono !== baseMono || testSans !== baseSans;
4497
+ supportedFontsCache.set(normalizedFont, supported);
4498
+ return supported;
4499
+ };
4500
+ const remarkFontPlugin = utils.$remark(
4501
+ "remarkFont",
4477
4502
  () => function() {
4478
4503
  const data = this.data();
4479
4504
  function add(key, value) {
@@ -4485,31 +4510,46 @@ const remarkHighlightMarkPlugin = utils.$remark(
4485
4510
  }
4486
4511
  add("toMarkdownExtensions", {
4487
4512
  handlers: {
4488
- highlightMark: (node, _, state) => {
4489
- const idAttr = node.id ? ` data-id="${node.id}"` : "";
4490
- return `<mark${idAttr}>${state.containerPhrasing(node, state)}</mark>`;
4513
+ fontFamily: (node, _, state) => {
4514
+ return `<span style="font-family:${node.fontFamily}">${state.containerPhrasing(node, state)}</span>`;
4515
+ },
4516
+ fontSize: (node, _, state) => {
4517
+ return `<span style="font-size:${node.fontSize}">${state.containerPhrasing(node, state)}</span>`;
4491
4518
  }
4492
4519
  }
4493
4520
  });
4494
4521
  return (ast) => {
4495
4522
  unistUtilVisit.visit(ast, (node, index, parent) => {
4496
- if ((node == null ? void 0 : node.type) === "html" && node.value.startsWith("<mark") && parent && index != null) {
4497
- const idMatch = node.value.match(/data-id="([^"]+)"/);
4498
- const id = idMatch ? idMatch[1] : null;
4523
+ if ((node == null ? void 0 : node.type) === "html" && node.value.startsWith("<span") && parent && index != null) {
4524
+ const hasFontFamily = node.value.match(/font-family:\s*([^"';>]+)/);
4525
+ const hasFontSize = node.value.match(/font-size:\s*([^"';>]+)/);
4526
+ if (!hasFontFamily && !hasFontSize) return;
4527
+ let fontFamily = null;
4528
+ let fontSize = null;
4529
+ let markType = null;
4530
+ if (hasFontFamily) {
4531
+ fontFamily = hasFontFamily[1].trim();
4532
+ markType = "fontFamily";
4533
+ } else if (hasFontSize) {
4534
+ fontSize = hasFontSize[1].trim();
4535
+ markType = "fontSize";
4536
+ }
4499
4537
  const endIndex = parent.children.findIndex(
4500
- (n, i) => i > index && n.type === "html" && n.value === "</mark>"
4538
+ (n, i) => i > index && n.type === "html" && n.value === "</span>"
4501
4539
  );
4502
- if (endIndex !== -1) {
4540
+ if (endIndex !== -1 && markType && (fontFamily || fontSize)) {
4503
4541
  const children = parent.children.splice(
4504
4542
  index,
4505
4543
  endIndex - index + 1
4506
4544
  );
4507
4545
  const content = children.slice(1, -1);
4508
- parent.children.splice(index, 0, {
4509
- type: "highlightMark",
4510
- id,
4546
+ const payload = {
4547
+ type: markType,
4511
4548
  children: content
4512
- });
4549
+ };
4550
+ if (fontFamily) payload.fontFamily = fontFamily;
4551
+ if (fontSize) payload.fontSize = fontSize;
4552
+ parent.children.splice(index, 0, payload);
4513
4553
  return index + 1;
4514
4554
  }
4515
4555
  }
@@ -4518,450 +4558,700 @@ const remarkHighlightMarkPlugin = utils.$remark(
4518
4558
  };
4519
4559
  }
4520
4560
  );
4521
- const highlightMarkAttr = utils.$markAttr("highlightMark");
4522
- const highlightMarkSchema = utils.$markSchema("highlightMark", (ctx) => ({
4561
+ const fontFamilyAttr = utils.$markAttr("fontFamily");
4562
+ const fontFamilySchema = utils.$markSchema("fontFamily", (_ctx) => ({
4523
4563
  inclusive: true,
4524
4564
  attrs: {
4525
- id: { default: null }
4565
+ fontFamily: { default: null }
4526
4566
  },
4527
4567
  parseDOM: [
4528
4568
  {
4529
- tag: "mark",
4530
- getAttrs: (dom) => ({
4531
- id: dom.getAttribute("data-id") || null
4532
- })
4569
+ tag: 'span[style*="font-family"]',
4570
+ getAttrs: (dom) => {
4571
+ if (!(dom instanceof HTMLElement)) return false;
4572
+ const fontFamily = dom.style.fontFamily || null;
4573
+ if (!isFontSupported(fontFamily)) return false;
4574
+ return { fontFamily };
4575
+ }
4533
4576
  }
4534
4577
  ],
4535
4578
  toDOM: (mark) => {
4536
- const attrs = { ...ctx.get(highlightMarkAttr.key)(mark) };
4537
- if (mark.attrs.id) {
4538
- attrs["data-id"] = mark.attrs.id;
4579
+ return ["span", { style: `font-family: ${mark.attrs.fontFamily}` }, 0];
4580
+ },
4581
+ parseMarkdown: {
4582
+ match: (node) => node.type === "fontFamily",
4583
+ runner: (state, node, markType) => {
4584
+ state.openMark(markType, { fontFamily: node.fontFamily });
4585
+ state.next(node.children);
4586
+ state.closeMark(markType);
4539
4587
  }
4540
- return ["mark", attrs, 0];
4588
+ },
4589
+ toMarkdown: {
4590
+ match: (mark) => mark.type.name === "fontFamily",
4591
+ runner: (state, mark) => {
4592
+ state.withMark(mark, "fontFamily", void 0, {
4593
+ fontFamily: mark.attrs.fontFamily
4594
+ });
4595
+ }
4596
+ }
4597
+ }));
4598
+ const fontSizeAttr = utils.$markAttr("fontSize");
4599
+ const fontSizeSchema = utils.$markSchema("fontSize", (_ctx) => ({
4600
+ inclusive: true,
4601
+ attrs: {
4602
+ fontSize: { default: null }
4603
+ },
4604
+ parseDOM: [
4605
+ {
4606
+ tag: 'span[style*="font-size"]',
4607
+ getAttrs: (dom) => {
4608
+ if (!(dom instanceof HTMLElement)) return false;
4609
+ return { fontSize: dom.style.fontSize || null };
4610
+ }
4611
+ }
4612
+ ],
4613
+ toDOM: (mark) => {
4614
+ return ["span", { style: `font-size: ${mark.attrs.fontSize}` }, 0];
4541
4615
  },
4542
4616
  parseMarkdown: {
4543
- match: (node) => node.type === "highlightMark",
4617
+ match: (node) => node.type === "fontSize",
4544
4618
  runner: (state, node, markType) => {
4545
- state.openMark(markType, { id: node.id });
4619
+ state.openMark(markType, { fontSize: node.fontSize });
4546
4620
  state.next(node.children);
4547
4621
  state.closeMark(markType);
4548
4622
  }
4549
4623
  },
4550
4624
  toMarkdown: {
4551
- match: (mark) => mark.type.name === "highlightMark",
4625
+ match: (mark) => mark.type.name === "fontSize",
4552
4626
  runner: (state, mark) => {
4553
- state.withMark(mark, "highlightMark", void 0, { id: mark.attrs.id });
4627
+ state.withMark(mark, "fontSize", void 0, {
4628
+ fontSize: mark.attrs.fontSize
4629
+ });
4554
4630
  }
4555
4631
  }
4556
4632
  }));
4557
- const toggleHighlightMarkCommand = utils.$command(
4558
- "ToggleHighlightMark",
4559
- (ctx) => () => (state$1, dispatch) => {
4560
- const markType = highlightMarkSchema.type(ctx);
4561
- const { $cursor, ranges, $from, $to } = state$1.selection;
4562
- if (dispatch) {
4563
- let tr = state$1.tr;
4564
- const newId = Math.random().toString(36).substring(2, 9);
4565
- const creatMark = () => markType.create({ id: newId });
4566
- if ($cursor) {
4567
- const isEmptyBlock = $cursor.parent.content.size === 0;
4568
- if (isEmptyBlock) {
4569
- const marks = state$1.storedMarks || $cursor.marks();
4633
+ const toggleFontFamilyCommand = utils.$command(
4634
+ "ToggleFontFamily",
4635
+ (ctx) => (fontFamily) => {
4636
+ return (state, dispatch) => {
4637
+ const markType = fontFamilySchema.type(ctx);
4638
+ const { $cursor, ranges } = state.selection;
4639
+ if (dispatch) {
4640
+ let tr = state.tr;
4641
+ if ($cursor) {
4642
+ const marks = state.storedMarks || $cursor.marks();
4570
4643
  const currentMark = markType.isInSet(marks);
4571
- if (currentMark) {
4644
+ if (currentMark && currentMark.attrs.fontFamily === fontFamily) {
4572
4645
  tr = tr.removeStoredMark(markType);
4573
4646
  } else {
4574
- const zwsp = "\u200B";
4575
- tr = tr.insertText(zwsp, $cursor.pos);
4576
- tr = tr.addMark($cursor.pos, $cursor.pos + 1, creatMark());
4577
- tr = tr.setSelection(state.TextSelection.create(tr.doc, $cursor.pos));
4578
- }
4579
- } else {
4580
- const start = $cursor.start();
4581
- const end = $cursor.end();
4582
- const hasMark = state$1.doc.rangeHasMark(start, end, markType);
4583
- if (hasMark) {
4584
- tr = tr.removeMark(start, end, markType);
4585
- if ($cursor.parent.content.size === 1 && $cursor.parent.textContent === "\u200B") {
4586
- tr = tr.delete(start, end);
4587
- }
4588
- } else {
4589
- tr = tr.addMark(start, end, creatMark());
4590
- }
4591
- }
4592
- } else {
4593
- let hasMark = false;
4594
- for (const range of ranges) {
4595
- const { $from: $from2, $to: $to2 } = range;
4596
- if (state$1.doc.rangeHasMark($from2.pos, $to2.pos, markType)) {
4597
- hasMark = true;
4598
- break;
4599
- }
4600
- }
4601
- if (hasMark) {
4602
- for (const range of ranges) {
4603
- const { $from: $from2, $to: $to2 } = range;
4604
- tr = tr.removeMark($from2.pos, $to2.pos, markType);
4647
+ tr = tr.removeStoredMark(markType);
4648
+ if (fontFamily)
4649
+ tr = tr.addStoredMark(markType.create({ fontFamily }));
4605
4650
  }
4606
4651
  } else {
4652
+ let hasSameFontFamily = false;
4607
4653
  for (const range of ranges) {
4608
- const { $from: $from2, $to: $to2 } = range;
4609
- tr = tr.removeMark($from2.pos, $to2.pos, markType);
4610
- }
4611
- let canFlatten = true;
4612
- let blockCount = 0;
4613
- state$1.doc.nodesBetween($from.pos, $to.pos, (node) => {
4614
- if (node.isTextblock) {
4615
- blockCount++;
4616
- }
4617
- if (node.isBlock) {
4618
- const name = node.type.name;
4619
- if (name !== "paragraph" && name !== "doc" && name !== "blockquote") {
4620
- canFlatten = false;
4621
- }
4622
- }
4623
- });
4624
- if (canFlatten && blockCount > 1) {
4625
- const nodes = [];
4626
- state$1.doc.nodesBetween($from.pos, $to.pos, (node) => {
4627
- if (node.isTextblock) {
4628
- const hardbreakType = state$1.schema.nodes.hardbreak;
4629
- if (hardbreakType && nodes.length > 0) {
4630
- nodes.push(hardbreakType.create());
4654
+ const { $from, $to } = range;
4655
+ state.doc.nodesBetween($from.pos, $to.pos, (node) => {
4656
+ if (node.isText) {
4657
+ const mark = markType.isInSet(node.marks);
4658
+ if (mark && mark.attrs.fontFamily === fontFamily) {
4659
+ hasSameFontFamily = true;
4631
4660
  }
4632
- node.forEach((child) => nodes.push(child));
4633
4661
  }
4634
4662
  });
4635
- const paragraphType = state$1.schema.nodes.paragraph;
4636
- const range = $from.blockRange($to);
4637
- if (paragraphType && range) {
4638
- const p = paragraphType.create({}, nodes);
4639
- tr = tr.replaceWith(range.start, range.end, p);
4663
+ }
4664
+ for (const range of ranges) {
4665
+ const { $from, $to } = range;
4666
+ tr = tr.removeMark($from.pos, $to.pos, markType);
4667
+ if (!hasSameFontFamily && fontFamily) {
4640
4668
  tr = tr.addMark(
4641
- range.start,
4642
- range.start + p.nodeSize,
4643
- creatMark()
4669
+ $from.pos,
4670
+ $to.pos,
4671
+ markType.create({ fontFamily })
4644
4672
  );
4645
4673
  }
4646
- } else {
4647
- for (const range of ranges) {
4648
- const { $from: $from2, $to: $to2 } = range;
4649
- tr = tr.addMark($from2.pos, $to2.pos, creatMark());
4650
- }
4651
4674
  }
4652
4675
  }
4676
+ dispatch(tr.scrollIntoView());
4653
4677
  }
4654
- dispatch(tr.scrollIntoView());
4655
- }
4656
- return true;
4678
+ return true;
4679
+ };
4657
4680
  }
4658
4681
  );
4659
- const highlightMarkKeymap = utils.$useKeymap("highlightMarkKeymap", {
4660
- ToggleHighlightMark: {
4661
- shortcuts: "Mod-Shift-h",
4662
- command: (ctx) => {
4663
- const commands = ctx.get(core.commandsCtx);
4664
- return () => commands.call(toggleHighlightMarkCommand.key);
4665
- }
4666
- },
4667
- HighlightMarkEnter: {
4668
- shortcuts: "Enter",
4669
- command: (ctx) => {
4670
- return (state, dispatch) => {
4671
- const markType = highlightMarkSchema.type(ctx);
4672
- const { $from, empty } = state.selection;
4673
- if (!empty) return false;
4674
- const marks = state.storedMarks || $from.marks();
4675
- if (!markType.isInSet(marks)) return false;
4676
- if (dispatch) {
4677
- const hardbreak = state.schema.nodes.hardbreak;
4678
- if (hardbreak) {
4679
- let tr = state.tr.replaceSelectionWith(hardbreak.create(), true);
4680
- dispatch(tr.scrollIntoView());
4681
- }
4682
- }
4683
- return true;
4684
- };
4685
- }
4686
- },
4687
- HighlightMarkArrowDown: {
4688
- shortcuts: "ArrowDown",
4689
- command: (ctx) => {
4690
- return (state$1, dispatch, view) => {
4691
- if (!view) return false;
4692
- const markType = highlightMarkSchema.type(ctx);
4693
- const { selection } = state$1;
4694
- const { $from, empty } = selection;
4695
- if (!empty) return false;
4696
- const isTextblock = $from.parent.isTextblock;
4697
- if (!isTextblock) return false;
4698
- let hasNodeAfter = false;
4699
- state$1.doc.nodesBetween(
4700
- $from.after(),
4701
- state$1.doc.content.size,
4702
- (node) => {
4703
- if (node.isTextblock) hasNodeAfter = true;
4704
- }
4705
- );
4706
- if (hasNodeAfter) return false;
4707
- let hasHighlight = false;
4708
- if ($from.parent.content.size === 0) {
4709
- const marks = state$1.storedMarks || $from.marks();
4710
- if (markType.isInSet(marks)) {
4711
- hasHighlight = true;
4712
- }
4713
- } else if ($from.parent.content.size === 1 && $from.parent.textContent === "\u200B") {
4714
- const child = $from.parent.child(0);
4715
- if (child.marks.some((m) => m.type === markType)) {
4716
- hasHighlight = true;
4682
+ const toggleFontSizeCommand = utils.$command(
4683
+ "ToggleFontSize",
4684
+ (ctx) => (fontSize) => {
4685
+ return (state, dispatch) => {
4686
+ const markType = fontSizeSchema.type(ctx);
4687
+ const { $cursor, ranges } = state.selection;
4688
+ if (dispatch) {
4689
+ let tr = state.tr;
4690
+ if ($cursor) {
4691
+ const marks = state.storedMarks || $cursor.marks();
4692
+ const currentMark = markType.isInSet(marks);
4693
+ if (currentMark && currentMark.attrs.fontSize === fontSize) {
4694
+ tr = tr.removeStoredMark(markType);
4695
+ } else {
4696
+ tr = tr.removeStoredMark(markType);
4697
+ if (fontSize) tr = tr.addStoredMark(markType.create({ fontSize }));
4717
4698
  }
4718
4699
  } else {
4719
- $from.parent.descendants((node) => {
4720
- if (node.isText && node.marks.some((m) => m.type === markType)) {
4721
- hasHighlight = true;
4722
- }
4723
- });
4724
- }
4725
- if (!hasHighlight) return false;
4726
- if (!view.endOfTextblock("down")) return false;
4727
- const paragraphType = state$1.schema.nodes.paragraph;
4728
- if (!paragraphType) return false;
4729
- if (dispatch) {
4730
- const p = paragraphType.create();
4731
- const insertPos = state$1.doc.content.size;
4732
- let tr = state$1.tr.insert(insertPos, p);
4733
- const newPos = insertPos + 1;
4734
- tr = tr.setSelection(state.TextSelection.create(tr.doc, newPos));
4735
- tr = tr.removeStoredMark(markType);
4736
- dispatch(tr.scrollIntoView());
4737
- }
4738
- return true;
4739
- };
4740
- }
4741
- },
4742
- HighlightMarkBackspace: {
4743
- shortcuts: "Backspace",
4744
- command: (ctx) => {
4745
- return (state, dispatch) => {
4746
- const markType = highlightMarkSchema.type(ctx);
4747
- const { selection } = state;
4748
- const { $from, empty } = selection;
4749
- if (!empty) return false;
4750
- const isTextblock = $from.parent.isTextblock;
4751
- if (!isTextblock) return false;
4752
- if ($from.parentOffset === 0) {
4753
- const prevBlockPos = $from.before() - 1;
4754
- if (prevBlockPos > 0) {
4755
- const $prev = state.doc.resolve(prevBlockPos);
4756
- const prevBlock = $prev.parent;
4757
- if (prevBlock && prevBlock.isTextblock) {
4758
- let prevHasHighlight = false;
4759
- prevBlock.descendants((node) => {
4760
- if (node.marks.some((m) => m.type === markType)) {
4761
- prevHasHighlight = true;
4762
- }
4763
- });
4764
- if (prevHasHighlight) {
4765
- if (dispatch) {
4766
- let tr = state.tr;
4767
- tr = tr.delete($prev.start() - 1, $prev.end() + 1);
4768
- dispatch(tr.scrollIntoView());
4700
+ let hasSameFontSize = false;
4701
+ for (const range of ranges) {
4702
+ const { $from, $to } = range;
4703
+ state.doc.nodesBetween($from.pos, $to.pos, (node) => {
4704
+ if (node.isText) {
4705
+ const mark = markType.isInSet(node.marks);
4706
+ if (mark && mark.attrs.fontSize === fontSize) {
4707
+ hasSameFontSize = true;
4769
4708
  }
4770
- return true;
4771
4709
  }
4710
+ });
4711
+ }
4712
+ for (const range of ranges) {
4713
+ const { $from, $to } = range;
4714
+ tr = tr.removeMark($from.pos, $to.pos, markType);
4715
+ if (!hasSameFontSize && fontSize) {
4716
+ tr = tr.addMark(
4717
+ $from.pos,
4718
+ $to.pos,
4719
+ markType.create({ fontSize })
4720
+ );
4772
4721
  }
4773
4722
  }
4774
4723
  }
4775
- let hasHighlight = false;
4776
- let isPlaceholder = false;
4777
- if ($from.parent.content.size === 0) {
4778
- const marks = state.storedMarks || $from.marks();
4779
- if (markType.isInSet(marks)) {
4780
- hasHighlight = true;
4781
- }
4782
- } else if ($from.parent.content.size === 1 && $from.parent.textContent === "\u200B") {
4783
- const child = $from.parent.child(0);
4784
- if (child.marks.some((m) => m.type === markType)) {
4785
- hasHighlight = true;
4786
- isPlaceholder = true;
4787
- }
4724
+ dispatch(tr.scrollIntoView());
4725
+ }
4726
+ return true;
4727
+ };
4728
+ }
4729
+ );
4730
+ function stripFontFamilyFromExternalHTML(html) {
4731
+ if (html.includes("data-pm-slice")) return html;
4732
+ try {
4733
+ const template = document.createElement("template");
4734
+ template.innerHTML = html;
4735
+ const styledElements = template.content.querySelectorAll(
4736
+ '[style*="font-family"]'
4737
+ );
4738
+ styledElements.forEach((el) => {
4739
+ if (el instanceof HTMLElement) {
4740
+ el.style.removeProperty("font-family");
4741
+ }
4742
+ });
4743
+ const fontElements = template.content.querySelectorAll("font[face]");
4744
+ fontElements.forEach((el) => {
4745
+ if (el instanceof HTMLElement) {
4746
+ el.removeAttribute("face");
4747
+ }
4748
+ });
4749
+ html = template.innerHTML;
4750
+ template.remove();
4751
+ } catch (e) {
4752
+ }
4753
+ return html;
4754
+ }
4755
+ const fontPlugins = [
4756
+ fontFamilyAttr,
4757
+ fontFamilySchema,
4758
+ toggleFontFamilyCommand,
4759
+ fontSizeAttr,
4760
+ fontSizeSchema,
4761
+ toggleFontSizeCommand,
4762
+ remarkFontPlugin
4763
+ ];
4764
+
4765
+ const remarkHighlightMarkPlugin = utils.$remark(
4766
+ "remarkHighlightMark",
4767
+ () => function() {
4768
+ const data = this.data();
4769
+ function add(key, value) {
4770
+ if (Array.isArray(data[key])) {
4771
+ data[key].push(value);
4772
+ } else {
4773
+ data[key] = [value];
4774
+ }
4775
+ }
4776
+ add("toMarkdownExtensions", {
4777
+ handlers: {
4778
+ highlightMark: (node, _, state) => {
4779
+ const idAttr = node.id ? ` data-id="${node.id}"` : "";
4780
+ return `<mark${idAttr}>${state.containerPhrasing(node, state)}</mark>`;
4788
4781
  }
4789
- if (hasHighlight) {
4790
- if (dispatch) {
4791
- let tr = state.tr;
4792
- if (isPlaceholder) {
4793
- const start = $from.start();
4794
- const end = $from.end();
4795
- tr = tr.delete(start, end);
4796
- }
4797
- tr = tr.removeStoredMark(markType);
4798
- dispatch(tr.scrollIntoView());
4782
+ }
4783
+ });
4784
+ return (ast) => {
4785
+ unistUtilVisit.visit(ast, (node, index, parent) => {
4786
+ if ((node == null ? void 0 : node.type) === "html" && node.value.startsWith("<mark") && parent && index != null) {
4787
+ const idMatch = node.value.match(/data-id="([^"]+)"/);
4788
+ const id = idMatch ? idMatch[1] : null;
4789
+ const endIndex = parent.children.findIndex(
4790
+ (n, i) => i > index && n.type === "html" && n.value === "</mark>"
4791
+ );
4792
+ if (endIndex !== -1) {
4793
+ const children = parent.children.splice(
4794
+ index,
4795
+ endIndex - index + 1
4796
+ );
4797
+ const content = children.slice(1, -1);
4798
+ parent.children.splice(index, 0, {
4799
+ type: "highlightMark",
4800
+ id,
4801
+ children: content
4802
+ });
4803
+ return index + 1;
4799
4804
  }
4800
- return true;
4801
4805
  }
4802
- return false;
4803
- };
4804
- }
4805
- }
4806
- });
4807
- const highlightEmptyBlockPlugin = utils.$prose((ctx) => {
4808
- return new state.Plugin({
4809
- key: new state.PluginKey("highlightEmptyBlock"),
4810
- props: {
4811
- decorations(state) {
4812
- const markType = highlightMarkSchema.type(ctx);
4813
- const decorations = [];
4814
- state.doc.descendants((node, pos) => {
4815
- if (node.isTextblock) {
4816
- if (node.content.size === 1 && node.textContent === "\u200B") {
4817
- const child = node.child(0);
4818
- if (child.marks.some((m) => m.type === markType)) {
4819
- decorations.push(
4820
- view$1.Decoration.node(pos, pos + node.nodeSize, {
4821
- class: "crepe-placeholder crepe-highlight-empty",
4822
- "data-placeholder": "\u8BF7\u8F93\u5165\u5185\u5BB9"
4823
- })
4824
- );
4825
- }
4826
- }
4827
- }
4828
- });
4829
- const { selection } = state;
4830
- const { $from, empty } = selection;
4831
- if (empty && $from.parent.isTextblock && $from.parent.content.size === 0) {
4832
- const marks = state.storedMarks || $from.marks();
4833
- if (markType.isInSet(marks)) {
4834
- const start = $from.start() - 1;
4835
- decorations.push(
4836
- view$1.Decoration.node(start, start + $from.parent.nodeSize, {
4837
- class: "crepe-placeholder crepe-highlight-empty",
4838
- "data-placeholder": "\u8BF7\u8F93\u5165\u5185\u5BB9"
4839
- })
4840
- );
4841
- }
4842
- }
4843
- return view$1.DecorationSet.create(state.doc, decorations);
4844
- }
4845
- },
4846
- appendTransaction(transactions, _oldState, newState) {
4847
- const markType = highlightMarkSchema.type(ctx);
4848
- if (!transactions.some((t) => t.docChanged)) return null;
4849
- const { empty, $from } = newState.selection;
4850
- if (!empty || !$from.parent.isTextblock) return null;
4851
- if ($from.parent.content.size !== 0) return null;
4852
- const marks = newState.storedMarks || $from.marks();
4853
- if (!markType.isInSet(marks)) return null;
4854
- const id = Math.random().toString(36).substring(2, 9);
4855
- const mark = markType.create({ id });
4856
- return newState.tr.insert($from.pos, newState.schema.text("\u200B", [mark]));
4857
- }
4858
- });
4859
- });
4860
- const highlightMark = [
4861
- highlightMarkAttr,
4862
- highlightMarkSchema,
4863
- toggleHighlightMarkCommand,
4864
- highlightMarkKeymap,
4865
- remarkHighlightMarkPlugin,
4866
- highlightEmptyBlockPlugin
4867
- ];
4868
-
4869
- const remarkUnderlinePlugin = utils.$remark(
4870
- "remarkUnderline",
4871
- () => function() {
4872
- const data = this.data();
4873
- function add(key, value) {
4874
- if (Array.isArray(data[key])) {
4875
- data[key].push(value);
4876
- } else {
4877
- data[key] = [value];
4878
- }
4879
- }
4880
- add("toMarkdownExtensions", {
4881
- handlers: {
4882
- underline: (node, _, state) => {
4883
- return `<u>${state.containerPhrasing(node, state)}</u>`;
4884
- }
4885
- }
4886
- });
4887
- return (ast) => {
4888
- unistUtilVisit.visit(ast, (node, index, parent) => {
4889
- if ((node == null ? void 0 : node.type) === "html" && node.value === "<u>" && parent && index != null) {
4890
- const endIndex = parent.children.findIndex(
4891
- (n, i) => i > index && n.type === "html" && n.value === "</u>"
4892
- );
4893
- if (endIndex !== -1) {
4894
- const children = parent.children.splice(
4895
- index,
4896
- endIndex - index + 1
4897
- );
4898
- const content = children.slice(1, -1);
4899
- parent.children.splice(index, 0, {
4900
- type: "underline",
4901
- children: content
4902
- });
4903
- return index + 1;
4904
- }
4905
- }
4906
- return;
4907
- });
4908
- };
4806
+ return;
4807
+ });
4808
+ };
4909
4809
  }
4910
4810
  );
4911
- const underlineAttr = utils.$markAttr("underline");
4912
- const underlineSchema = utils.$markSchema("underline", (ctx) => ({
4811
+ const highlightMarkAttr = utils.$markAttr("highlightMark");
4812
+ const highlightMarkSchema = utils.$markSchema("highlightMark", (ctx) => ({
4913
4813
  inclusive: true,
4814
+ attrs: {
4815
+ id: { default: null }
4816
+ },
4914
4817
  parseDOM: [
4915
- { tag: "u" },
4916
4818
  {
4917
- style: "text-decoration",
4918
- getAttrs: (value) => value === "underline" ? null : false
4819
+ tag: "mark",
4820
+ getAttrs: (dom) => ({
4821
+ id: dom.getAttribute("data-id") || null
4822
+ })
4919
4823
  }
4920
4824
  ],
4921
- toDOM: (mark) => ["u", ctx.get(underlineAttr.key)(mark), 0],
4825
+ toDOM: (mark) => {
4826
+ const attrs = { ...ctx.get(highlightMarkAttr.key)(mark) };
4827
+ if (mark.attrs.id) {
4828
+ attrs["data-id"] = mark.attrs.id;
4829
+ }
4830
+ return ["mark", attrs, 0];
4831
+ },
4922
4832
  parseMarkdown: {
4923
- match: (node) => node.type === "underline",
4833
+ match: (node) => node.type === "highlightMark",
4924
4834
  runner: (state, node, markType) => {
4925
- state.openMark(markType);
4835
+ state.openMark(markType, { id: node.id });
4926
4836
  state.next(node.children);
4927
4837
  state.closeMark(markType);
4928
4838
  }
4929
4839
  },
4930
4840
  toMarkdown: {
4931
- match: (mark) => mark.type.name === "underline",
4841
+ match: (mark) => mark.type.name === "highlightMark",
4932
4842
  runner: (state, mark) => {
4933
- state.withMark(mark, "underline");
4843
+ state.withMark(mark, "highlightMark", void 0, { id: mark.attrs.id });
4934
4844
  }
4935
4845
  }
4936
4846
  }));
4937
- const toggleUnderlineCommand = utils.$command(
4938
- "ToggleUnderline",
4939
- (ctx) => () => commands.toggleMark(underlineSchema.type(ctx))
4847
+ const toggleHighlightMarkCommand = utils.$command(
4848
+ "ToggleHighlightMark",
4849
+ (ctx) => () => (state$1, dispatch) => {
4850
+ const markType = highlightMarkSchema.type(ctx);
4851
+ const { $cursor, ranges, $from, $to } = state$1.selection;
4852
+ if (dispatch) {
4853
+ let tr = state$1.tr;
4854
+ const newId = Math.random().toString(36).substring(2, 9);
4855
+ const creatMark = () => markType.create({ id: newId });
4856
+ if ($cursor) {
4857
+ const isEmptyBlock = $cursor.parent.content.size === 0;
4858
+ if (isEmptyBlock) {
4859
+ const marks = state$1.storedMarks || $cursor.marks();
4860
+ const currentMark = markType.isInSet(marks);
4861
+ if (currentMark) {
4862
+ tr = tr.removeStoredMark(markType);
4863
+ } else {
4864
+ const zwsp = "\u200B";
4865
+ tr = tr.insertText(zwsp, $cursor.pos);
4866
+ tr = tr.addMark($cursor.pos, $cursor.pos + 1, creatMark());
4867
+ tr = tr.setSelection(state.TextSelection.create(tr.doc, $cursor.pos));
4868
+ }
4869
+ } else {
4870
+ const start = $cursor.start();
4871
+ const end = $cursor.end();
4872
+ const hasMark = state$1.doc.rangeHasMark(start, end, markType);
4873
+ if (hasMark) {
4874
+ tr = tr.removeMark(start, end, markType);
4875
+ if ($cursor.parent.content.size === 1 && $cursor.parent.textContent === "\u200B") {
4876
+ tr = tr.delete(start, end);
4877
+ }
4878
+ } else {
4879
+ tr = tr.addMark(start, end, creatMark());
4880
+ }
4881
+ }
4882
+ } else {
4883
+ let hasMark = false;
4884
+ for (const range of ranges) {
4885
+ const { $from: $from2, $to: $to2 } = range;
4886
+ if (state$1.doc.rangeHasMark($from2.pos, $to2.pos, markType)) {
4887
+ hasMark = true;
4888
+ break;
4889
+ }
4890
+ }
4891
+ if (hasMark) {
4892
+ for (const range of ranges) {
4893
+ const { $from: $from2, $to: $to2 } = range;
4894
+ tr = tr.removeMark($from2.pos, $to2.pos, markType);
4895
+ }
4896
+ } else {
4897
+ for (const range of ranges) {
4898
+ const { $from: $from2, $to: $to2 } = range;
4899
+ tr = tr.removeMark($from2.pos, $to2.pos, markType);
4900
+ }
4901
+ let canFlatten = true;
4902
+ let blockCount = 0;
4903
+ state$1.doc.nodesBetween($from.pos, $to.pos, (node) => {
4904
+ if (node.isTextblock) {
4905
+ blockCount++;
4906
+ }
4907
+ if (node.isBlock) {
4908
+ const name = node.type.name;
4909
+ if (name !== "paragraph" && name !== "doc" && name !== "blockquote") {
4910
+ canFlatten = false;
4911
+ }
4912
+ }
4913
+ });
4914
+ if (canFlatten && blockCount > 1) {
4915
+ const nodes = [];
4916
+ state$1.doc.nodesBetween($from.pos, $to.pos, (node) => {
4917
+ if (node.isTextblock) {
4918
+ const hardbreakType = state$1.schema.nodes.hardbreak;
4919
+ if (hardbreakType && nodes.length > 0) {
4920
+ nodes.push(hardbreakType.create());
4921
+ }
4922
+ node.forEach((child) => nodes.push(child));
4923
+ }
4924
+ });
4925
+ const paragraphType = state$1.schema.nodes.paragraph;
4926
+ const range = $from.blockRange($to);
4927
+ if (paragraphType && range) {
4928
+ const p = paragraphType.create({}, nodes);
4929
+ tr = tr.replaceWith(range.start, range.end, p);
4930
+ tr = tr.addMark(
4931
+ range.start,
4932
+ range.start + p.nodeSize,
4933
+ creatMark()
4934
+ );
4935
+ }
4936
+ } else {
4937
+ for (const range of ranges) {
4938
+ const { $from: $from2, $to: $to2 } = range;
4939
+ tr = tr.addMark($from2.pos, $to2.pos, creatMark());
4940
+ }
4941
+ }
4942
+ }
4943
+ }
4944
+ dispatch(tr.scrollIntoView());
4945
+ }
4946
+ return true;
4947
+ }
4940
4948
  );
4941
- const underlineKeymap = utils.$useKeymap("underlineKeymap", {
4942
- ToggleUnderline: {
4943
- shortcuts: "Mod-u",
4949
+ const highlightMarkKeymap = utils.$useKeymap("highlightMarkKeymap", {
4950
+ ToggleHighlightMark: {
4951
+ shortcuts: "Mod-Shift-h",
4944
4952
  command: (ctx) => {
4945
4953
  const commands = ctx.get(core.commandsCtx);
4946
- return () => commands.call(toggleUnderlineCommand.key);
4954
+ return () => commands.call(toggleHighlightMarkCommand.key);
4947
4955
  }
4948
- }
4949
- });
4950
- const underline = [
4951
- underlineAttr,
4952
- underlineSchema,
4953
- toggleUnderlineCommand,
4954
- underlineKeymap,
4955
- remarkUnderlinePlugin
4956
- ];
4957
-
4958
- const listeners = /* @__PURE__ */ new Set();
4959
- let _popupCount = 0;
4960
- function getIsAnyPopupOpen() {
4961
- return _popupCount > 0;
4962
- }
4963
- function addPopupChangeListener(fn) {
4964
- listeners.add(fn);
4956
+ },
4957
+ HighlightMarkEnter: {
4958
+ shortcuts: "Enter",
4959
+ command: (ctx) => {
4960
+ return (state, dispatch) => {
4961
+ const markType = highlightMarkSchema.type(ctx);
4962
+ const { $from, empty } = state.selection;
4963
+ if (!empty) return false;
4964
+ const marks = state.storedMarks || $from.marks();
4965
+ if (!markType.isInSet(marks)) return false;
4966
+ if (dispatch) {
4967
+ const hardbreak = state.schema.nodes.hardbreak;
4968
+ if (hardbreak) {
4969
+ let tr = state.tr.replaceSelectionWith(hardbreak.create(), true);
4970
+ dispatch(tr.scrollIntoView());
4971
+ }
4972
+ }
4973
+ return true;
4974
+ };
4975
+ }
4976
+ },
4977
+ HighlightMarkArrowDown: {
4978
+ shortcuts: "ArrowDown",
4979
+ command: (ctx) => {
4980
+ return (state$1, dispatch, view) => {
4981
+ if (!view) return false;
4982
+ const markType = highlightMarkSchema.type(ctx);
4983
+ const { selection } = state$1;
4984
+ const { $from, empty } = selection;
4985
+ if (!empty) return false;
4986
+ const isTextblock = $from.parent.isTextblock;
4987
+ if (!isTextblock) return false;
4988
+ let hasNodeAfter = false;
4989
+ state$1.doc.nodesBetween(
4990
+ $from.after(),
4991
+ state$1.doc.content.size,
4992
+ (node) => {
4993
+ if (node.isTextblock) hasNodeAfter = true;
4994
+ }
4995
+ );
4996
+ if (hasNodeAfter) return false;
4997
+ let hasHighlight = false;
4998
+ if ($from.parent.content.size === 0) {
4999
+ const marks = state$1.storedMarks || $from.marks();
5000
+ if (markType.isInSet(marks)) {
5001
+ hasHighlight = true;
5002
+ }
5003
+ } else if ($from.parent.content.size === 1 && $from.parent.textContent === "\u200B") {
5004
+ const child = $from.parent.child(0);
5005
+ if (child.marks.some((m) => m.type === markType)) {
5006
+ hasHighlight = true;
5007
+ }
5008
+ } else {
5009
+ $from.parent.descendants((node) => {
5010
+ if (node.isText && node.marks.some((m) => m.type === markType)) {
5011
+ hasHighlight = true;
5012
+ }
5013
+ });
5014
+ }
5015
+ if (!hasHighlight) return false;
5016
+ if (!view.endOfTextblock("down")) return false;
5017
+ const paragraphType = state$1.schema.nodes.paragraph;
5018
+ if (!paragraphType) return false;
5019
+ if (dispatch) {
5020
+ const p = paragraphType.create();
5021
+ const insertPos = state$1.doc.content.size;
5022
+ let tr = state$1.tr.insert(insertPos, p);
5023
+ const newPos = insertPos + 1;
5024
+ tr = tr.setSelection(state.TextSelection.create(tr.doc, newPos));
5025
+ tr = tr.removeStoredMark(markType);
5026
+ dispatch(tr.scrollIntoView());
5027
+ }
5028
+ return true;
5029
+ };
5030
+ }
5031
+ },
5032
+ HighlightMarkBackspace: {
5033
+ shortcuts: "Backspace",
5034
+ command: (ctx) => {
5035
+ return (state, dispatch) => {
5036
+ const markType = highlightMarkSchema.type(ctx);
5037
+ const { selection } = state;
5038
+ const { $from, empty } = selection;
5039
+ if (!empty) return false;
5040
+ const isTextblock = $from.parent.isTextblock;
5041
+ if (!isTextblock) return false;
5042
+ if ($from.parentOffset === 0) {
5043
+ const prevBlockPos = $from.before() - 1;
5044
+ if (prevBlockPos > 0) {
5045
+ const $prev = state.doc.resolve(prevBlockPos);
5046
+ const prevBlock = $prev.parent;
5047
+ if (prevBlock && prevBlock.isTextblock) {
5048
+ let prevHasHighlight = false;
5049
+ prevBlock.descendants((node) => {
5050
+ if (node.marks.some((m) => m.type === markType)) {
5051
+ prevHasHighlight = true;
5052
+ }
5053
+ });
5054
+ if (prevHasHighlight) {
5055
+ if (dispatch) {
5056
+ let tr = state.tr;
5057
+ tr = tr.delete($prev.start() - 1, $prev.end() + 1);
5058
+ dispatch(tr.scrollIntoView());
5059
+ }
5060
+ return true;
5061
+ }
5062
+ }
5063
+ }
5064
+ }
5065
+ let hasHighlight = false;
5066
+ let isPlaceholder = false;
5067
+ if ($from.parent.content.size === 0) {
5068
+ const marks = state.storedMarks || $from.marks();
5069
+ if (markType.isInSet(marks)) {
5070
+ hasHighlight = true;
5071
+ }
5072
+ } else if ($from.parent.content.size === 1 && $from.parent.textContent === "\u200B") {
5073
+ const child = $from.parent.child(0);
5074
+ if (child.marks.some((m) => m.type === markType)) {
5075
+ hasHighlight = true;
5076
+ isPlaceholder = true;
5077
+ }
5078
+ }
5079
+ if (hasHighlight) {
5080
+ if (dispatch) {
5081
+ let tr = state.tr;
5082
+ if (isPlaceholder) {
5083
+ const start = $from.start();
5084
+ const end = $from.end();
5085
+ tr = tr.delete(start, end);
5086
+ }
5087
+ tr = tr.removeStoredMark(markType);
5088
+ dispatch(tr.scrollIntoView());
5089
+ }
5090
+ return true;
5091
+ }
5092
+ return false;
5093
+ };
5094
+ }
5095
+ }
5096
+ });
5097
+ const highlightEmptyBlockPlugin = utils.$prose((ctx) => {
5098
+ return new state.Plugin({
5099
+ key: new state.PluginKey("highlightEmptyBlock"),
5100
+ props: {
5101
+ decorations(state) {
5102
+ const markType = highlightMarkSchema.type(ctx);
5103
+ const decorations = [];
5104
+ state.doc.descendants((node, pos) => {
5105
+ if (node.isTextblock) {
5106
+ if (node.content.size === 1 && node.textContent === "\u200B") {
5107
+ const child = node.child(0);
5108
+ if (child.marks.some((m) => m.type === markType)) {
5109
+ decorations.push(
5110
+ view$1.Decoration.node(pos, pos + node.nodeSize, {
5111
+ class: "crepe-placeholder crepe-highlight-empty",
5112
+ "data-placeholder": "\u8BF7\u8F93\u5165\u5185\u5BB9"
5113
+ })
5114
+ );
5115
+ }
5116
+ }
5117
+ }
5118
+ });
5119
+ const { selection } = state;
5120
+ const { $from, empty } = selection;
5121
+ if (empty && $from.parent.isTextblock && $from.parent.content.size === 0) {
5122
+ const marks = state.storedMarks || $from.marks();
5123
+ if (markType.isInSet(marks)) {
5124
+ const start = $from.start() - 1;
5125
+ decorations.push(
5126
+ view$1.Decoration.node(start, start + $from.parent.nodeSize, {
5127
+ class: "crepe-placeholder crepe-highlight-empty",
5128
+ "data-placeholder": "\u8BF7\u8F93\u5165\u5185\u5BB9"
5129
+ })
5130
+ );
5131
+ }
5132
+ }
5133
+ return view$1.DecorationSet.create(state.doc, decorations);
5134
+ }
5135
+ },
5136
+ appendTransaction(transactions, _oldState, newState) {
5137
+ const markType = highlightMarkSchema.type(ctx);
5138
+ if (!transactions.some((t) => t.docChanged)) return null;
5139
+ const { empty, $from } = newState.selection;
5140
+ if (!empty || !$from.parent.isTextblock) return null;
5141
+ if ($from.parent.content.size !== 0) return null;
5142
+ const marks = newState.storedMarks || $from.marks();
5143
+ if (!markType.isInSet(marks)) return null;
5144
+ const id = Math.random().toString(36).substring(2, 9);
5145
+ const mark = markType.create({ id });
5146
+ return newState.tr.insert($from.pos, newState.schema.text("\u200B", [mark]));
5147
+ }
5148
+ });
5149
+ });
5150
+ const highlightMark = [
5151
+ highlightMarkAttr,
5152
+ highlightMarkSchema,
5153
+ toggleHighlightMarkCommand,
5154
+ highlightMarkKeymap,
5155
+ remarkHighlightMarkPlugin,
5156
+ highlightEmptyBlockPlugin
5157
+ ];
5158
+
5159
+ const remarkUnderlinePlugin = utils.$remark(
5160
+ "remarkUnderline",
5161
+ () => function() {
5162
+ const data = this.data();
5163
+ function add(key, value) {
5164
+ if (Array.isArray(data[key])) {
5165
+ data[key].push(value);
5166
+ } else {
5167
+ data[key] = [value];
5168
+ }
5169
+ }
5170
+ add("toMarkdownExtensions", {
5171
+ handlers: {
5172
+ underline: (node, _, state) => {
5173
+ return `<u>${state.containerPhrasing(node, state)}</u>`;
5174
+ }
5175
+ }
5176
+ });
5177
+ return (ast) => {
5178
+ unistUtilVisit.visit(ast, (node, index, parent) => {
5179
+ if ((node == null ? void 0 : node.type) === "html" && node.value === "<u>" && parent && index != null) {
5180
+ const endIndex = parent.children.findIndex(
5181
+ (n, i) => i > index && n.type === "html" && n.value === "</u>"
5182
+ );
5183
+ if (endIndex !== -1) {
5184
+ const children = parent.children.splice(
5185
+ index,
5186
+ endIndex - index + 1
5187
+ );
5188
+ const content = children.slice(1, -1);
5189
+ parent.children.splice(index, 0, {
5190
+ type: "underline",
5191
+ children: content
5192
+ });
5193
+ return index + 1;
5194
+ }
5195
+ }
5196
+ return;
5197
+ });
5198
+ };
5199
+ }
5200
+ );
5201
+ const underlineAttr = utils.$markAttr("underline");
5202
+ const underlineSchema = utils.$markSchema("underline", (ctx) => ({
5203
+ inclusive: true,
5204
+ parseDOM: [
5205
+ { tag: "u" },
5206
+ {
5207
+ style: "text-decoration",
5208
+ getAttrs: (value) => value === "underline" ? null : false
5209
+ }
5210
+ ],
5211
+ toDOM: (mark) => ["u", ctx.get(underlineAttr.key)(mark), 0],
5212
+ parseMarkdown: {
5213
+ match: (node) => node.type === "underline",
5214
+ runner: (state, node, markType) => {
5215
+ state.openMark(markType);
5216
+ state.next(node.children);
5217
+ state.closeMark(markType);
5218
+ }
5219
+ },
5220
+ toMarkdown: {
5221
+ match: (mark) => mark.type.name === "underline",
5222
+ runner: (state, mark) => {
5223
+ state.withMark(mark, "underline");
5224
+ }
5225
+ }
5226
+ }));
5227
+ const toggleUnderlineCommand = utils.$command(
5228
+ "ToggleUnderline",
5229
+ (ctx) => () => commands.toggleMark(underlineSchema.type(ctx))
5230
+ );
5231
+ const underlineKeymap = utils.$useKeymap("underlineKeymap", {
5232
+ ToggleUnderline: {
5233
+ shortcuts: "Mod-u",
5234
+ command: (ctx) => {
5235
+ const commands = ctx.get(core.commandsCtx);
5236
+ return () => commands.call(toggleUnderlineCommand.key);
5237
+ }
5238
+ }
5239
+ });
5240
+ const underline = [
5241
+ underlineAttr,
5242
+ underlineSchema,
5243
+ toggleUnderlineCommand,
5244
+ underlineKeymap,
5245
+ remarkUnderlinePlugin
5246
+ ];
5247
+
5248
+ const listeners = /* @__PURE__ */ new Set();
5249
+ let _popupCount = 0;
5250
+ function getIsAnyPopupOpen() {
5251
+ return _popupCount > 0;
5252
+ }
5253
+ function addPopupChangeListener(fn) {
5254
+ listeners.add(fn);
4965
5255
  return () => listeners.delete(fn);
4966
5256
  }
4967
5257
  function incrementPopupCount() {
@@ -5080,434 +5370,144 @@ function getGroups(config, ctx) {
5080
5370
  onRun: (ctx2) => {
5081
5371
  const commands = ctx2.get(core.commandsCtx);
5082
5372
  const view = ctx2.get(core.editorViewCtx);
5083
- const result = prose.findNodeInSelection(view.state, commonmark.headingSchema.type(ctx2));
5084
- const isActive = result.hasNode && !!result.target && result.target.attrs.level === 5;
5085
- if (isActive) {
5086
- commands.call(commonmark.setBlockTypeCommand.key, {
5087
- nodeType: commonmark.paragraphSchema.type(ctx2)
5088
- });
5089
- } else {
5090
- commands.call(commonmark.wrapInHeadingCommand.key, 5);
5091
- }
5092
- }
5093
- }).addItem("h6", {
5094
- label: ctx ? i18n(ctx, "menu.item.h6") : "Heading 6",
5095
- icon: (_f = config == null ? void 0 : config.h6Icon) != null ? _f : h6Icon,
5096
- active: (ctx2) => {
5097
- const view = ctx2.get(core.editorViewCtx);
5098
- const result = prose.findNodeInSelection(view.state, commonmark.headingSchema.type(ctx2));
5099
- return result.hasNode && !!result.target && result.target.attrs.level === 6;
5100
- },
5101
- onRun: (ctx2) => {
5102
- const commands = ctx2.get(core.commandsCtx);
5103
- const view = ctx2.get(core.editorViewCtx);
5104
- const result = prose.findNodeInSelection(view.state, commonmark.headingSchema.type(ctx2));
5105
- const isActive = result.hasNode && !!result.target && result.target.attrs.level === 6;
5106
- if (isActive) {
5107
- commands.call(commonmark.setBlockTypeCommand.key, {
5108
- nodeType: commonmark.paragraphSchema.type(ctx2)
5109
- });
5110
- } else {
5111
- commands.call(commonmark.wrapInHeadingCommand.key, 6);
5112
- }
5113
- }
5114
- });
5115
- groupBuilder.addGroup(
5116
- "formatting",
5117
- ctx ? i18n(ctx, "toolbar.formatting") : "Formatting"
5118
- ).addItem("bold", {
5119
- label: ctx ? i18n(ctx, "menu.item.bold") : "Bold",
5120
- icon: (_g = config == null ? void 0 : config.boldIcon) != null ? _g : boldIcon,
5121
- active: (ctx2) => {
5122
- const commands = ctx2.get(core.commandsCtx);
5123
- return commands.call(commonmark.isMarkSelectedCommand.key, commonmark.strongSchema.type(ctx2));
5124
- },
5125
- onRun: (ctx2) => {
5126
- const commands = ctx2.get(core.commandsCtx);
5127
- commands.call(commonmark.toggleStrongCommand.key);
5128
- }
5129
- }).addItem("italic", {
5130
- label: ctx ? i18n(ctx, "menu.item.italic") : "Italic",
5131
- icon: (_h = config == null ? void 0 : config.italicIcon) != null ? _h : italicIcon,
5132
- active: (ctx2) => {
5133
- const commands = ctx2.get(core.commandsCtx);
5134
- return commands.call(
5135
- commonmark.isMarkSelectedCommand.key,
5136
- commonmark.emphasisSchema.type(ctx2)
5137
- );
5138
- },
5139
- onRun: (ctx2) => {
5140
- const commands = ctx2.get(core.commandsCtx);
5141
- commands.call(commonmark.toggleEmphasisCommand.key);
5142
- }
5143
- }).addItem("strikethrough", {
5144
- label: ctx ? i18n(ctx, "menu.item.strikethrough") : "Strikethrough",
5145
- icon: (_i = config == null ? void 0 : config.strikethroughIcon) != null ? _i : strikethroughIcon,
5146
- active: (ctx2) => {
5147
- const commands = ctx2.get(core.commandsCtx);
5148
- return commands.call(
5149
- commonmark.isMarkSelectedCommand.key,
5150
- gfm.strikethroughSchema.type(ctx2)
5151
- );
5152
- },
5153
- onRun: (ctx2) => {
5154
- const commands = ctx2.get(core.commandsCtx);
5155
- commands.call(gfm.toggleStrikethroughCommand.key);
5156
- }
5157
- }).addItem("underline", {
5158
- label: ctx ? i18n(ctx, "menu.item.underline") : "Underline",
5159
- icon: (_j = config == null ? void 0 : config.underlineIcon) != null ? _j : underlineIcon,
5160
- active: (ctx2) => {
5161
- const commands = ctx2.get(core.commandsCtx);
5162
- return commands.call(
5163
- commonmark.isMarkSelectedCommand.key,
5164
- underlineSchema.type(ctx2)
5165
- );
5166
- },
5167
- onRun: (ctx2) => {
5168
- const commands = ctx2.get(core.commandsCtx);
5169
- commands.call(toggleUnderlineCommand.key);
5170
- }
5171
- });
5172
- const functionGroup = groupBuilder.addGroup(
5173
- "function",
5174
- ctx ? i18n(ctx, "toolbar.function") : "Function"
5175
- );
5176
- functionGroup.addItem("highlight", {
5177
- label: ctx ? i18n(ctx, "menu.item.highlight") : "Highlight",
5178
- icon: (_k = config == null ? void 0 : config.highlightIcon) != null ? _k : highLineCodeIcon,
5179
- active: (ctx2) => {
5180
- const commands = ctx2.get(core.commandsCtx);
5181
- return commands.call(
5182
- commonmark.isMarkSelectedCommand.key,
5183
- highlightMarkSchema.type(ctx2)
5184
- );
5185
- },
5186
- onRun: (ctx2) => {
5187
- const commands = ctx2.get(core.commandsCtx);
5188
- commands.call(toggleHighlightMarkCommand.key);
5189
- }
5190
- });
5191
- functionGroup.addItem("code", {
5192
- label: ctx ? i18n(ctx, "menu.item.lineCode") : "Inline Code",
5193
- icon: (_l = config == null ? void 0 : config.codeIcon) != null ? _l : linCodeIcon,
5194
- active: (ctx2) => {
5195
- const commands = ctx2.get(core.commandsCtx);
5196
- return commands.call(
5197
- commonmark.isMarkSelectedCommand.key,
5198
- commonmark.inlineCodeSchema.type(ctx2)
5199
- );
5200
- },
5201
- onRun: (ctx2) => {
5202
- const commands = ctx2.get(core.commandsCtx);
5203
- commands.call(commonmark.toggleInlineCodeCommand.key);
5204
- }
5205
- });
5206
- functionGroup.addItem("link", {
5207
- label: ctx ? i18n(ctx, "menu.item.link") : "Link",
5208
- icon: (_m = config == null ? void 0 : config.linkIcon) != null ? _m : linkIcon,
5209
- active: (ctx2) => {
5210
- const commands = ctx2.get(core.commandsCtx);
5211
- return commands.call(commonmark.isMarkSelectedCommand.key, commonmark.linkSchema.type(ctx2));
5212
- },
5213
- onRun: (ctx2) => {
5214
- const commands = ctx2.get(core.commandsCtx);
5215
- commands.call(linkTooltip$1.toggleLinkCommand.key);
5216
- }
5217
- });
5218
- (_n = config == null ? void 0 : config.buildToolbar) == null ? void 0 : _n.call(config, groupBuilder);
5219
- return groupBuilder.build();
5220
- }
5221
-
5222
- const supportedFontsCache = /* @__PURE__ */ new Map();
5223
- const isFontSupported = (fontFamily) => {
5224
- if (!fontFamily) return true;
5225
- const normalizedFont = fontFamily.replace(/['"]/g, "");
5226
- if (supportedFontsCache.has(normalizedFont)) {
5227
- return supportedFontsCache.get(normalizedFont);
5228
- }
5229
- if (typeof document === "undefined") return true;
5230
- const canvas = document.createElement("canvas");
5231
- const context = canvas.getContext("2d");
5232
- if (!context) return true;
5233
- const text = "abcdefghijklmnopqrstuvwxyz0123456789";
5234
- const size = "72px";
5235
- context.font = `${size} monospace`;
5236
- const baseMono = context.measureText(text).width;
5237
- context.font = `${size} sans-serif`;
5238
- const baseSans = context.measureText(text).width;
5239
- context.font = `${size} "${normalizedFont}", monospace`;
5240
- const testMono = context.measureText(text).width;
5241
- context.font = `${size} "${normalizedFont}", sans-serif`;
5242
- const testSans = context.measureText(text).width;
5243
- const supported = testMono !== baseMono || testSans !== baseSans;
5244
- supportedFontsCache.set(normalizedFont, supported);
5245
- return supported;
5246
- };
5247
- const remarkFontPlugin = utils.$remark(
5248
- "remarkFont",
5249
- () => function() {
5250
- const data = this.data();
5251
- function add(key, value) {
5252
- if (Array.isArray(data[key])) {
5253
- data[key].push(value);
5254
- } else {
5255
- data[key] = [value];
5256
- }
5257
- }
5258
- add("toMarkdownExtensions", {
5259
- handlers: {
5260
- fontFamily: (node, _, state) => {
5261
- return `<span style="font-family:${node.fontFamily}">${state.containerPhrasing(node, state)}</span>`;
5262
- },
5263
- fontSize: (node, _, state) => {
5264
- return `<span style="font-size:${node.fontSize}">${state.containerPhrasing(node, state)}</span>`;
5265
- }
5266
- }
5267
- });
5268
- return (ast) => {
5269
- unistUtilVisit.visit(ast, (node, index, parent) => {
5270
- if ((node == null ? void 0 : node.type) === "html" && node.value.startsWith("<span") && parent && index != null) {
5271
- const hasFontFamily = node.value.match(/font-family:\s*([^"';>]+)/);
5272
- const hasFontSize = node.value.match(/font-size:\s*([^"';>]+)/);
5273
- if (!hasFontFamily && !hasFontSize) return;
5274
- let fontFamily = null;
5275
- let fontSize = null;
5276
- let markType = null;
5277
- if (hasFontFamily) {
5278
- fontFamily = hasFontFamily[1].trim();
5279
- markType = "fontFamily";
5280
- } else if (hasFontSize) {
5281
- fontSize = hasFontSize[1].trim();
5282
- markType = "fontSize";
5283
- }
5284
- const endIndex = parent.children.findIndex(
5285
- (n, i) => i > index && n.type === "html" && n.value === "</span>"
5286
- );
5287
- if (endIndex !== -1 && markType && (fontFamily || fontSize)) {
5288
- const children = parent.children.splice(
5289
- index,
5290
- endIndex - index + 1
5291
- );
5292
- const content = children.slice(1, -1);
5293
- const payload = {
5294
- type: markType,
5295
- children: content
5296
- };
5297
- if (fontFamily) payload.fontFamily = fontFamily;
5298
- if (fontSize) payload.fontSize = fontSize;
5299
- parent.children.splice(index, 0, payload);
5300
- return index + 1;
5301
- }
5302
- }
5303
- return;
5304
- });
5305
- };
5306
- }
5307
- );
5308
- const fontFamilyAttr = utils.$markAttr("fontFamily");
5309
- const fontFamilySchema = utils.$markSchema("fontFamily", (_ctx) => ({
5310
- inclusive: true,
5311
- attrs: {
5312
- fontFamily: { default: null }
5313
- },
5314
- parseDOM: [
5315
- {
5316
- tag: 'span[style*="font-family"]',
5317
- getAttrs: (dom) => {
5318
- if (!(dom instanceof HTMLElement)) return false;
5319
- const fontFamily = dom.style.fontFamily || null;
5320
- if (!isFontSupported(fontFamily)) return false;
5321
- return { fontFamily };
5373
+ const result = prose.findNodeInSelection(view.state, commonmark.headingSchema.type(ctx2));
5374
+ const isActive = result.hasNode && !!result.target && result.target.attrs.level === 5;
5375
+ if (isActive) {
5376
+ commands.call(commonmark.setBlockTypeCommand.key, {
5377
+ nodeType: commonmark.paragraphSchema.type(ctx2)
5378
+ });
5379
+ } else {
5380
+ commands.call(commonmark.wrapInHeadingCommand.key, 5);
5322
5381
  }
5323
5382
  }
5324
- ],
5325
- toDOM: (mark) => {
5326
- return ["span", { style: `font-family: ${mark.attrs.fontFamily}` }, 0];
5327
- },
5328
- parseMarkdown: {
5329
- match: (node) => node.type === "fontFamily",
5330
- runner: (state, node, markType) => {
5331
- state.openMark(markType, { fontFamily: node.fontFamily });
5332
- state.next(node.children);
5333
- state.closeMark(markType);
5383
+ }).addItem("h6", {
5384
+ label: ctx ? i18n(ctx, "menu.item.h6") : "Heading 6",
5385
+ icon: (_f = config == null ? void 0 : config.h6Icon) != null ? _f : h6Icon,
5386
+ active: (ctx2) => {
5387
+ const view = ctx2.get(core.editorViewCtx);
5388
+ const result = prose.findNodeInSelection(view.state, commonmark.headingSchema.type(ctx2));
5389
+ return result.hasNode && !!result.target && result.target.attrs.level === 6;
5390
+ },
5391
+ onRun: (ctx2) => {
5392
+ const commands = ctx2.get(core.commandsCtx);
5393
+ const view = ctx2.get(core.editorViewCtx);
5394
+ const result = prose.findNodeInSelection(view.state, commonmark.headingSchema.type(ctx2));
5395
+ const isActive = result.hasNode && !!result.target && result.target.attrs.level === 6;
5396
+ if (isActive) {
5397
+ commands.call(commonmark.setBlockTypeCommand.key, {
5398
+ nodeType: commonmark.paragraphSchema.type(ctx2)
5399
+ });
5400
+ } else {
5401
+ commands.call(commonmark.wrapInHeadingCommand.key, 6);
5402
+ }
5334
5403
  }
5335
- },
5336
- toMarkdown: {
5337
- match: (mark) => mark.type.name === "fontFamily",
5338
- runner: (state, mark) => {
5339
- state.withMark(mark, "fontFamily", void 0, {
5340
- fontFamily: mark.attrs.fontFamily
5341
- });
5404
+ });
5405
+ groupBuilder.addGroup(
5406
+ "formatting",
5407
+ ctx ? i18n(ctx, "toolbar.formatting") : "Formatting"
5408
+ ).addItem("bold", {
5409
+ label: ctx ? i18n(ctx, "menu.item.bold") : "Bold",
5410
+ icon: (_g = config == null ? void 0 : config.boldIcon) != null ? _g : boldIcon,
5411
+ active: (ctx2) => {
5412
+ const commands = ctx2.get(core.commandsCtx);
5413
+ return commands.call(commonmark.isMarkSelectedCommand.key, commonmark.strongSchema.type(ctx2));
5414
+ },
5415
+ onRun: (ctx2) => {
5416
+ const commands = ctx2.get(core.commandsCtx);
5417
+ commands.call(commonmark.toggleStrongCommand.key);
5342
5418
  }
5343
- }
5344
- }));
5345
- const fontSizeAttr = utils.$markAttr("fontSize");
5346
- const fontSizeSchema = utils.$markSchema("fontSize", (_ctx) => ({
5347
- inclusive: true,
5348
- attrs: {
5349
- fontSize: { default: null }
5350
- },
5351
- parseDOM: [
5352
- {
5353
- tag: 'span[style*="font-size"]',
5354
- getAttrs: (dom) => {
5355
- if (!(dom instanceof HTMLElement)) return false;
5356
- return { fontSize: dom.style.fontSize || null };
5357
- }
5419
+ }).addItem("italic", {
5420
+ label: ctx ? i18n(ctx, "menu.item.italic") : "Italic",
5421
+ icon: (_h = config == null ? void 0 : config.italicIcon) != null ? _h : italicIcon,
5422
+ active: (ctx2) => {
5423
+ const commands = ctx2.get(core.commandsCtx);
5424
+ return commands.call(
5425
+ commonmark.isMarkSelectedCommand.key,
5426
+ commonmark.emphasisSchema.type(ctx2)
5427
+ );
5428
+ },
5429
+ onRun: (ctx2) => {
5430
+ const commands = ctx2.get(core.commandsCtx);
5431
+ commands.call(commonmark.toggleEmphasisCommand.key);
5358
5432
  }
5359
- ],
5360
- toDOM: (mark) => {
5361
- return ["span", { style: `font-size: ${mark.attrs.fontSize}` }, 0];
5362
- },
5363
- parseMarkdown: {
5364
- match: (node) => node.type === "fontSize",
5365
- runner: (state, node, markType) => {
5366
- state.openMark(markType, { fontSize: node.fontSize });
5367
- state.next(node.children);
5368
- state.closeMark(markType);
5433
+ }).addItem("strikethrough", {
5434
+ label: ctx ? i18n(ctx, "menu.item.strikethrough") : "Strikethrough",
5435
+ icon: (_i = config == null ? void 0 : config.strikethroughIcon) != null ? _i : strikethroughIcon,
5436
+ active: (ctx2) => {
5437
+ const commands = ctx2.get(core.commandsCtx);
5438
+ return commands.call(
5439
+ commonmark.isMarkSelectedCommand.key,
5440
+ gfm.strikethroughSchema.type(ctx2)
5441
+ );
5442
+ },
5443
+ onRun: (ctx2) => {
5444
+ const commands = ctx2.get(core.commandsCtx);
5445
+ commands.call(gfm.toggleStrikethroughCommand.key);
5369
5446
  }
5370
- },
5371
- toMarkdown: {
5372
- match: (mark) => mark.type.name === "fontSize",
5373
- runner: (state, mark) => {
5374
- state.withMark(mark, "fontSize", void 0, {
5375
- fontSize: mark.attrs.fontSize
5376
- });
5447
+ }).addItem("underline", {
5448
+ label: ctx ? i18n(ctx, "menu.item.underline") : "Underline",
5449
+ icon: (_j = config == null ? void 0 : config.underlineIcon) != null ? _j : underlineIcon,
5450
+ active: (ctx2) => {
5451
+ const commands = ctx2.get(core.commandsCtx);
5452
+ return commands.call(
5453
+ commonmark.isMarkSelectedCommand.key,
5454
+ underlineSchema.type(ctx2)
5455
+ );
5456
+ },
5457
+ onRun: (ctx2) => {
5458
+ const commands = ctx2.get(core.commandsCtx);
5459
+ commands.call(toggleUnderlineCommand.key);
5377
5460
  }
5378
- }
5379
- }));
5380
- const toggleFontFamilyCommand = utils.$command(
5381
- "ToggleFontFamily",
5382
- (ctx) => (fontFamily) => {
5383
- return (state, dispatch) => {
5384
- const markType = fontFamilySchema.type(ctx);
5385
- const { $cursor, ranges } = state.selection;
5386
- if (dispatch) {
5387
- let tr = state.tr;
5388
- if ($cursor) {
5389
- const marks = state.storedMarks || $cursor.marks();
5390
- const currentMark = markType.isInSet(marks);
5391
- if (currentMark && currentMark.attrs.fontFamily === fontFamily) {
5392
- tr = tr.removeStoredMark(markType);
5393
- } else {
5394
- tr = tr.removeStoredMark(markType);
5395
- if (fontFamily)
5396
- tr = tr.addStoredMark(markType.create({ fontFamily }));
5397
- }
5398
- } else {
5399
- let hasSameFontFamily = false;
5400
- for (const range of ranges) {
5401
- const { $from, $to } = range;
5402
- state.doc.nodesBetween($from.pos, $to.pos, (node) => {
5403
- if (node.isText) {
5404
- const mark = markType.isInSet(node.marks);
5405
- if (mark && mark.attrs.fontFamily === fontFamily) {
5406
- hasSameFontFamily = true;
5407
- }
5408
- }
5409
- });
5410
- }
5411
- for (const range of ranges) {
5412
- const { $from, $to } = range;
5413
- tr = tr.removeMark($from.pos, $to.pos, markType);
5414
- if (!hasSameFontFamily && fontFamily) {
5415
- tr = tr.addMark(
5416
- $from.pos,
5417
- $to.pos,
5418
- markType.create({ fontFamily })
5419
- );
5420
- }
5421
- }
5422
- }
5423
- dispatch(tr.scrollIntoView());
5424
- }
5425
- return true;
5426
- };
5427
- }
5428
- );
5429
- const toggleFontSizeCommand = utils.$command(
5430
- "ToggleFontSize",
5431
- (ctx) => (fontSize) => {
5432
- return (state, dispatch) => {
5433
- const markType = fontSizeSchema.type(ctx);
5434
- const { $cursor, ranges } = state.selection;
5435
- if (dispatch) {
5436
- let tr = state.tr;
5437
- if ($cursor) {
5438
- const marks = state.storedMarks || $cursor.marks();
5439
- const currentMark = markType.isInSet(marks);
5440
- if (currentMark && currentMark.attrs.fontSize === fontSize) {
5441
- tr = tr.removeStoredMark(markType);
5442
- } else {
5443
- tr = tr.removeStoredMark(markType);
5444
- if (fontSize) tr = tr.addStoredMark(markType.create({ fontSize }));
5445
- }
5446
- } else {
5447
- let hasSameFontSize = false;
5448
- for (const range of ranges) {
5449
- const { $from, $to } = range;
5450
- state.doc.nodesBetween($from.pos, $to.pos, (node) => {
5451
- if (node.isText) {
5452
- const mark = markType.isInSet(node.marks);
5453
- if (mark && mark.attrs.fontSize === fontSize) {
5454
- hasSameFontSize = true;
5455
- }
5456
- }
5457
- });
5458
- }
5459
- for (const range of ranges) {
5460
- const { $from, $to } = range;
5461
- tr = tr.removeMark($from.pos, $to.pos, markType);
5462
- if (!hasSameFontSize && fontSize) {
5463
- tr = tr.addMark(
5464
- $from.pos,
5465
- $to.pos,
5466
- markType.create({ fontSize })
5467
- );
5468
- }
5469
- }
5470
- }
5471
- dispatch(tr.scrollIntoView());
5472
- }
5473
- return true;
5474
- };
5475
- }
5476
- );
5477
- function stripFontFamilyFromExternalHTML(html) {
5478
- if (html.includes("data-pm-slice")) return html;
5479
- try {
5480
- const template = document.createElement("template");
5481
- template.innerHTML = html;
5482
- const styledElements = template.content.querySelectorAll(
5483
- '[style*="font-family"]'
5484
- );
5485
- styledElements.forEach((el) => {
5486
- if (el instanceof HTMLElement) {
5487
- el.style.removeProperty("font-family");
5488
- }
5489
- });
5490
- const fontElements = template.content.querySelectorAll("font[face]");
5491
- fontElements.forEach((el) => {
5492
- if (el instanceof HTMLElement) {
5493
- el.removeAttribute("face");
5494
- }
5495
- });
5496
- html = template.innerHTML;
5497
- template.remove();
5498
- } catch (e) {
5499
- }
5500
- return html;
5461
+ });
5462
+ const functionGroup = groupBuilder.addGroup(
5463
+ "function",
5464
+ ctx ? i18n(ctx, "toolbar.function") : "Function"
5465
+ );
5466
+ functionGroup.addItem("highlight", {
5467
+ label: ctx ? i18n(ctx, "menu.item.highlight") : "Highlight",
5468
+ icon: (_k = config == null ? void 0 : config.highlightIcon) != null ? _k : highLineCodeIcon,
5469
+ active: (ctx2) => {
5470
+ const commands = ctx2.get(core.commandsCtx);
5471
+ return commands.call(
5472
+ commonmark.isMarkSelectedCommand.key,
5473
+ highlightMarkSchema.type(ctx2)
5474
+ );
5475
+ },
5476
+ onRun: (ctx2) => {
5477
+ const commands = ctx2.get(core.commandsCtx);
5478
+ commands.call(toggleHighlightMarkCommand.key);
5479
+ }
5480
+ });
5481
+ functionGroup.addItem("code", {
5482
+ label: ctx ? i18n(ctx, "menu.item.lineCode") : "Inline Code",
5483
+ icon: (_l = config == null ? void 0 : config.codeIcon) != null ? _l : linCodeIcon,
5484
+ active: (ctx2) => {
5485
+ const commands = ctx2.get(core.commandsCtx);
5486
+ return commands.call(
5487
+ commonmark.isMarkSelectedCommand.key,
5488
+ commonmark.inlineCodeSchema.type(ctx2)
5489
+ );
5490
+ },
5491
+ onRun: (ctx2) => {
5492
+ const commands = ctx2.get(core.commandsCtx);
5493
+ commands.call(commonmark.toggleInlineCodeCommand.key);
5494
+ }
5495
+ });
5496
+ functionGroup.addItem("link", {
5497
+ label: ctx ? i18n(ctx, "menu.item.link") : "Link",
5498
+ icon: (_m = config == null ? void 0 : config.linkIcon) != null ? _m : linkIcon,
5499
+ active: (ctx2) => {
5500
+ const commands = ctx2.get(core.commandsCtx);
5501
+ return commands.call(commonmark.isMarkSelectedCommand.key, commonmark.linkSchema.type(ctx2));
5502
+ },
5503
+ onRun: (ctx2) => {
5504
+ const commands = ctx2.get(core.commandsCtx);
5505
+ commands.call(linkTooltip$1.toggleLinkCommand.key);
5506
+ }
5507
+ });
5508
+ (_n = config == null ? void 0 : config.buildToolbar) == null ? void 0 : _n.call(config, groupBuilder);
5509
+ return groupBuilder.build();
5501
5510
  }
5502
- const fontPlugins = [
5503
- fontFamilyAttr,
5504
- fontFamilySchema,
5505
- toggleFontFamilyCommand,
5506
- fontSizeAttr,
5507
- fontSizeSchema,
5508
- toggleFontSizeCommand,
5509
- remarkFontPlugin
5510
- ];
5511
5511
 
5512
5512
  const activeIconMap = {
5513
5513
  [boldIcon]: boldIconActive,
@@ -5540,7 +5540,7 @@ const Toolbar = vue.defineComponent({
5540
5540
  ctx: { type: Object, required: true },
5541
5541
  hide: { type: Function, required: true },
5542
5542
  show: { type: Object, required: true },
5543
- selection: { type: Object, required: true },
5543
+ state: { type: Object, required: true },
5544
5544
  config: { type: Object, required: false },
5545
5545
  isFixed: { type: Boolean, required: false }
5546
5546
  },
@@ -6142,17 +6142,17 @@ const Toolbar = vue.defineComponent({
6142
6142
  if (ctx) fn(ctx);
6143
6143
  };
6144
6144
  function checkActive(checker) {
6145
- var _a;
6146
- keepAlive(props.selection.value);
6147
- const status = (_a = ctx == null ? void 0 : ctx.get(core.editorCtx)) == null ? void 0 : _a.status;
6145
+ var _a, _b;
6146
+ keepAlive(props.state, (_a = props.state) == null ? void 0 : _a.value);
6147
+ const status = (_b = ctx == null ? void 0 : ctx.get(core.editorCtx)) == null ? void 0 : _b.status;
6148
6148
  if (status !== core.EditorStatus.Created) return false;
6149
6149
  return checker(ctx);
6150
6150
  }
6151
6151
  const blockGroups = vue.computed(() => getGroups$1("", void 0, ctx));
6152
6152
  const activeBlockItem = vue.computed(() => {
6153
- var _a;
6154
- keepAlive(props.selection.value);
6155
- const status = (_a = ctx == null ? void 0 : ctx.get(core.editorCtx)) == null ? void 0 : _a.status;
6153
+ var _a, _b;
6154
+ keepAlive(props.state, (_a = props.state) == null ? void 0 : _a.value);
6155
+ const status = (_b = ctx == null ? void 0 : ctx.get(core.editorCtx)) == null ? void 0 : _b.status;
6156
6156
  if (status !== core.EditorStatus.Created) return null;
6157
6157
  const view = ctx.get(core.editorViewCtx);
6158
6158
  const { $from } = view.state.selection;
@@ -6190,9 +6190,9 @@ const Toolbar = vue.defineComponent({
6190
6190
  return targetIcon;
6191
6191
  });
6192
6192
  const currentAlignIndent = vue.computed(() => {
6193
- var _a;
6194
- keepAlive(props.selection.value);
6195
- const status = (_a = ctx == null ? void 0 : ctx.get(core.editorCtx)) == null ? void 0 : _a.status;
6193
+ var _a, _b;
6194
+ keepAlive(props.state, (_a = props.state) == null ? void 0 : _a.value);
6195
+ const status = (_b = ctx == null ? void 0 : ctx.get(core.editorCtx)) == null ? void 0 : _b.status;
6196
6196
  if (status !== core.EditorStatus.Created) return { align: "left", indent: 0 };
6197
6197
  const view = ctx.get(core.editorViewCtx);
6198
6198
  let align = "left";
@@ -6262,13 +6262,15 @@ const Toolbar = vue.defineComponent({
6262
6262
  }
6263
6263
  };
6264
6264
  const canMerge = vue.computed(() => {
6265
- keepAlive(props.selection.value);
6265
+ var _a;
6266
+ keepAlive(props.state, (_a = props.state) == null ? void 0 : _a.value);
6266
6267
  const view = ctx == null ? void 0 : ctx.get(core.editorViewCtx);
6267
6268
  if (!view) return false;
6268
6269
  return tables.mergeCells(view.state);
6269
6270
  });
6270
6271
  const canSplit = vue.computed(() => {
6271
- keepAlive(props.selection.value);
6272
+ var _a;
6273
+ keepAlive(props.state, (_a = props.state) == null ? void 0 : _a.value);
6272
6274
  const view = ctx == null ? void 0 : ctx.get(core.editorViewCtx);
6273
6275
  if (!view) return false;
6274
6276
  return tables.splitCell(view.state);
@@ -6328,16 +6330,16 @@ const Toolbar = vue.defineComponent({
6328
6330
  showAlignMenu.value = false;
6329
6331
  };
6330
6332
  const currentColorState = vue.computed(() => {
6331
- var _a;
6332
- keepAlive(props.selection.value);
6333
- const status = (_a = ctx == null ? void 0 : ctx.get(core.editorCtx)) == null ? void 0 : _a.status;
6333
+ var _a, _b;
6334
+ keepAlive(props.state, (_a = props.state) == null ? void 0 : _a.value);
6335
+ const status = (_b = ctx == null ? void 0 : ctx.get(core.editorCtx)) == null ? void 0 : _b.status;
6334
6336
  if (status !== core.EditorStatus.Created)
6335
6337
  return { textColor: null, bgColor: null };
6336
6338
  const view = ctx.get(core.editorViewCtx);
6337
6339
  const { state } = view;
6338
6340
  const schema = ctx.get(core.schemaCtx);
6339
- const tcHasMark = schema.marks[textColorSchema.id];
6340
- const bcHasMark = schema.marks[bgColorSchema.id];
6341
+ const tcHasMark = schema.marks["textColor"];
6342
+ const bcHasMark = schema.marks["bgColor"];
6341
6343
  if (!tcHasMark || !bcHasMark) return { textColor: null, bgColor: null };
6342
6344
  const tcType = textColorSchema.type(ctx);
6343
6345
  const bcType = bgColorSchema.type(ctx);
@@ -6384,8 +6386,8 @@ const Toolbar = vue.defineComponent({
6384
6386
  const { tr } = state;
6385
6387
  const { from, to, empty } = state.selection;
6386
6388
  const schema = ctx.get(core.schemaCtx);
6387
- const tcHasMark = schema.marks[textColorSchema.id];
6388
- const bcHasMark = schema.marks[bgColorSchema.id];
6389
+ const tcHasMark = schema.marks["textColor"];
6390
+ const bcHasMark = schema.marks["bgColor"];
6389
6391
  if (!tcHasMark || !bcHasMark) return;
6390
6392
  const textColorType = textColorSchema.type(ctx);
6391
6393
  const bgColorType = bgColorSchema.type(ctx);
@@ -6401,29 +6403,37 @@ const Toolbar = vue.defineComponent({
6401
6403
  showColorMenu.value = false;
6402
6404
  };
6403
6405
  const currentFontState = vue.computed(() => {
6404
- var _a;
6405
- keepAlive(props.selection.value);
6406
- const status = (_a = ctx == null ? void 0 : ctx.get(core.editorCtx)) == null ? void 0 : _a.status;
6406
+ var _a, _b;
6407
+ keepAlive(props.state, (_a = props.state) == null ? void 0 : _a.value);
6408
+ const status = (_b = ctx == null ? void 0 : ctx.get(core.editorCtx)) == null ? void 0 : _b.status;
6407
6409
  if (status !== core.EditorStatus.Created)
6408
6410
  return { fontFamily: null, fontSize: null };
6409
6411
  const view = ctx.get(core.editorViewCtx);
6410
6412
  const { state } = view;
6411
6413
  const schema = ctx.get(core.schemaCtx);
6412
- const ffHasMark = schema.marks[fontFamilySchema.id];
6413
- const fsHasMark = schema.marks[fontSizeSchema.id];
6414
- if (!ffHasMark || !fsHasMark) return { fontFamily: null, fontSize: null };
6414
+ const ffHasMark = schema.marks["fontFamily"];
6415
+ const fsHasMark = schema.marks["fontSize"];
6416
+ if (!ffHasMark || !fsHasMark) {
6417
+ return { fontFamily: null, fontSize: null };
6418
+ }
6415
6419
  const ffType = fontFamilySchema.type(ctx);
6416
6420
  const fsType = fontSizeSchema.type(ctx);
6417
6421
  const { $cursor, ranges } = state.selection;
6422
+ let result = {
6423
+ fontFamily: null,
6424
+ fontSize: null
6425
+ };
6418
6426
  if ($cursor) {
6419
6427
  let fontFamily = null;
6420
6428
  let fontSize = null;
6421
6429
  const marks = state.storedMarks || $cursor.marks();
6422
6430
  for (const mark of marks) {
6423
- if (mark.type === ffType) fontFamily = mark.attrs.fontFamily;
6424
- if (mark.type === fsType) fontSize = mark.attrs.fontSize;
6431
+ if (mark.type === ffType)
6432
+ fontFamily = mark.attrs.fontFamily || null;
6433
+ if (mark.type === fsType)
6434
+ fontSize = mark.attrs.fontSize || null;
6425
6435
  }
6426
- return { fontFamily, fontSize };
6436
+ result = { fontFamily, fontSize };
6427
6437
  } else {
6428
6438
  const fontFamilies = /* @__PURE__ */ new Set();
6429
6439
  const fontSizes = /* @__PURE__ */ new Set();
@@ -6433,15 +6443,20 @@ const Toolbar = vue.defineComponent({
6433
6443
  if (node.isText) {
6434
6444
  const ffMark = ffType.isInSet(node.marks);
6435
6445
  const fsMark = fsType.isInSet(node.marks);
6436
- fontFamilies.add(ffMark ? ffMark.attrs.fontFamily : null);
6437
- fontSizes.add(fsMark ? fsMark.attrs.fontSize : null);
6446
+ fontFamilies.add(
6447
+ ffMark ? ffMark.attrs.fontFamily : null
6448
+ );
6449
+ fontSizes.add(
6450
+ fsMark ? fsMark.attrs.fontSize : null
6451
+ );
6438
6452
  }
6439
6453
  });
6440
6454
  }
6441
6455
  const fontFamily = fontFamilies.size === 1 ? Array.from(fontFamilies)[0] : "mixed";
6442
6456
  const fontSize = fontSizes.size === 1 ? Array.from(fontSizes)[0] : "mixed";
6443
- return { fontFamily, fontSize };
6457
+ result = { fontFamily, fontSize };
6444
6458
  }
6459
+ return result;
6445
6460
  });
6446
6461
  const setFontFamily = (fontFamily) => {
6447
6462
  const commands = ctx.get(core.commandsCtx);
@@ -6672,7 +6687,11 @@ const Toolbar = vue.defineComponent({
6672
6687
  color: "#363B4C"
6673
6688
  }
6674
6689
  },
6675
- currentFontState.value.fontFamily && currentFontState.value.fontFamily !== "mixed" ? currentFontState.value.fontFamily.split(",")[0].replace(/['"]/g, "") || (ctx ? i18n(ctx, "customMenu.fontDefault") : "\u9ED8\u8BA4") : ctx ? i18n(ctx, "customMenu.fontDefault") : "\u9ED8\u8BA4"
6690
+ (() => {
6691
+ const fontState = currentFontState.value;
6692
+ const fontFamily = fontState == null ? void 0 : fontState.fontFamily;
6693
+ return fontFamily && fontFamily !== "mixed" ? fontFamily.split(",")[0].replace(/['"]/g, "") || (ctx ? i18n(ctx, "customMenu.fontDefault") : "\u9ED8\u8BA4") : ctx ? i18n(ctx, "customMenu.fontDefault") : "\u9ED8\u8BA4";
6694
+ })()
6676
6695
  ),
6677
6696
  /* @__PURE__ */ vue.h(
6678
6697
  "span",
@@ -6702,7 +6721,10 @@ const Toolbar = vue.defineComponent({
6702
6721
  flexShrink: 0
6703
6722
  }
6704
6723
  },
6705
- /* @__PURE__ */ vue.h("span", { style: { fontSize: "13px", color: "#363B4C" } }, currentFontState.value.fontSize && currentFontState.value.fontSize !== "mixed" ? currentFontState.value.fontSize : "16px"),
6724
+ /* @__PURE__ */ vue.h("span", { style: { fontSize: "13px", color: "#363B4C" } }, (() => {
6725
+ const fs = currentFontState.value.fontSize;
6726
+ return fs && fs !== "mixed" ? fs : "16px";
6727
+ })()),
6706
6728
  /* @__PURE__ */ vue.h(
6707
6729
  "span",
6708
6730
  {
@@ -7850,7 +7872,8 @@ const createViewMenuState = () => vue.reactive({
7850
7872
  showTitle: false,
7851
7873
  showCover: false,
7852
7874
  coverUrl: "",
7853
- editorWidth: "default"
7875
+ editorWidth: "default",
7876
+ fixedToolbarVisible: true
7854
7877
  });
7855
7878
  const viewMenuStateCtx = utils.$ctx(createViewMenuState(), "viewMenuStateCtx");
7856
7879
 
@@ -8601,7 +8624,7 @@ const FixedToolbarComponent = vue.defineComponent({
8601
8624
  ctx: { type: Object, required: true },
8602
8625
  hide: { type: Function, required: true },
8603
8626
  show: { type: Object, required: true },
8604
- selection: { type: Object, required: true },
8627
+ state: { type: Object, required: true },
8605
8628
  config: { type: Object, required: false },
8606
8629
  canUndo: { type: Object, required: true },
8607
8630
  canRedo: { type: Object, required: true }
@@ -8622,140 +8645,234 @@ const FixedToolbarComponent = vue.defineComponent({
8622
8645
  });
8623
8646
  });
8624
8647
  return () => {
8625
- var _a, _b, _c, _d;
8626
- props.selection.value;
8627
- const canUndo = (typeof props.canUndo === "boolean" ? props.canUndo : (_a = props.canUndo) == null ? void 0 : _a.value) || false;
8628
- const canRedo = (typeof props.canRedo === "boolean" ? props.canRedo : (_b = props.canRedo) == null ? void 0 : _b.value) || false;
8648
+ var _a, _b, _c, _d, _e;
8649
+ ((_a = props.state) == null ? void 0 : _a.value) || props.state;
8650
+ const canUndo = (typeof props.canUndo === "boolean" ? props.canUndo : (_b = props.canUndo) == null ? void 0 : _b.value) || false;
8651
+ const canRedo = (typeof props.canRedo === "boolean" ? props.canRedo : (_c = props.canRedo) == null ? void 0 : _c.value) || false;
8652
+ const viewState = props.ctx.get(viewMenuStateCtx.key);
8653
+ const maxWidth = editorWidthMap[viewState.editorWidth];
8654
+ const isFull = maxWidth === "none";
8655
+ if (!viewState.fixedToolbarVisible) {
8656
+ return /* @__PURE__ */ vue.h(
8657
+ "button",
8658
+ {
8659
+ type: "button",
8660
+ class: "fixed-toolbar-expand-btn",
8661
+ title: "\u5C55\u5F00\u5DE5\u5177\u680F",
8662
+ onClick: (e) => {
8663
+ e.preventDefault();
8664
+ e.stopPropagation();
8665
+ viewState.fixedToolbarVisible = true;
8666
+ },
8667
+ style: {
8668
+ position: "absolute",
8669
+ top: "0",
8670
+ right: "32px",
8671
+ display: "flex",
8672
+ alignItems: "center",
8673
+ justifyContent: "center",
8674
+ width: "32px",
8675
+ height: "24px",
8676
+ border: "1px solid var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 85%))",
8677
+ borderTop: "none",
8678
+ background: "var(--crepe-color-surface, #ffffff)",
8679
+ cursor: "pointer",
8680
+ borderRadius: "0 0 6px 6px",
8681
+ boxShadow: "0 4px 8px rgba(0, 0, 0, 0.06)",
8682
+ color: "var(--crepe-color-on-surface, #363b4c)",
8683
+ pointerEvents: "auto",
8684
+ zIndex: 200
8685
+ }
8686
+ },
8687
+ /* @__PURE__ */ vue.h(
8688
+ "span",
8689
+ {
8690
+ style: { display: "inline-flex", alignItems: "center" },
8691
+ innerHTML: chevronDownIcon
8692
+ }
8693
+ )
8694
+ );
8695
+ }
8629
8696
  return /* @__PURE__ */ vue.h(
8630
8697
  "div",
8631
8698
  {
8632
8699
  style: {
8700
+ position: "relative",
8701
+ width: "100%",
8702
+ height: "100%",
8633
8703
  display: "flex",
8634
8704
  alignItems: "center",
8635
- justifyContent: "center",
8636
- width: "100%",
8637
- gap: "0px",
8638
- minWidth: "0",
8639
- overflow: "hidden"
8705
+ justifyContent: "center"
8640
8706
  }
8641
8707
  },
8642
- ((_c = props.config) == null ? void 0 : _c.showMenuBar) !== false && [
8643
- /* @__PURE__ */ vue.h(MenuBar, { ctx: props.ctx, config: props.config }),
8644
- /* @__PURE__ */ vue.h(
8645
- "div",
8646
- {
8647
- style: {
8648
- width: "1px",
8649
- minWidth: "1px",
8650
- height: "20px",
8651
- backgroundColor: "var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))"
8652
- }
8708
+ /* @__PURE__ */ vue.h(
8709
+ "div",
8710
+ {
8711
+ style: {
8712
+ display: "flex",
8713
+ alignItems: "center",
8714
+ justifyContent: "center",
8715
+ width: "100%",
8716
+ maxWidth: isFull ? "100%" : maxWidth,
8717
+ margin: isFull ? "0" : "0 auto",
8718
+ gap: "0px",
8719
+ minWidth: "0",
8720
+ overflow: "hidden"
8653
8721
  }
8654
- )
8655
- ],
8656
- ((_d = props.config) == null ? void 0 : _d.showHistory) !== false && [
8657
- /* @__PURE__ */ vue.h(
8658
- "button",
8659
- {
8660
- type: "button",
8661
- class: ["toolbar-item", !canUndo && "disabled"],
8662
- disabled: !canUndo,
8663
- title: "\u64A4\u9500",
8664
- onPointerdown: (e) => {
8665
- e.preventDefault();
8666
- e.stopPropagation();
8667
- },
8668
- onClick: (e) => {
8669
- e.preventDefault();
8670
- e.stopPropagation();
8671
- if (canUndo) {
8672
- props.ctx.get(core.commandsCtx).call("Undo");
8673
- }
8674
- },
8675
- style: {
8676
- display: "flex",
8677
- alignItems: "center",
8678
- justifyContent: "center",
8679
- border: "none",
8680
- background: "transparent",
8681
- cursor: canUndo ? "pointer" : "default",
8682
- padding: "6px",
8683
- borderRadius: "4px",
8684
- color: canUndo ? "#363b4c" : "#c0c4cc",
8685
- "--toolbar-icon-color": canUndo ? "#363b4c" : "#c0c4cc"
8686
- }
8687
- },
8722
+ },
8723
+ ((_d = props.config) == null ? void 0 : _d.showMenuBar) !== false && [
8724
+ /* @__PURE__ */ vue.h(MenuBar, { ctx: props.ctx, config: props.config }),
8688
8725
  /* @__PURE__ */ vue.h(
8689
- "span",
8726
+ "div",
8690
8727
  {
8691
- style: { display: "inline-flex", alignItems: "center" },
8692
- innerHTML: undoIcon
8728
+ style: {
8729
+ width: "1px",
8730
+ minWidth: "1px",
8731
+ height: "20px",
8732
+ backgroundColor: "var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))"
8733
+ }
8693
8734
  }
8694
8735
  )
8695
- ),
8696
- /* @__PURE__ */ vue.h(
8697
- "button",
8698
- {
8699
- type: "button",
8700
- class: ["toolbar-item", !canRedo && "disabled"],
8701
- disabled: !canRedo,
8702
- title: "\u6062\u590D",
8703
- onPointerdown: (e) => {
8704
- e.preventDefault();
8705
- e.stopPropagation();
8736
+ ],
8737
+ ((_e = props.config) == null ? void 0 : _e.showHistory) !== false && [
8738
+ /* @__PURE__ */ vue.h(
8739
+ "button",
8740
+ {
8741
+ type: "button",
8742
+ class: ["toolbar-item", !canUndo && "disabled"],
8743
+ disabled: !canUndo,
8744
+ title: "\u64A4\u9500",
8745
+ onPointerdown: (e) => {
8746
+ e.preventDefault();
8747
+ e.stopPropagation();
8748
+ },
8749
+ onClick: (e) => {
8750
+ e.preventDefault();
8751
+ e.stopPropagation();
8752
+ if (canUndo) {
8753
+ props.ctx.get(core.commandsCtx).call("Undo");
8754
+ }
8755
+ },
8756
+ style: {
8757
+ display: "flex",
8758
+ alignItems: "center",
8759
+ justifyContent: "center",
8760
+ border: "none",
8761
+ background: "transparent",
8762
+ cursor: canUndo ? "pointer" : "default",
8763
+ padding: "6px",
8764
+ borderRadius: "4px",
8765
+ color: canUndo ? "#363b4c" : "#c0c4cc",
8766
+ "--toolbar-icon-color": canUndo ? "#363b4c" : "#c0c4cc"
8767
+ }
8706
8768
  },
8707
- onClick: (e) => {
8708
- e.preventDefault();
8709
- e.stopPropagation();
8710
- if (canRedo) {
8711
- props.ctx.get(core.commandsCtx).call("Redo");
8769
+ /* @__PURE__ */ vue.h(
8770
+ "span",
8771
+ {
8772
+ style: { display: "inline-flex", alignItems: "center" },
8773
+ innerHTML: undoIcon
8774
+ }
8775
+ )
8776
+ ),
8777
+ /* @__PURE__ */ vue.h(
8778
+ "button",
8779
+ {
8780
+ type: "button",
8781
+ class: ["toolbar-item", !canRedo && "disabled"],
8782
+ disabled: !canRedo,
8783
+ title: "\u6062\u590D",
8784
+ onPointerdown: (e) => {
8785
+ e.preventDefault();
8786
+ e.stopPropagation();
8787
+ },
8788
+ onClick: (e) => {
8789
+ e.preventDefault();
8790
+ e.stopPropagation();
8791
+ if (canRedo) {
8792
+ props.ctx.get(core.commandsCtx).call("Redo");
8793
+ }
8794
+ },
8795
+ style: {
8796
+ display: "flex",
8797
+ alignItems: "center",
8798
+ justifyContent: "center",
8799
+ border: "none",
8800
+ background: "transparent",
8801
+ cursor: canRedo ? "pointer" : "default",
8802
+ padding: "6px",
8803
+ borderRadius: "4px",
8804
+ color: canRedo ? "#363b4c" : "#c0c4cc",
8805
+ "--toolbar-icon-color": canRedo ? "#363b4c" : "#c0c4cc"
8712
8806
  }
8713
8807
  },
8714
- style: {
8715
- display: "flex",
8716
- alignItems: "center",
8717
- justifyContent: "center",
8718
- border: "none",
8719
- background: "transparent",
8720
- cursor: canRedo ? "pointer" : "default",
8721
- padding: "6px",
8722
- borderRadius: "4px",
8723
- color: canRedo ? "#363b4c" : "#c0c4cc",
8724
- "--toolbar-icon-color": canRedo ? "#363b4c" : "#c0c4cc"
8725
- }
8726
- },
8808
+ /* @__PURE__ */ vue.h(
8809
+ "span",
8810
+ {
8811
+ style: { display: "inline-flex", alignItems: "center" },
8812
+ innerHTML: redoIcon
8813
+ }
8814
+ )
8815
+ ),
8727
8816
  /* @__PURE__ */ vue.h(
8728
- "span",
8817
+ "div",
8729
8818
  {
8730
- style: { display: "inline-flex", alignItems: "center" },
8731
- innerHTML: redoIcon
8819
+ style: {
8820
+ width: "1px",
8821
+ minWidth: "1px",
8822
+ height: "20px",
8823
+ backgroundColor: "var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))"
8824
+ }
8732
8825
  }
8733
8826
  )
8827
+ ],
8828
+ /* @__PURE__ */ vue.h(
8829
+ Toolbar,
8830
+ {
8831
+ ctx: props.ctx,
8832
+ hide: props.hide,
8833
+ show: props.show,
8834
+ state: props.state,
8835
+ config: props.config,
8836
+ isFixed: true
8837
+ }
8734
8838
  ),
8839
+ showShortcuts.value && /* @__PURE__ */ vue.h(ShortcutHelpModal, { ctx: props.ctx, visible: showShortcuts })
8840
+ ),
8841
+ /* @__PURE__ */ vue.h(
8842
+ "button",
8843
+ {
8844
+ type: "button",
8845
+ class: "toolbar-item collapse-btn",
8846
+ title: "\u6298\u53E0\u5DE5\u5177\u680F",
8847
+ onClick: (e) => {
8848
+ e.preventDefault();
8849
+ e.stopPropagation();
8850
+ viewState.fixedToolbarVisible = false;
8851
+ },
8852
+ style: {
8853
+ position: "absolute",
8854
+ top: "6px",
8855
+ right: "32px",
8856
+ margin: "0",
8857
+ display: "flex",
8858
+ alignItems: "center",
8859
+ justifyContent: "center",
8860
+ pointerEvents: "auto",
8861
+ zIndex: 200
8862
+ }
8863
+ },
8735
8864
  /* @__PURE__ */ vue.h(
8736
- "div",
8865
+ "span",
8737
8866
  {
8738
8867
  style: {
8739
- width: "1px",
8740
- minWidth: "1px",
8741
- height: "20px",
8742
- backgroundColor: "var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))"
8743
- }
8868
+ display: "inline-flex",
8869
+ alignItems: "center",
8870
+ transform: "rotate(180deg)"
8871
+ },
8872
+ innerHTML: chevronDownIcon
8744
8873
  }
8745
8874
  )
8746
- ],
8747
- /* @__PURE__ */ vue.h(
8748
- Toolbar,
8749
- {
8750
- ctx: props.ctx,
8751
- hide: props.hide,
8752
- show: props.show,
8753
- selection: props.selection,
8754
- config: props.config,
8755
- isFixed: true
8756
- }
8757
- ),
8758
- showShortcuts.value && /* @__PURE__ */ vue.h(ShortcutHelpModal, { ctx: props.ctx, visible: showShortcuts })
8875
+ )
8759
8876
  );
8760
8877
  };
8761
8878
  }
@@ -10273,7 +10390,7 @@ const OutlinePanel = vue.defineComponent({
10273
10390
  width: `${state.outlineWidth}px`,
10274
10391
  minWidth: "200px",
10275
10392
  maxWidth: "400px",
10276
- backgroundColor: state.documentBackground || "var(--crepe-color-background)",
10393
+ backgroundColor: "transparent",
10277
10394
  borderRight: isLeft ? "1px solid var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))" : "none",
10278
10395
  borderLeft: !isLeft ? "1px solid var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))" : "none",
10279
10396
  boxSizing: "border-box",
@@ -10474,7 +10591,7 @@ var __accessCheck$4 = (obj, member, msg) => member.has(obj) || __typeError$4("Ca
10474
10591
  var __privateGet$4 = (obj, member, getter) => (__accessCheck$4(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
10475
10592
  var __privateAdd$4 = (obj, member, value) => member.has(obj) ? __typeError$4("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
10476
10593
  var __privateSet$4 = (obj, member, value, setter) => (__accessCheck$4(obj, member, "write to private field"), member.set(obj, value), value);
10477
- var _content$2, _app$2, _headerContent, _headerApp, _outlineContent, _outlineApp, _watcher, _selection$1, _show$1, _canUndo, _canRedo, _resizeObserver$1, _updateOutlineGeometry, _scrollContainers$1, _onDblClick, _view$1, _editorContainer;
10594
+ var _content$2, _app$2, _headerContent, _headerApp, _outlineContent, _outlineApp, _watcher, _state$1, _show$1, _canUndo, _canRedo, _resizeObserver$1, _updateOutlineGeometry, _scrollContainers$1, _onDblClick, _view$1, _editorContainer;
10478
10595
  const fixedToolbarConfig = utils.$ctx(
10479
10596
  {},
10480
10597
  "fixedToolbarConfigCtx"
@@ -10489,7 +10606,7 @@ class FixedToolbarView {
10489
10606
  __privateAdd$4(this, _outlineContent);
10490
10607
  __privateAdd$4(this, _outlineApp);
10491
10608
  __privateAdd$4(this, _watcher);
10492
- __privateAdd$4(this, _selection$1);
10609
+ __privateAdd$4(this, _state$1);
10493
10610
  __privateAdd$4(this, _show$1, vue.ref(true));
10494
10611
  __privateAdd$4(this, _canUndo, vue.ref(false));
10495
10612
  __privateAdd$4(this, _canRedo, vue.ref(false));
@@ -10500,7 +10617,7 @@ class FixedToolbarView {
10500
10617
  __privateAdd$4(this, _view$1);
10501
10618
  __privateAdd$4(this, _editorContainer);
10502
10619
  this.update = (view) => {
10503
- __privateGet$4(this, _selection$1).value = view.state.selection;
10620
+ __privateGet$4(this, _state$1).value = view.state;
10504
10621
  try {
10505
10622
  __privateGet$4(this, _canUndo).value = history.undo(view.state);
10506
10623
  __privateGet$4(this, _canRedo).value = history.redo(view.state);
@@ -10544,6 +10661,10 @@ class FixedToolbarView {
10544
10661
  if ((config == null ? void 0 : config.coverUrl) !== void 0) viewState.coverUrl = config.coverUrl;
10545
10662
  if ((config == null ? void 0 : config.editorWidth) !== void 0)
10546
10663
  viewState.editorWidth = config.editorWidth;
10664
+ if ((config == null ? void 0 : config.showFloatingToolbar) !== void 0)
10665
+ viewState.fixedToolbarVisible = config.showFloatingToolbar;
10666
+ if ((config == null ? void 0 : config.fixedToolbarVisible) !== void 0)
10667
+ viewState.fixedToolbarVisible = config.fixedToolbarVisible;
10547
10668
  if (config == null ? void 0 : config.useLocalStorage) {
10548
10669
  try {
10549
10670
  const stored = localStorage.getItem("jvs-milkdown-data");
@@ -10565,6 +10686,10 @@ class FixedToolbarView {
10565
10686
  viewState.coverUrl = parsed.coverUrl;
10566
10687
  if (parsed.editorWidth !== void 0)
10567
10688
  viewState.editorWidth = parsed.editorWidth;
10689
+ if (parsed.showFloatingToolbar !== void 0)
10690
+ viewState.fixedToolbarVisible = parsed.showFloatingToolbar;
10691
+ if (parsed.fixedToolbarVisible !== void 0)
10692
+ viewState.fixedToolbarVisible = parsed.fixedToolbarVisible;
10568
10693
  }
10569
10694
  } catch (e) {
10570
10695
  console.error("Error loading view state from localStorage:", e);
@@ -10587,7 +10712,8 @@ class FixedToolbarView {
10587
10712
  showTitle: newState.showTitle,
10588
10713
  showCover: newState.showCover,
10589
10714
  coverUrl: newState.coverUrl,
10590
- editorWidth: newState.editorWidth
10715
+ editorWidth: newState.editorWidth,
10716
+ fixedToolbarVisible: newState.fixedToolbarVisible
10591
10717
  };
10592
10718
  localStorage.setItem("jvs-milkdown-data", JSON.stringify(merged));
10593
10719
  } catch (e) {
@@ -10599,14 +10725,14 @@ class FixedToolbarView {
10599
10725
  }
10600
10726
  const content = document.createElement("div");
10601
10727
  content.className = "milkdown-fixed-toolbar";
10602
- __privateSet$4(this, _selection$1, vue.shallowRef(view.state.selection));
10728
+ __privateSet$4(this, _state$1, vue.shallowRef(view.state));
10603
10729
  const app = vue.createApp(FixedToolbarComponent, {
10604
10730
  ctx,
10605
10731
  hide: () => {
10606
10732
  },
10607
10733
  // No-op for fixed toolbar
10608
10734
  config,
10609
- selection: __privateGet$4(this, _selection$1),
10735
+ state: __privateGet$4(this, _state$1),
10610
10736
  show: __privateGet$4(this, _show$1),
10611
10737
  canUndo: __privateGet$4(this, _canUndo),
10612
10738
  canRedo: __privateGet$4(this, _canRedo)
@@ -10750,13 +10876,20 @@ class FixedToolbarView {
10750
10876
  viewState2.outlineWidth,
10751
10877
  viewState2.documentBackground,
10752
10878
  viewState2.showCover,
10753
- viewState2.editorWidth
10879
+ viewState2.editorWidth,
10880
+ viewState2.fixedToolbarVisible
10754
10881
  ],
10755
10882
  () => {
10883
+ if (viewState2.fixedToolbarVisible === false) {
10884
+ __privateGet$4(this, _content$2).classList.add("collapsed");
10885
+ } else {
10886
+ __privateGet$4(this, _content$2).classList.remove("collapsed");
10887
+ }
10888
+ root.style.backgroundColor = "";
10756
10889
  if (viewState2.documentBackground) {
10757
- root.style.backgroundColor = viewState2.documentBackground;
10890
+ __privateGet$4(this, _view$1).dom.style.backgroundColor = viewState2.documentBackground;
10758
10891
  } else {
10759
- root.style.backgroundColor = "";
10892
+ __privateGet$4(this, _view$1).dom.style.backgroundColor = "";
10760
10893
  }
10761
10894
  root.style.paddingLeft = "0";
10762
10895
  root.style.paddingRight = "0";
@@ -10779,7 +10912,7 @@ class FixedToolbarView {
10779
10912
  }
10780
10913
  const maxWidth = editorWidthMap[viewState2.editorWidth];
10781
10914
  const isFull = maxWidth === "none";
10782
- const px = isFull ? "80px" : "0";
10915
+ const px = isFull ? "80px" : "10px";
10783
10916
  __privateGet$4(this, _view$1).dom.style.maxWidth = maxWidth;
10784
10917
  __privateGet$4(this, _view$1).dom.style.width = isFull ? "100%" : maxWidth;
10785
10918
  __privateGet$4(this, _view$1).dom.style.margin = isFull ? "0" : "0 auto";
@@ -10809,7 +10942,7 @@ _headerApp = new WeakMap();
10809
10942
  _outlineContent = new WeakMap();
10810
10943
  _outlineApp = new WeakMap();
10811
10944
  _watcher = new WeakMap();
10812
- _selection$1 = new WeakMap();
10945
+ _state$1 = new WeakMap();
10813
10946
  _show$1 = new WeakMap();
10814
10947
  _canUndo = new WeakMap();
10815
10948
  _canRedo = new WeakMap();
@@ -10841,7 +10974,7 @@ const fixedToolbar = (editor, config) => {
10841
10974
  ...prev,
10842
10975
  ...mergedConfig
10843
10976
  }));
10844
- }).use(viewMenuStateCtx).use(fixedToolbarConfig).use(underline).use(highlightMark).use(fixedToolbarPlugin);
10977
+ }).use(viewMenuStateCtx).use(fixedToolbarConfig).use(underline).use(highlightMark).use(colorPlugins).use(fontPlugins).use(fixedToolbarPlugin);
10845
10978
  };
10846
10979
 
10847
10980
  const imageBlock = (editor, config) => {
@@ -12331,21 +12464,21 @@ var __accessCheck$1 = (obj, member, msg) => member.has(obj) || __typeError$1("Ca
12331
12464
  var __privateGet$1 = (obj, member, getter) => (__accessCheck$1(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
12332
12465
  var __privateAdd$1 = (obj, member, value) => member.has(obj) ? __typeError$1("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
12333
12466
  var __privateSet$1 = (obj, member, value, setter) => (__accessCheck$1(obj, member, "write to private field"), member.set(obj, value), value);
12334
- var _tooltipProvider, _content, _app, _selection, _show, _mousePressed, _removePopupListener, _onDocumentMouseUp;
12467
+ var _tooltipProvider, _content, _app, _state, _show, _mousePressed, _removePopupListener, _onDocumentMouseUp;
12335
12468
  const toolbarTooltip = tooltip.tooltipFactory("CREPE_TOOLBAR");
12336
12469
  class ToolbarView {
12337
12470
  constructor(ctx, view, config) {
12338
12471
  __privateAdd$1(this, _tooltipProvider);
12339
12472
  __privateAdd$1(this, _content);
12340
12473
  __privateAdd$1(this, _app);
12341
- __privateAdd$1(this, _selection);
12474
+ __privateAdd$1(this, _state);
12342
12475
  __privateAdd$1(this, _show, vue.ref(false));
12343
12476
  __privateAdd$1(this, _mousePressed, false);
12344
12477
  __privateAdd$1(this, _removePopupListener);
12345
12478
  __privateAdd$1(this, _onDocumentMouseUp);
12346
12479
  this.update = (view, prevState) => {
12347
12480
  __privateGet$1(this, _tooltipProvider).update(view, prevState);
12348
- __privateGet$1(this, _selection).value = view.state.selection;
12481
+ __privateGet$1(this, _state).value = view.state;
12349
12482
  };
12350
12483
  this.destroy = () => {
12351
12484
  var _a;
@@ -12362,12 +12495,12 @@ class ToolbarView {
12362
12495
  };
12363
12496
  const content = document.createElement("div");
12364
12497
  content.className = "milkdown-toolbar";
12365
- __privateSet$1(this, _selection, vue.shallowRef(view.state.selection));
12498
+ __privateSet$1(this, _state, vue.shallowRef(view.state));
12366
12499
  const app = vue.createApp(Toolbar, {
12367
12500
  ctx,
12368
12501
  hide: this.hide,
12369
12502
  config,
12370
- selection: __privateGet$1(this, _selection),
12503
+ state: __privateGet$1(this, _state),
12371
12504
  show: __privateGet$1(this, _show)
12372
12505
  });
12373
12506
  app.mount(content);
@@ -12431,7 +12564,7 @@ class ToolbarView {
12431
12564
  _tooltipProvider = new WeakMap();
12432
12565
  _content = new WeakMap();
12433
12566
  _app = new WeakMap();
12434
- _selection = new WeakMap();
12567
+ _state = new WeakMap();
12435
12568
  _show = new WeakMap();
12436
12569
  _mousePressed = new WeakMap();
12437
12570
  _removePopupListener = new WeakMap();