zenn-embed-elements 0.4.3 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/classes/katex.d.ts +35 -0
- package/lib/classes/katex.js +88 -19
- package/package.json +6 -4
package/lib/classes/katex.d.ts
CHANGED
|
@@ -1,6 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KaTeX数式をレンダリングするWeb Component
|
|
3
|
+
*
|
|
4
|
+
* ## 使用例
|
|
5
|
+
* ```html
|
|
6
|
+
* <embed-katex><eq>x^2 + y^2 = z^2</eq></embed-katex>
|
|
7
|
+
* <embed-katex display-mode><eq>\frac{-b \pm \sqrt{b^2-4ac}}{2a}</eq></embed-katex>
|
|
8
|
+
* ```
|
|
9
|
+
*
|
|
10
|
+
* ## MutationObserverについて
|
|
11
|
+
*
|
|
12
|
+
* morphdomなどのDOM差分更新ライブラリを使用する場合、既存のembed-katex要素の
|
|
13
|
+
* 内容が更新されてもconnectedCallbackが発火しない。これにより、レンダリング済みの
|
|
14
|
+
* 数式がrender前の状態(<eq>タグ)に戻されてしまう問題がある。
|
|
15
|
+
*
|
|
16
|
+
* MutationObserverで子要素の変更を監視し、未レンダリング状態を検出した場合に
|
|
17
|
+
* 自動的にrender()を呼び出すことで、この問題を解決している。
|
|
18
|
+
*/
|
|
1
19
|
export declare class EmbedKatex extends HTMLElement {
|
|
20
|
+
/** KaTeXレンダリング用の一時コンテナ */
|
|
2
21
|
private _container;
|
|
22
|
+
/** DOM変更を監視するObserver */
|
|
23
|
+
private _observer;
|
|
24
|
+
/** レンダリング中フラグ(無限ループ防止用) */
|
|
25
|
+
private _isRendering;
|
|
3
26
|
constructor();
|
|
4
27
|
connectedCallback(): Promise<void>;
|
|
28
|
+
disconnectedCallback(): void;
|
|
29
|
+
/**
|
|
30
|
+
* MutationObserverをセットアップする
|
|
31
|
+
*
|
|
32
|
+
* 子要素の変更を監視し、morphdomなどによるDOM更新後に
|
|
33
|
+
* 未レンダリング状態であればrender()を再実行する。
|
|
34
|
+
*/
|
|
35
|
+
private _setupObserver;
|
|
36
|
+
/**
|
|
37
|
+
* MutationObserverをクリーンアップする(メモリリーク防止)
|
|
38
|
+
*/
|
|
39
|
+
private _cleanupObserver;
|
|
5
40
|
render(): Promise<void>;
|
|
6
41
|
}
|
package/lib/classes/katex.js
CHANGED
|
@@ -13,9 +13,31 @@ exports.EmbedKatex = void 0;
|
|
|
13
13
|
const load_script_1 = require("../utils/load-script");
|
|
14
14
|
const load_stylesheet_1 = require("../utils/load-stylesheet");
|
|
15
15
|
const containerId = 'katex-container';
|
|
16
|
+
/**
|
|
17
|
+
* KaTeX数式をレンダリングするWeb Component
|
|
18
|
+
*
|
|
19
|
+
* ## 使用例
|
|
20
|
+
* ```html
|
|
21
|
+
* <embed-katex><eq>x^2 + y^2 = z^2</eq></embed-katex>
|
|
22
|
+
* <embed-katex display-mode><eq>\frac{-b \pm \sqrt{b^2-4ac}}{2a}</eq></embed-katex>
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* ## MutationObserverについて
|
|
26
|
+
*
|
|
27
|
+
* morphdomなどのDOM差分更新ライブラリを使用する場合、既存のembed-katex要素の
|
|
28
|
+
* 内容が更新されてもconnectedCallbackが発火しない。これにより、レンダリング済みの
|
|
29
|
+
* 数式がrender前の状態(<eq>タグ)に戻されてしまう問題がある。
|
|
30
|
+
*
|
|
31
|
+
* MutationObserverで子要素の変更を監視し、未レンダリング状態を検出した場合に
|
|
32
|
+
* 自動的にrender()を呼び出すことで、この問題を解決している。
|
|
33
|
+
*/
|
|
16
34
|
class EmbedKatex extends HTMLElement {
|
|
17
35
|
constructor() {
|
|
18
36
|
super();
|
|
37
|
+
/** DOM変更を監視するObserver */
|
|
38
|
+
this._observer = null;
|
|
39
|
+
/** レンダリング中フラグ(無限ループ防止用) */
|
|
40
|
+
this._isRendering = false;
|
|
19
41
|
const container = document.createElement('div');
|
|
20
42
|
container.setAttribute('id', containerId);
|
|
21
43
|
this._container = container;
|
|
@@ -23,32 +45,79 @@ class EmbedKatex extends HTMLElement {
|
|
|
23
45
|
connectedCallback() {
|
|
24
46
|
return __awaiter(this, void 0, void 0, function* () {
|
|
25
47
|
this.render();
|
|
48
|
+
this._setupObserver();
|
|
26
49
|
});
|
|
27
50
|
}
|
|
51
|
+
disconnectedCallback() {
|
|
52
|
+
this._cleanupObserver();
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* MutationObserverをセットアップする
|
|
56
|
+
*
|
|
57
|
+
* 子要素の変更を監視し、morphdomなどによるDOM更新後に
|
|
58
|
+
* 未レンダリング状態であればrender()を再実行する。
|
|
59
|
+
*/
|
|
60
|
+
_setupObserver() {
|
|
61
|
+
if (this._observer)
|
|
62
|
+
return;
|
|
63
|
+
this._observer = new MutationObserver(() => {
|
|
64
|
+
// render()がinnerHTMLを変更するとObserverが発火するため、
|
|
65
|
+
// レンダリング中は無視して無限ループを防止する
|
|
66
|
+
if (this._isRendering)
|
|
67
|
+
return;
|
|
68
|
+
// 未レンダリング状態の判定:
|
|
69
|
+
// - <eq>タグが存在する = まだKaTeXでレンダリングされていない
|
|
70
|
+
// - .katexクラスがない = KaTeXのレンダリング結果が存在しない
|
|
71
|
+
if (this.querySelector('eq') && !this.querySelector('.katex')) {
|
|
72
|
+
this.render();
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
this._observer.observe(this, {
|
|
76
|
+
childList: true,
|
|
77
|
+
subtree: true,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* MutationObserverをクリーンアップする(メモリリーク防止)
|
|
82
|
+
*/
|
|
83
|
+
_cleanupObserver() {
|
|
84
|
+
if (this._observer) {
|
|
85
|
+
this._observer.disconnect();
|
|
86
|
+
this._observer = null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
28
89
|
render() {
|
|
29
90
|
return __awaiter(this, void 0, void 0, function* () {
|
|
30
|
-
if (
|
|
31
|
-
|
|
91
|
+
if (this._isRendering)
|
|
92
|
+
return;
|
|
93
|
+
this._isRendering = true;
|
|
94
|
+
try {
|
|
95
|
+
if (typeof katex === 'undefined') {
|
|
96
|
+
yield (0, load_script_1.loadScript)({
|
|
97
|
+
// 本来はバージョンを指定した方がいいが、他の処理との兼ね合いでバージョンを固定するのは難しいので指定していません
|
|
98
|
+
src: `https://cdn.jsdelivr.net/npm/katex/dist/katex.min.js`,
|
|
99
|
+
id: 'katex-js',
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
// CSSを読み込む(まだ読み込まれていない場合のみ)
|
|
103
|
+
(0, load_stylesheet_1.loadStylesheet)({
|
|
32
104
|
// 本来はバージョンを指定した方がいいが、他の処理との兼ね合いでバージョンを固定するのは難しいので指定していません
|
|
33
|
-
|
|
34
|
-
id:
|
|
105
|
+
href: `https://cdn.jsdelivr.net/npm/katex/dist/katex.min.css`,
|
|
106
|
+
id: `katex-css`,
|
|
35
107
|
});
|
|
108
|
+
const displayMode = !!this.getAttribute('display-mode');
|
|
109
|
+
// detailsタグの中ではinnerTextがnullになることがあるため
|
|
110
|
+
const content = this.textContent || this.innerText;
|
|
111
|
+
katex === null || katex === void 0 ? void 0 : katex.render(content, this._container, {
|
|
112
|
+
macros: { '\\RR': '\\mathbb{R}' },
|
|
113
|
+
throwOnError: false,
|
|
114
|
+
displayMode,
|
|
115
|
+
});
|
|
116
|
+
this.innerHTML = this._container.innerHTML;
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
this._isRendering = false;
|
|
36
120
|
}
|
|
37
|
-
// CSSを読み込む(まだ読み込まれていない場合のみ)
|
|
38
|
-
(0, load_stylesheet_1.loadStylesheet)({
|
|
39
|
-
// 本来はバージョンを指定した方がいいが、他の処理との兼ね合いでバージョンを固定するのは難しいので指定していません
|
|
40
|
-
href: `https://cdn.jsdelivr.net/npm/katex/dist/katex.min.css`,
|
|
41
|
-
id: `katex-css`,
|
|
42
|
-
});
|
|
43
|
-
const displayMode = !!this.getAttribute('display-mode');
|
|
44
|
-
// detailsタグの中ではinnerTextがnullになることがあるため
|
|
45
|
-
const content = this.textContent || this.innerText;
|
|
46
|
-
katex === null || katex === void 0 ? void 0 : katex.render(content, this._container, {
|
|
47
|
-
macros: { '\\RR': '\\mathbb{R}' },
|
|
48
|
-
throwOnError: false,
|
|
49
|
-
displayMode,
|
|
50
|
-
});
|
|
51
|
-
this.innerHTML = this._container.innerHTML;
|
|
52
121
|
});
|
|
53
122
|
}
|
|
54
123
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zenn-embed-elements",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Web components for embedded contents.",
|
|
6
6
|
"repository": {
|
|
@@ -25,18 +25,20 @@
|
|
|
25
25
|
"fix": "run-s fix:*",
|
|
26
26
|
"fix:eslint": "eslint . --fix",
|
|
27
27
|
"fix:prettier": "prettier -w .",
|
|
28
|
-
"test": "
|
|
28
|
+
"test": "vitest run"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@eslint/js": "^9.38.0",
|
|
32
32
|
"@types/node": "^24.9.1",
|
|
33
33
|
"eslint": "^9.38.0",
|
|
34
34
|
"eslint-config-prettier": "^10.1.8",
|
|
35
|
+
"happy-dom": "^20.3.9",
|
|
35
36
|
"rimraf": "^6.0.1",
|
|
36
37
|
"typescript": "^5.9.3",
|
|
37
|
-
"typescript-eslint": "^8.46.2"
|
|
38
|
+
"typescript-eslint": "^8.46.2",
|
|
39
|
+
"vitest": "^4.0.18"
|
|
38
40
|
},
|
|
39
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "de867b158201c3a387544cb88b8b627ea356aa43",
|
|
40
42
|
"publishConfig": {
|
|
41
43
|
"access": "public"
|
|
42
44
|
}
|