@jvs-milkdown/crepe 1.2.15 → 1.2.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/cjs/index.js CHANGED
@@ -3092,27 +3092,39 @@ const Menu = vue.defineComponent({
3092
3092
  let activeTextColor = null;
3093
3093
  let activeBgColor = null;
3094
3094
  if (node && node.nodeSize > 2) {
3095
- node.descendants((childNode) => {
3096
- if (childNode.isText) {
3097
- const tcType = textColorSchema.type(ctx);
3098
- const bcType = bgColorSchema.type(ctx);
3099
- if (!activeTextColor) {
3100
- const tcMark = childNode.marks.find((m) => m.type === tcType);
3101
- if (tcMark) activeTextColor = tcMark.attrs.color;
3102
- }
3103
- if (!activeBgColor) {
3104
- const bcMark = childNode.marks.find((m) => m.type === bcType);
3105
- if (bcMark) activeBgColor = bcMark.attrs.color;
3095
+ const schema = ctx.get(core.schemaCtx);
3096
+ const tcHasMark = schema.marks[textColorSchema.id];
3097
+ const bcHasMark = schema.marks[bgColorSchema.id];
3098
+ if (tcHasMark || bcHasMark) {
3099
+ node.descendants((childNode) => {
3100
+ if (childNode.isText) {
3101
+ if (tcHasMark && !activeTextColor) {
3102
+ const tcType = textColorSchema.type(ctx);
3103
+ const tcMark = childNode.marks.find(
3104
+ (m) => m.type === tcType
3105
+ );
3106
+ if (tcMark) activeTextColor = tcMark.attrs.color;
3107
+ }
3108
+ if (bcHasMark && !activeBgColor) {
3109
+ const bcType = bgColorSchema.type(ctx);
3110
+ const bcMark = childNode.marks.find(
3111
+ (m) => m.type === bcType
3112
+ );
3113
+ if (bcMark) activeBgColor = bcMark.attrs.color;
3114
+ }
3106
3115
  }
3107
- }
3108
- return false;
3109
- });
3116
+ return false;
3117
+ });
3118
+ }
3110
3119
  }
3111
3120
  const setBlockColor = (colorValue, isBg) => {
3112
3121
  if (pos === null || pos === void 0) return;
3113
3122
  const { tr } = view.state;
3114
3123
  const targetNode = tr.doc.nodeAt(pos);
3115
3124
  if (!targetNode) return;
3125
+ const schema = ctx.get(core.schemaCtx);
3126
+ const hasMark = isBg ? schema.marks[bgColorSchema.id] : schema.marks[textColorSchema.id];
3127
+ if (!hasMark) return;
3116
3128
  const markType = isBg ? bgColorSchema.type(ctx) : textColorSchema.type(ctx);
3117
3129
  const start = pos + 1;
3118
3130
  const end = pos + targetNode.nodeSize - 1;
@@ -3131,10 +3143,17 @@ const Menu = vue.defineComponent({
3131
3143
  const { tr } = view.state;
3132
3144
  const targetNode = tr.doc.nodeAt(pos);
3133
3145
  if (!targetNode) return;
3146
+ const schema = ctx.get(core.schemaCtx);
3147
+ const tcHasMark = schema.marks[textColorSchema.id];
3148
+ const bcHasMark = schema.marks[bgColorSchema.id];
3134
3149
  const start = pos + 1;
3135
3150
  const end = pos + targetNode.nodeSize - 1;
3136
- tr.removeMark(start, end, textColorSchema.type(ctx));
3137
- tr.removeMark(start, end, bgColorSchema.type(ctx));
3151
+ if (tcHasMark) {
3152
+ tr.removeMark(start, end, textColorSchema.type(ctx));
3153
+ }
3154
+ if (bcHasMark) {
3155
+ tr.removeMark(start, end, bgColorSchema.type(ctx));
3156
+ }
3138
3157
  view.dispatch(tr);
3139
3158
  showColorMenu.value = false;
3140
3159
  hide();
@@ -6165,6 +6184,10 @@ const Toolbar = vue.defineComponent({
6165
6184
  return { textColor: null, bgColor: null };
6166
6185
  const view = ctx.get(core.editorViewCtx);
6167
6186
  const { state } = view;
6187
+ const schema = ctx.get(core.schemaCtx);
6188
+ const tcHasMark = schema.marks[textColorSchema.id];
6189
+ const bcHasMark = schema.marks[bgColorSchema.id];
6190
+ if (!tcHasMark || !bcHasMark) return { textColor: null, bgColor: null };
6168
6191
  const tcType = textColorSchema.type(ctx);
6169
6192
  const bcType = bgColorSchema.type(ctx);
6170
6193
  const { $cursor, ranges } = state.selection;
@@ -6209,6 +6232,10 @@ const Toolbar = vue.defineComponent({
6209
6232
  const { state, dispatch } = view;
6210
6233
  const { tr } = state;
6211
6234
  const { from, to, empty } = state.selection;
6235
+ const schema = ctx.get(core.schemaCtx);
6236
+ const tcHasMark = schema.marks[textColorSchema.id];
6237
+ const bcHasMark = schema.marks[bgColorSchema.id];
6238
+ if (!tcHasMark || !bcHasMark) return;
6212
6239
  const textColorType = textColorSchema.type(ctx);
6213
6240
  const bgColorType = bgColorSchema.type(ctx);
6214
6241
  if (empty) {
@@ -6230,6 +6257,10 @@ const Toolbar = vue.defineComponent({
6230
6257
  return { fontFamily: null, fontSize: null };
6231
6258
  const view = ctx.get(core.editorViewCtx);
6232
6259
  const { state } = view;
6260
+ const schema = ctx.get(core.schemaCtx);
6261
+ const ffHasMark = schema.marks[fontFamilySchema.id];
6262
+ const fsHasMark = schema.marks[fontSizeSchema.id];
6263
+ if (!ffHasMark || !fsHasMark) return { fontFamily: null, fontSize: null };
6233
6264
  const ffType = fontFamilySchema.type(ctx);
6234
6265
  const fsType = fontSizeSchema.type(ctx);
6235
6266
  const { $cursor, ranges } = state.selection;
@@ -9205,6 +9236,11 @@ const OutlinePanel = vue.defineComponent({
9205
9236
  const activeId = vue.ref("");
9206
9237
  const collapsedIds = vue.ref(/* @__PURE__ */ new Set());
9207
9238
  let scrollLock = false;
9239
+ const clickedActiveId = vue.ref(null);
9240
+ const clearClickedActive = () => {
9241
+ if (scrollLock) return;
9242
+ clickedActiveId.value = null;
9243
+ };
9208
9244
  const hasChildren = (index) => {
9209
9245
  const current = items.value[index];
9210
9246
  if (!current) return false;
@@ -9259,6 +9295,10 @@ const OutlinePanel = vue.defineComponent({
9259
9295
  if (scrollLock) return;
9260
9296
  const view = props.ctx.get(core.editorViewCtx);
9261
9297
  if (!view || !view.dom) return;
9298
+ if (clickedActiveId.value) {
9299
+ activeId.value = clickedActiveId.value;
9300
+ return;
9301
+ }
9262
9302
  const headings = Array.from(
9263
9303
  view.dom.querySelectorAll("h1, h2, h3, h4, h5, h6")
9264
9304
  );
@@ -9266,14 +9306,39 @@ const OutlinePanel = vue.defineComponent({
9266
9306
  activeId.value = "";
9267
9307
  return;
9268
9308
  }
9269
- const scrollContainer = view.dom.parentElement;
9270
- if (!scrollContainer) return;
9271
- const toolbar = scrollContainer.querySelector(
9309
+ let scrollContainer = view.dom.parentElement;
9310
+ while (scrollContainer && scrollContainer !== document.body) {
9311
+ const style = window.getComputedStyle(scrollContainer);
9312
+ const overflowY = style.overflowY;
9313
+ if ((overflowY === "auto" || overflowY === "scroll") && scrollContainer.scrollHeight > scrollContainer.clientHeight) {
9314
+ break;
9315
+ }
9316
+ scrollContainer = scrollContainer.parentElement;
9317
+ }
9318
+ const isRootScroll = !scrollContainer || scrollContainer === document.body || scrollContainer === document.documentElement;
9319
+ const actualScrollContainer = isRootScroll ? document.scrollingElement || document.documentElement || document.body : scrollContainer;
9320
+ const rootNode = view.dom.getRootNode();
9321
+ let toolbar = rootNode.querySelector(
9272
9322
  ".milkdown-fixed-toolbar"
9273
9323
  );
9324
+ if (!toolbar) {
9325
+ toolbar = document.querySelector(
9326
+ ".milkdown-fixed-toolbar"
9327
+ );
9328
+ }
9274
9329
  const toolbarHeight = (toolbar == null ? void 0 : toolbar.offsetHeight) || 0;
9275
- const containerRect = scrollContainer.getBoundingClientRect();
9276
- const threshold = containerRect.top + toolbarHeight + 50;
9330
+ const containerRect = actualScrollContainer.getBoundingClientRect();
9331
+ const containerTop = isRootScroll ? 0 : Math.max(0, containerRect.top);
9332
+ let scrollTop = actualScrollContainer.scrollTop;
9333
+ let clientHeight = actualScrollContainer.clientHeight;
9334
+ let scrollHeight = actualScrollContainer.scrollHeight;
9335
+ if (isRootScroll) {
9336
+ scrollTop = window.scrollY || document.documentElement.scrollTop;
9337
+ clientHeight = window.innerHeight || document.documentElement.clientHeight;
9338
+ scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
9339
+ }
9340
+ const isAtBottom = scrollTop + clientHeight >= scrollHeight - 15;
9341
+ const threshold = isAtBottom ? containerTop + clientHeight : containerTop + toolbarHeight + 50;
9277
9342
  let active = headings[0];
9278
9343
  for (const h2 of headings) {
9279
9344
  const rect = h2.getBoundingClientRect();
@@ -9283,43 +9348,120 @@ const OutlinePanel = vue.defineComponent({
9283
9348
  break;
9284
9349
  }
9285
9350
  }
9286
- activeId.value = (active == null ? void 0 : active.id) || "";
9351
+ const activeItem = items.value.find((item) => {
9352
+ try {
9353
+ const activePos = view.posAtDOM(active, 0);
9354
+ const isPosMatch = item.pos === activePos - 1;
9355
+ let isDepthMatch = false;
9356
+ const $pos = view.state.doc.resolve(activePos);
9357
+ for (let d = $pos.depth; d >= 0; d--) {
9358
+ if ($pos.node(d).type.name === "heading") {
9359
+ if (item.pos === $pos.before(d)) {
9360
+ isDepthMatch = true;
9361
+ break;
9362
+ }
9363
+ }
9364
+ }
9365
+ if (isPosMatch || isDepthMatch) {
9366
+ return true;
9367
+ }
9368
+ } catch (e) {
9369
+ }
9370
+ const dom = view.nodeDOM(item.pos);
9371
+ const domMatch = dom === active || dom instanceof HTMLElement && active && dom.contains(active);
9372
+ if (domMatch) {
9373
+ return true;
9374
+ }
9375
+ return false;
9376
+ });
9377
+ const newActiveId = activeItem ? activeItem.id : (active == null ? void 0 : active.id) || "";
9378
+ activeId.value = newActiveId;
9287
9379
  };
9288
- const scrollToHeading = (id) => {
9380
+ const scrollToHeading = (item) => {
9289
9381
  const view = props.ctx.get(core.editorViewCtx);
9290
9382
  if (!view) return;
9291
9383
  try {
9292
- const headingEl = view.dom.querySelector(
9293
- `[id="${id}"]`
9294
- );
9384
+ let headingEl = view.nodeDOM(item.pos);
9385
+ if (!headingEl) {
9386
+ try {
9387
+ const domAt = view.domAtPos(item.pos);
9388
+ let node = domAt.node;
9389
+ if (node.nodeType === Node.TEXT_NODE) {
9390
+ node = node.parentElement;
9391
+ }
9392
+ if (node instanceof HTMLElement) {
9393
+ headingEl = node.closest(
9394
+ "h1, h2, h3, h4, h5, h6"
9395
+ );
9396
+ if (!headingEl && domAt.offset < node.childNodes.length) {
9397
+ const child = node.childNodes[domAt.offset];
9398
+ if (child instanceof HTMLElement) {
9399
+ headingEl = child.closest("h1, h2, h3, h4, h5, h6") || child.querySelector(
9400
+ "h1, h2, h3, h4, h5, h6"
9401
+ );
9402
+ }
9403
+ }
9404
+ }
9405
+ } catch (e) {
9406
+ }
9407
+ }
9408
+ if (!headingEl) {
9409
+ headingEl = view.dom.querySelector(
9410
+ `[id="${item.id}"]`
9411
+ );
9412
+ }
9295
9413
  if (!headingEl) return;
9296
- const scrollContainer = view.dom.parentElement;
9297
- if (!scrollContainer) return;
9414
+ let scrollContainer = view.dom.parentElement;
9415
+ while (scrollContainer && scrollContainer !== document.body) {
9416
+ const style = window.getComputedStyle(scrollContainer);
9417
+ const overflowY = style.overflowY;
9418
+ if ((overflowY === "auto" || overflowY === "scroll") && scrollContainer.scrollHeight > scrollContainer.clientHeight) {
9419
+ break;
9420
+ }
9421
+ scrollContainer = scrollContainer.parentElement;
9422
+ }
9423
+ const isRootScroll = !scrollContainer || scrollContainer === document.body || scrollContainer === document.documentElement;
9424
+ const actualScrollContainer = isRootScroll ? document.scrollingElement || document.documentElement || document.body : scrollContainer;
9298
9425
  scrollLock = true;
9299
- const toolbar = scrollContainer.querySelector(
9426
+ const rootNode = view.dom.getRootNode();
9427
+ let toolbar = rootNode.querySelector(
9300
9428
  ".milkdown-fixed-toolbar"
9301
9429
  );
9430
+ if (!toolbar) {
9431
+ toolbar = document.querySelector(
9432
+ ".milkdown-fixed-toolbar"
9433
+ );
9434
+ }
9302
9435
  const toolbarHeight = (toolbar == null ? void 0 : toolbar.offsetHeight) || 0;
9303
- const containerRect = scrollContainer.getBoundingClientRect();
9436
+ const containerRectTop = isRootScroll ? 0 : actualScrollContainer.getBoundingClientRect().top;
9304
9437
  const headingRect = headingEl.getBoundingClientRect();
9305
- scrollContainer.scrollTo({
9306
- top: scrollContainer.scrollTop + headingRect.top - containerRect.top - toolbarHeight - 20,
9307
- behavior: "smooth"
9308
- });
9438
+ const targetTop = actualScrollContainer.scrollTop + headingRect.top - containerRectTop - toolbarHeight - 20;
9439
+ const scrollTarget = isRootScroll ? window : actualScrollContainer;
9309
9440
  let timer;
9310
9441
  const onScrollEnd = () => {
9311
9442
  clearTimeout(timer);
9312
9443
  timer = setTimeout(() => {
9313
9444
  scrollLock = false;
9314
- scrollContainer.removeEventListener("scroll", onScrollEnd);
9445
+ scrollTarget.removeEventListener("scroll", onScrollEnd);
9315
9446
  checkActive();
9316
9447
  }, 150);
9317
9448
  };
9318
- scrollContainer.addEventListener("scroll", onScrollEnd);
9449
+ scrollTarget.addEventListener("scroll", onScrollEnd);
9319
9450
  setTimeout(() => {
9320
9451
  scrollLock = false;
9321
- scrollContainer.removeEventListener("scroll", onScrollEnd);
9452
+ scrollTarget.removeEventListener("scroll", onScrollEnd);
9322
9453
  }, 2e3);
9454
+ if (isRootScroll) {
9455
+ window.scrollTo({
9456
+ top: targetTop,
9457
+ behavior: "smooth"
9458
+ });
9459
+ } else {
9460
+ actualScrollContainer.scrollTo({
9461
+ top: targetTop,
9462
+ behavior: "smooth"
9463
+ });
9464
+ }
9323
9465
  } catch (e) {
9324
9466
  scrollLock = false;
9325
9467
  updateOutline();
@@ -9330,6 +9472,27 @@ const OutlinePanel = vue.defineComponent({
9330
9472
  vue.onMounted(() => {
9331
9473
  updateOutline();
9332
9474
  checkActive();
9475
+ window.addEventListener("wheel", clearClickedActive, { passive: true });
9476
+ window.addEventListener("touchmove", clearClickedActive, {
9477
+ passive: true
9478
+ });
9479
+ window.addEventListener("pointerdown", clearClickedActive, {
9480
+ passive: true
9481
+ });
9482
+ const keyHandler = (e) => {
9483
+ if ([
9484
+ "ArrowUp",
9485
+ "ArrowDown",
9486
+ "PageUp",
9487
+ "PageDown",
9488
+ "Home",
9489
+ "End"
9490
+ ].includes(e.key)) {
9491
+ clearClickedActive();
9492
+ }
9493
+ };
9494
+ window.addEventListener("keydown", keyHandler, { passive: true });
9495
+ vue.onMounted._keyHandler = keyHandler;
9333
9496
  interval = setInterval(() => {
9334
9497
  if (viewState.value.outlineVisible) {
9335
9498
  updateOutline();
@@ -9346,6 +9509,13 @@ const OutlinePanel = vue.defineComponent({
9346
9509
  if (interval) clearInterval(interval);
9347
9510
  if (pollInterval) clearInterval(pollInterval);
9348
9511
  window.removeEventListener("scroll", checkActive, true);
9512
+ window.removeEventListener("wheel", clearClickedActive);
9513
+ window.removeEventListener("touchmove", clearClickedActive);
9514
+ window.removeEventListener("pointerdown", clearClickedActive);
9515
+ const keyHandler = vue.onMounted._keyHandler;
9516
+ if (keyHandler) {
9517
+ window.removeEventListener("keydown", keyHandler);
9518
+ }
9349
9519
  });
9350
9520
  let startX = 0;
9351
9521
  let startWidth = 0;
@@ -9473,7 +9643,8 @@ const OutlinePanel = vue.defineComponent({
9473
9643
  key: item.id,
9474
9644
  onClick: () => {
9475
9645
  activeId.value = item.id;
9476
- scrollToHeading(item.id);
9646
+ clickedActiveId.value = item.id;
9647
+ scrollToHeading(item);
9477
9648
  },
9478
9649
  style: {
9479
9650
  display: "flex",
@@ -9530,7 +9701,7 @@ const OutlinePanel = vue.defineComponent({
9530
9701
  e.currentTarget.style.backgroundColor = "transparent";
9531
9702
  }
9532
9703
  },
9533
- "\uFFFD?",
9704
+ "\u25BC",
9534
9705
  " "
9535
9706
  ),
9536
9707
  /* @__PURE__ */ vue.h(