vuepress-plugin-md-power 1.0.0-rc.170 → 1.0.0-rc.172

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.
@@ -0,0 +1,4 @@
1
+ //#region src/client/composables/mark.d.ts
2
+ declare function setupMarkHighlight(mode: 'lazy' | 'eager'): void;
3
+ //#endregion
4
+ export { setupMarkHighlight };
@@ -0,0 +1,108 @@
1
+ import { onBeforeUnmount, onMounted } from "vue";
2
+ import { onContentUpdated, useRouter } from "vuepress/client";
3
+
4
+ //#region src/client/composables/mark.ts
5
+ const MARK_MODE_ATTR = "data-mark-mode";
6
+ const MARK_MODE_LAZY = "lazy";
7
+ const MARK_VISIBLE_CLASS = "vp-mark-visible";
8
+ const MARK_BOUND_ATTR = "data-vp-mark-bound";
9
+ const MARK_SELECTOR = ".vp-doc mark";
10
+ const DOC_SELECTOR = ".vp-doc";
11
+ const BOUND_SELECTOR = `${MARK_SELECTOR}[${MARK_BOUND_ATTR}="1"]`;
12
+ function setupMarkHighlight(mode) {
13
+ if (typeof window === "undefined" || __VUEPRESS_SSR__) return;
14
+ const root = document.documentElement;
15
+ if (mode !== MARK_MODE_LAZY) {
16
+ root.removeAttribute(MARK_MODE_ATTR);
17
+ return;
18
+ }
19
+ root.setAttribute(MARK_MODE_ATTR, MARK_MODE_LAZY);
20
+ let intersectionObserver = null;
21
+ let mutationObserver = null;
22
+ let rafId = null;
23
+ let removeAfterEach = null;
24
+ const ensureObserver = () => {
25
+ if (!intersectionObserver) intersectionObserver = new IntersectionObserver((entries, obs) => {
26
+ for (const entry of entries) {
27
+ if (!entry.isIntersecting && entry.intersectionRatio <= 0) continue;
28
+ const target = entry.target;
29
+ target.classList.add(MARK_VISIBLE_CLASS);
30
+ target.removeAttribute(MARK_BOUND_ATTR);
31
+ obs.unobserve(target);
32
+ }
33
+ }, {
34
+ threshold: [
35
+ 0,
36
+ .1,
37
+ .25,
38
+ .5
39
+ ],
40
+ rootMargin: "8% 0px -8% 0px"
41
+ });
42
+ return intersectionObserver;
43
+ };
44
+ const bindMarks = () => {
45
+ const marks = Array.from(document.querySelectorAll(MARK_SELECTOR)).filter((mark) => mark instanceof HTMLElement && !mark.classList.contains(MARK_VISIBLE_CLASS) && mark.getAttribute(MARK_BOUND_ATTR) !== "1");
46
+ if (marks.length === 0) return;
47
+ const observer = ensureObserver();
48
+ for (const mark of marks) {
49
+ mark.setAttribute(MARK_BOUND_ATTR, "1");
50
+ observer.observe(mark);
51
+ }
52
+ };
53
+ const scheduleBind = () => {
54
+ if (rafId !== null) cancelAnimationFrame(rafId);
55
+ rafId = requestAnimationFrame(() => {
56
+ rafId = null;
57
+ bindMarks();
58
+ });
59
+ };
60
+ const observeDocMutations = () => {
61
+ const doc = document.querySelector(DOC_SELECTOR);
62
+ if (!doc) return;
63
+ if (mutationObserver) mutationObserver.disconnect();
64
+ mutationObserver = new MutationObserver((mutations) => {
65
+ if (mutations.some((mutation) => mutation.addedNodes.length > 0)) scheduleBind();
66
+ });
67
+ mutationObserver.observe(doc, {
68
+ childList: true,
69
+ subtree: true
70
+ });
71
+ };
72
+ const resetObserver = () => {
73
+ document.querySelectorAll(BOUND_SELECTOR).forEach((mark) => {
74
+ if (!mark.classList.contains(MARK_VISIBLE_CLASS)) mark.removeAttribute(MARK_BOUND_ATTR);
75
+ });
76
+ if (intersectionObserver) {
77
+ intersectionObserver.disconnect();
78
+ intersectionObserver = null;
79
+ }
80
+ };
81
+ const router = useRouter();
82
+ onMounted(() => {
83
+ observeDocMutations();
84
+ scheduleBind();
85
+ });
86
+ onContentUpdated(() => {
87
+ resetObserver();
88
+ observeDocMutations();
89
+ scheduleBind();
90
+ });
91
+ if (router?.afterEach) removeAfterEach = router.afterEach(() => {
92
+ resetObserver();
93
+ observeDocMutations();
94
+ scheduleBind();
95
+ });
96
+ if (router?.isReady) router.isReady().then(() => scheduleBind()).catch(() => {});
97
+ onBeforeUnmount(() => {
98
+ if (rafId !== null) cancelAnimationFrame(rafId);
99
+ resetObserver();
100
+ mutationObserver?.disconnect();
101
+ mutationObserver = null;
102
+ removeAfterEach?.();
103
+ removeAfterEach = null;
104
+ });
105
+ }
106
+
107
+ //#endregion
108
+ export { setupMarkHighlight };
@@ -1,6 +1,6 @@
1
1
  import { ensureEndingSlash, isLinkHttp } from "vuepress/shared";
2
- import { isMobile, isSafari, isiPad } from "@vuepress/helper/client";
3
2
  import { withBase } from "vuepress/client";
3
+ import { isMobile, isSafari, isiPad } from "@vuepress/helper/client";
4
4
  import { pluginOptions } from "../options.js";
5
5
 
6
6
  //#region src/client/composables/pdf.ts
@@ -210,6 +210,9 @@ interface CodeTreeOptions {
210
210
  height?: string | number;
211
211
  }
212
212
  //#endregion
213
+ //#region src/shared/mark.d.ts
214
+ type MarkOptions = 'lazy' | 'eager';
215
+ //#endregion
213
216
  //#region src/shared/repl.d.ts
214
217
  type ThemeOptions = BuiltinTheme | {
215
218
  light: BuiltinTheme;
@@ -279,6 +282,11 @@ interface MarkdownPowerPluginOptions {
279
282
  * @default false
280
283
  */
281
284
  abbr?: boolean;
285
+ /**
286
+ * 马克笔动画模式
287
+ * @default 'eager'
288
+ */
289
+ mark?: MarkOptions;
282
290
  /**
283
291
  * 配置代码块分组
284
292
  */
package/lib/node/index.js CHANGED
@@ -6,9 +6,8 @@ import http from "node:https";
6
6
  import { URL, URLSearchParams } from "node:url";
7
7
  import { camelCase, isBoolean, isEmptyObject, isNull, isNumber, isPlainObject as isPlainObject$1, isString, isUndefined, kebabCase, notNullish, omit, toArray, uniqueBy, withTimeout } from "@pengzhanbo/utils";
8
8
  import imageSize from "image-size";
9
- import { colors, fs, getDirname, logger, ora, path } from "vuepress/utils";
9
+ import { colors, fs, getDirname, logger, ora, path, tinyglobby } from "vuepress/utils";
10
10
  import path$1 from "node:path";
11
- import { globSync } from "tinyglobby";
12
11
  import { isLinkHttp as isLinkHttp$1, isLinkWithProtocol, removeEndingSlash, removeLeadingSlash } from "vuepress/shared";
13
12
  import fs$1, { promises } from "node:fs";
14
13
  import process from "node:process";
@@ -1474,7 +1473,7 @@ function codeTreePlugin(md, app, options = {}) {
1474
1473
  content: ({ dir, icon,...props }, _, env) => {
1475
1474
  const codeTreeFiles = env.codeTreeFiles ??= [];
1476
1475
  const root = findFile(app, env, dir);
1477
- const files = globSync("**/*", {
1476
+ const files = tinyglobby.globSync("**/*", {
1478
1477
  cwd: root,
1479
1478
  onlyFiles: true,
1480
1479
  dot: true,
@@ -3961,7 +3960,7 @@ const iconPlugin = (md, options = {}) => {
3961
3960
  //#endregion
3962
3961
  //#region src/node/icon/prepareIcon.ts
3963
3962
  function getFontAwesomeCDNLink(type) {
3964
- return `https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6/js/${type}.min.js`;
3963
+ return `https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/js/${type}.min.js`;
3965
3964
  }
3966
3965
  function prepareIcon(imports, options = {}) {
3967
3966
  const setupContent = [];
@@ -3974,7 +3973,7 @@ function prepareIcon(imports, options = {}) {
3974
3973
  "fontawesome"
3975
3974
  ].map(getFontAwesomeCDNLink).map((asset$1) => normalizeAsset(asset$1, "fontawesome"));
3976
3975
  if (asset === "fontawesome-with-brands") return normalizeAsset(getFontAwesomeCDNLink("brands"), "fontawesome");
3977
- return null;
3976
+ return normalizeAsset(asset, "fontawesome");
3978
3977
  }).flat().filter(notNullish));
3979
3978
  let hasStyle = false;
3980
3979
  let hasScript = false;
@@ -4331,6 +4330,13 @@ async function prepareConfigFile(app, options) {
4331
4330
  enhances.add(`app.component('VPTable', VPTable)`);
4332
4331
  }
4333
4332
  const setupIcon = prepareIcon(imports, options.icon);
4333
+ const setupStmts = [];
4334
+ const iconSetup = setupIcon.trim();
4335
+ if (iconSetup) setupStmts.push(iconSetup);
4336
+ const markMode = options.mark === "lazy" ? "lazy" : "eager";
4337
+ imports.add(`import { setupMarkHighlight } from '${CLIENT_FOLDER}composables/mark.js'`);
4338
+ setupStmts.push(`setupMarkHighlight(${JSON.stringify(markMode)})`);
4339
+ const setupContent = setupStmts.length ? ` ${setupStmts.join("\n ")}\n` : "";
4334
4340
  return app.writeTemp("md-power/config.js", `\
4335
4341
  import { defineClientConfig } from 'vuepress/client'
4336
4342
  ${Array.from(imports.values()).join("\n")}
@@ -4342,7 +4348,7 @@ export default defineClientConfig({
4342
4348
  ${Array.from(enhances.values()).map((item) => ` ${item}`).join("\n")}
4343
4349
  },
4344
4350
  setup() {
4345
- ${setupIcon}
4351
+ ${setupContent}
4346
4352
  }
4347
4353
  })
4348
4354
  `);
@@ -208,6 +208,9 @@ interface CodeTreeOptions {
208
208
  height?: string | number;
209
209
  }
210
210
  //#endregion
211
+ //#region src/shared/mark.d.ts
212
+ type MarkOptions = 'lazy' | 'eager';
213
+ //#endregion
211
214
  //#region src/shared/repl.d.ts
212
215
  type ThemeOptions = BuiltinTheme | {
213
216
  light: BuiltinTheme;
@@ -277,6 +280,11 @@ interface MarkdownPowerPluginOptions {
277
280
  * @default false
278
281
  */
279
282
  abbr?: boolean;
283
+ /**
284
+ * 马克笔动画模式
285
+ * @default 'eager'
286
+ */
287
+ mark?: MarkOptions;
280
288
  /**
281
289
  * 配置代码块分组
282
290
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vuepress-plugin-md-power",
3
3
  "type": "module",
4
- "version": "1.0.0-rc.170",
4
+ "version": "1.0.0-rc.172",
5
5
  "description": "The Plugin for VuePress 2 - markdown power",
6
6
  "author": "pengzhanbo <volodymyr@foxmail.com>",
7
7
  "license": "MIT",
@@ -33,7 +33,7 @@
33
33
  "peerDependencies": {
34
34
  "artplayer": "^5.3.0",
35
35
  "dashjs": "^5.0.3",
36
- "esbuild": "^0.25.10",
36
+ "esbuild": "^0.25.11",
37
37
  "hls.js": "^1.6.13",
38
38
  "less": "^4.4.2",
39
39
  "markdown-it": "^14.1.0",
@@ -42,7 +42,7 @@
42
42
  "sass": "^1.93.2",
43
43
  "sass-embedded": "^1.93.2",
44
44
  "stylus": "^0.64.0",
45
- "vuepress": "2.0.0-rc.24"
45
+ "vuepress": "2.0.0-rc.26"
46
46
  },
47
47
  "peerDependenciesMeta": {
48
48
  "artplayer": {
@@ -85,7 +85,7 @@
85
85
  "@mdit/plugin-tab": "^0.22.2",
86
86
  "@mdit/plugin-tasklist": "^0.22.1",
87
87
  "@pengzhanbo/utils": "^2.1.0",
88
- "@vuepress/helper": "2.0.0-rc.112",
88
+ "@vuepress/helper": "2.0.0-rc.114",
89
89
  "@vueuse/core": "^13.9.0",
90
90
  "chokidar": "4.0.3",
91
91
  "image-size": "^2.0.2",
@@ -94,9 +94,8 @@
94
94
  "markdown-it-container": "^4.0.0",
95
95
  "nanoid": "^5.1.6",
96
96
  "shiki": "^3.13.0",
97
- "tinyglobby": "^0.2.15",
98
- "tm-grammars": "^1.24.17",
99
- "tm-themes": "^1.10.9",
97
+ "tm-grammars": "^1.24.22",
98
+ "tm-themes": "^1.10.11",
100
99
  "vue": "^3.5.22"
101
100
  },
102
101
  "devDependencies": {