@riebeckite/plugin-code-enhance 0.0.31 → 0.0.33
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/README.md +10 -0
- package/README_ja.md +14 -4
- package/dist/client.js +16 -5
- package/dist/index.js +33 -7
- package/dist/src/hast.d.ts +0 -1
- package/dist/src/init.d.ts +1 -1
- package/package.json +3 -3
- package/style.css +11 -16
package/README.md
CHANGED
|
@@ -35,6 +35,16 @@ export default defineConfig({
|
|
|
35
35
|
});
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
## Live example
|
|
39
|
+
|
|
40
|
+
The block below uses a filename header, line numbers, and a highlighted line.
|
|
41
|
+
|
|
42
|
+
~~~ts title="greeting.ts" {2}
|
|
43
|
+
export function greet(name: string) {
|
|
44
|
+
return `Hello, ${name}`;
|
|
45
|
+
}
|
|
46
|
+
~~~
|
|
47
|
+
|
|
38
48
|
## Features
|
|
39
49
|
|
|
40
50
|
- Syntax highlighting via Shiki (rehype-pretty-code)
|
package/README_ja.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- Generated from docs/docs/plugins/code-enhance.ja.md. Edit the canonical documentation in docs/docs/plugins and run `pnpm docs:sync`. -->
|
|
4
4
|
|
|
5
|
-
Shiki
|
|
5
|
+
Shiki のシンタックスハイライトに、ファイル名ヘッダーとコピー、折り返し、折りたたみの操作を加えたコードブロックを提供するプラグインです。
|
|
6
6
|
|
|
7
7
|
[English](./README.md)
|
|
8
8
|
|
|
@@ -20,6 +20,16 @@ export default defineConfig({
|
|
|
20
20
|
|
|
21
21
|
`codeEnhance()` は `rehype-pretty-code` を使ってコードブロックを処理し、ファイル名と操作ボタンを持つ `.rr-code` 要素に整えます。ボタンの操作はクライアントエントリーが担当します。
|
|
22
22
|
|
|
23
|
+
## 実行例
|
|
24
|
+
|
|
25
|
+
次のブロックでは、ファイル名ヘッダー、行番号、行ハイライトを同時に使っています。
|
|
26
|
+
|
|
27
|
+
~~~ts title="greeting.ts" {2}
|
|
28
|
+
export function greet(name: string) {
|
|
29
|
+
return `Hello, ${name}`;
|
|
30
|
+
}
|
|
31
|
+
~~~
|
|
32
|
+
|
|
23
33
|
## 表示と操作
|
|
24
34
|
|
|
25
35
|
- Shiki のテーマによる色付け、行番号、メタデータによる行・文字の強調
|
|
@@ -29,7 +39,7 @@ export default defineConfig({
|
|
|
29
39
|
- `bash`、`console`、`sh` などのシェル言語の行に `$` を付ける
|
|
30
40
|
- キーボードで内容を確認できるよう、`<pre>` をフォーカス可能にする
|
|
31
41
|
|
|
32
|
-
|
|
42
|
+
テーマは `rr-code` のルート要素に `--rr-code-syntax` を指定すると、ハイライト済みコードの
|
|
33
43
|
子要素を選択せずに構文色を指定できます。
|
|
34
44
|
|
|
35
45
|
## オプション
|
|
@@ -51,12 +61,12 @@ Theme は `rr-code` の root に `--rr-code-syntax` を指定すると、ハイ
|
|
|
51
61
|
|
|
52
62
|
## クライアント側の初期化
|
|
53
63
|
|
|
54
|
-
`codeEnhance()` は `copyLabel` と `copiedLabel` をクライアントエントリーへ渡します。`initCodeEnhance(options?)`
|
|
64
|
+
`codeEnhance()` は `copyLabel` と `copiedLabel` をクライアントエントリーへ渡します。`initCodeEnhance(options?)` はコピー、折り返し、折りたたみボタンのためにドキュメント全体のクリックハンドラーを登録します。直接呼び出す場合も同じ 2 つの文言を指定できます。
|
|
55
65
|
|
|
56
66
|
## 公開 API
|
|
57
67
|
|
|
58
68
|
- `codeEnhance(options?)`:プラグインファクトリ
|
|
59
|
-
- `rehypeCodeEnhance(options?)`:
|
|
69
|
+
- `rehypeCodeEnhance(options?)`:rehype 変換
|
|
60
70
|
- `initCodeEnhance(options?)`:ブラウザ初期化関数
|
|
61
71
|
- `DEFAULT_COPY_LABEL`、`DEFAULT_COPIED_LABEL`:既定のコピー文言
|
|
62
72
|
- `CodeEnhanceOptions`、`CodeEnhanceClientOptions`、`CodeEnhanceTheme`:型
|
package/dist/client.js
CHANGED
|
@@ -4,12 +4,13 @@ var DEFAULT_COPIED_LABEL = "Copied";
|
|
|
4
4
|
function initCodeEnhance(options = {}) {
|
|
5
5
|
const copyLabel = options.copyLabel ?? DEFAULT_COPY_LABEL;
|
|
6
6
|
const copiedLabel = options.copiedLabel ?? DEFAULT_COPIED_LABEL;
|
|
7
|
-
|
|
7
|
+
const timers = /* @__PURE__ */ new Set();
|
|
8
|
+
const onClick = async (event) => {
|
|
8
9
|
const target = event.target;
|
|
9
10
|
if (!(target instanceof Element)) return;
|
|
10
11
|
const copyButton = target.closest("[data-code-copy]");
|
|
11
12
|
if (copyButton) {
|
|
12
|
-
await copyCode(copyButton, copyLabel, copiedLabel);
|
|
13
|
+
await copyCode(copyButton, copyLabel, copiedLabel, timers);
|
|
13
14
|
return;
|
|
14
15
|
}
|
|
15
16
|
const wrapButton = target.closest(
|
|
@@ -23,16 +24,26 @@ function initCodeEnhance(options = {}) {
|
|
|
23
24
|
"[data-code-collapse-toggle]"
|
|
24
25
|
);
|
|
25
26
|
if (collapseButton) toggleCollapse(collapseButton);
|
|
26
|
-
}
|
|
27
|
+
};
|
|
28
|
+
document.addEventListener("click", onClick);
|
|
29
|
+
return () => {
|
|
30
|
+
document.removeEventListener("click", onClick);
|
|
31
|
+
for (const timer of timers) window.clearTimeout(timer);
|
|
32
|
+
timers.clear();
|
|
33
|
+
};
|
|
27
34
|
}
|
|
28
|
-
async function copyCode(button, copyLabel, copiedLabel) {
|
|
35
|
+
async function copyCode(button, copyLabel, copiedLabel, timers) {
|
|
29
36
|
const code = getCodeText(button);
|
|
30
37
|
if (!code) return;
|
|
31
38
|
await navigator.clipboard.writeText(code);
|
|
39
|
+
button.dataset.codeCopyState = "success";
|
|
32
40
|
button.textContent = copiedLabel;
|
|
33
|
-
window.setTimeout(() => {
|
|
41
|
+
const timer = window.setTimeout(() => {
|
|
42
|
+
timers.delete(timer);
|
|
43
|
+
delete button.dataset.codeCopyState;
|
|
34
44
|
button.textContent = copyLabel;
|
|
35
45
|
}, 1500);
|
|
46
|
+
timers.add(timer);
|
|
36
47
|
}
|
|
37
48
|
function getCodeText(button) {
|
|
38
49
|
const figure = button.closest(".rr-code");
|
package/dist/index.js
CHANGED
|
@@ -11,12 +11,13 @@ var DEFAULT_COPIED_LABEL = "Copied";
|
|
|
11
11
|
function initCodeEnhance(options = {}) {
|
|
12
12
|
const copyLabel = options.copyLabel ?? DEFAULT_COPY_LABEL;
|
|
13
13
|
const copiedLabel = options.copiedLabel ?? DEFAULT_COPIED_LABEL;
|
|
14
|
-
|
|
14
|
+
const timers = /* @__PURE__ */ new Set();
|
|
15
|
+
const onClick = async (event) => {
|
|
15
16
|
const target = event.target;
|
|
16
17
|
if (!(target instanceof Element)) return;
|
|
17
18
|
const copyButton = target.closest("[data-code-copy]");
|
|
18
19
|
if (copyButton) {
|
|
19
|
-
await copyCode(copyButton, copyLabel, copiedLabel);
|
|
20
|
+
await copyCode(copyButton, copyLabel, copiedLabel, timers);
|
|
20
21
|
return;
|
|
21
22
|
}
|
|
22
23
|
const wrapButton = target.closest(
|
|
@@ -30,16 +31,26 @@ function initCodeEnhance(options = {}) {
|
|
|
30
31
|
"[data-code-collapse-toggle]"
|
|
31
32
|
);
|
|
32
33
|
if (collapseButton) toggleCollapse(collapseButton);
|
|
33
|
-
}
|
|
34
|
+
};
|
|
35
|
+
document.addEventListener("click", onClick);
|
|
36
|
+
return () => {
|
|
37
|
+
document.removeEventListener("click", onClick);
|
|
38
|
+
for (const timer of timers) window.clearTimeout(timer);
|
|
39
|
+
timers.clear();
|
|
40
|
+
};
|
|
34
41
|
}
|
|
35
|
-
async function copyCode(button, copyLabel, copiedLabel) {
|
|
42
|
+
async function copyCode(button, copyLabel, copiedLabel, timers) {
|
|
36
43
|
const code = getCodeText(button);
|
|
37
44
|
if (!code) return;
|
|
38
45
|
await navigator.clipboard.writeText(code);
|
|
46
|
+
button.dataset.codeCopyState = "success";
|
|
39
47
|
button.textContent = copiedLabel;
|
|
40
|
-
window.setTimeout(() => {
|
|
48
|
+
const timer = window.setTimeout(() => {
|
|
49
|
+
timers.delete(timer);
|
|
50
|
+
delete button.dataset.codeCopyState;
|
|
41
51
|
button.textContent = copyLabel;
|
|
42
52
|
}, 1500);
|
|
53
|
+
timers.add(timer);
|
|
43
54
|
}
|
|
44
55
|
function getCodeText(button) {
|
|
45
56
|
const figure = button.closest(".rr-code");
|
|
@@ -182,6 +193,7 @@ function restoreCodeMeta(tree) {
|
|
|
182
193
|
});
|
|
183
194
|
}
|
|
184
195
|
var LANGUAGE_CLASS_PREFIX = "language-";
|
|
196
|
+
var SOURCE_FILE_TITLE_PREFIX = "source-file:";
|
|
185
197
|
function normalizeCodeLanguages(tree) {
|
|
186
198
|
visitElements(tree, (node) => {
|
|
187
199
|
if (node.tagName !== "code") return;
|
|
@@ -229,12 +241,16 @@ function enhancePrettyCodeFigures(tree, options) {
|
|
|
229
241
|
const code = findDirectChild(pre, "code");
|
|
230
242
|
const titleNode = findTitleNode(node);
|
|
231
243
|
const title = titleNode ? getTextContent(titleNode) : null;
|
|
244
|
+
const sourceFileTitle = title?.startsWith(SOURCE_FILE_TITLE_PREFIX) ? title : null;
|
|
245
|
+
const isSourceFile = sourceFileTitle !== null;
|
|
246
|
+
const displayTitle = sourceFileTitle ? sourceFileTitle.slice(SOURCE_FILE_TITLE_PREFIX.length) : title;
|
|
232
247
|
const language = getLanguage(pre, code);
|
|
233
248
|
const isShell = isTerminalLanguage(language);
|
|
234
249
|
node.properties = {
|
|
235
250
|
...node.properties,
|
|
236
251
|
className: mergeClassName(node.properties?.className, "rr-code"),
|
|
237
|
-
dataLanguage: language
|
|
252
|
+
dataLanguage: language,
|
|
253
|
+
...isSourceFile ? { dataSourceFile: "true" } : {}
|
|
238
254
|
};
|
|
239
255
|
pre.properties = {
|
|
240
256
|
...pre.properties,
|
|
@@ -250,6 +266,7 @@ function enhancePrettyCodeFigures(tree, options) {
|
|
|
250
266
|
className: mergeClassName(code.properties?.className, "rr-code__code")
|
|
251
267
|
};
|
|
252
268
|
if (options.lineNumbers) markLineNumbers(code);
|
|
269
|
+
if (isSourceFile) markSourceFileLines(code);
|
|
253
270
|
if (options.diffHighlight !== false && isDiffLanguage(language))
|
|
254
271
|
markDiffLines(code);
|
|
255
272
|
if (options.commandPrompt !== false && isShell) markCommandPrompts(code);
|
|
@@ -258,7 +275,7 @@ function enhancePrettyCodeFigures(tree, options) {
|
|
|
258
275
|
const body = element("div", { className: "rr-code__body" }, bodyChildren);
|
|
259
276
|
node.children = [
|
|
260
277
|
buildHeader({
|
|
261
|
-
title: options.filename === false ? null :
|
|
278
|
+
title: options.filename === false ? null : displayTitle,
|
|
262
279
|
language,
|
|
263
280
|
copyButton: options.copyButton !== false,
|
|
264
281
|
wrapToggle: options.wrapToggle !== false,
|
|
@@ -334,6 +351,15 @@ function markLineNumbers(code) {
|
|
|
334
351
|
};
|
|
335
352
|
}
|
|
336
353
|
}
|
|
354
|
+
function markSourceFileLines(code) {
|
|
355
|
+
for (const [index, line] of getCodeLines(code).entries()) {
|
|
356
|
+
line.properties = {
|
|
357
|
+
...line.properties,
|
|
358
|
+
id: `L${index + 1}`,
|
|
359
|
+
tabindex: "-1"
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
}
|
|
337
363
|
function markDiffLines(code) {
|
|
338
364
|
for (const line of getCodeLines(code)) {
|
|
339
365
|
const content = getTextContent(line);
|
package/dist/src/hast.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ElementNode, HastNode, TextNode } from "./types.js";
|
|
2
2
|
export declare function visitElements(node: HastNode, visitor: (node: ElementNode, parent?: ElementNode, index?: number) => void, parent?: ElementNode, index?: number): void;
|
|
3
|
-
export declare function isElementNode(node: HastNode): node is ElementNode;
|
|
4
3
|
export declare function text(value: string): TextNode;
|
|
5
4
|
export declare function element(tagName: string, properties?: Record<string, unknown>, children?: HastNode[]): ElementNode;
|
|
6
5
|
export declare function getStringProperty(node: ElementNode, key: string): string | null;
|
package/dist/src/init.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { CodeEnhanceClientOptions } from "./types.js";
|
|
2
2
|
export declare const DEFAULT_COPY_LABEL = "Copy";
|
|
3
3
|
export declare const DEFAULT_COPIED_LABEL = "Copied";
|
|
4
|
-
export declare function initCodeEnhance(options?: CodeEnhanceClientOptions): void;
|
|
4
|
+
export declare function initCodeEnhance(options?: CodeEnhanceClientOptions): () => void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riebeckite/plugin-code-enhance",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.33",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
"./style.css": "./style.css"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
+
"@riebeckite/core": "0.0.33",
|
|
24
25
|
"rehype-pretty-code": "^0.14.1",
|
|
25
|
-
"shiki": "^3.13.0"
|
|
26
|
-
"@riebeckite/core": "0.0.31"
|
|
26
|
+
"shiki": "^3.13.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"tsx": "^4.22.4"
|
package/style.css
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
.rr-code {
|
|
2
|
-
--rr-code-paper: var(
|
|
3
|
-
|
|
2
|
+
--rr-code-paper: var(
|
|
3
|
+
--rb-color-code-background,
|
|
4
|
+
var(--rb-color-ink, #000000)
|
|
5
|
+
);
|
|
6
|
+
--rr-code-ink: var(--rb-color-code-ink, var(--rb-color-ink, #ffffff));
|
|
4
7
|
--rr-code-muted: color-mix(in srgb, var(--rr-code-ink) 56%, transparent);
|
|
5
8
|
--rr-code-rule: color-mix(in srgb, var(--rr-code-ink) 18%, transparent);
|
|
6
9
|
--rr-code-accent: var(--rb-color-accent, #686868);
|
|
@@ -53,8 +56,12 @@
|
|
|
53
56
|
|
|
54
57
|
.rr-code__action:hover,
|
|
55
58
|
.rr-code__action:focus-visible {
|
|
56
|
-
border-color: var(--rr-code-
|
|
57
|
-
|
|
59
|
+
border-color: color-mix(in srgb, var(--rr-code-ink) 42%, transparent);
|
|
60
|
+
background: var(
|
|
61
|
+
--rb-code-action-hover-background,
|
|
62
|
+
color-mix(in srgb, var(--rr-code-ink) 14%, var(--rb-color-paper, #ffffff))
|
|
63
|
+
);
|
|
64
|
+
color: var(--rr-code-ink);
|
|
58
65
|
outline: none;
|
|
59
66
|
}
|
|
60
67
|
|
|
@@ -133,15 +140,3 @@
|
|
|
133
140
|
.rr-code__pre--wrap .rr-code__line {
|
|
134
141
|
white-space: pre-wrap;
|
|
135
142
|
}
|
|
136
|
-
|
|
137
|
-
:is(:root, .rb-theme-root)[data-theme="dark"] .rr-code {
|
|
138
|
-
--rr-code-paper: var(--rb-color-paper, #000000);
|
|
139
|
-
--rr-code-ink: var(--rb-color-ink, #ffffff);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
@media (prefers-color-scheme: dark) {
|
|
143
|
-
:is(:root, .rb-theme-root):not([data-theme]) .rr-code {
|
|
144
|
-
--rr-code-paper: var(--rb-color-paper, #000000);
|
|
145
|
-
--rr-code-ink: var(--rb-color-ink, #ffffff);
|
|
146
|
-
}
|
|
147
|
-
}
|