CodeBlock

設定や短いコードを、改行を保って表示します。

CSSの読み込み

<link rel="stylesheet" href="/retrix/components/button.css">

公開設定の例

{
  "title": "秋の読書会",
  "published": false,
  "path": "/articles/abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789"
}
コマンド:短い数行

インストール

vp add retrix
vp run build
行番号と強調した行

controllers.ts

import { Application } from "@hotwired/stimulus";
import { BoardController } from "@tknf/retrix/controllers";

const application = Application.start();
application.register("board", BoardController);

// 列を移ったら、サーバーへ新しい並びを送る。
document.addEventListener("board:move", async (event) => {
  const { id, toColumn, toIndex } = event.detail;
  await fetch(`/cards/${id}`, { method: "PATCH", body: JSON.stringify({ toColumn, toIndex }) });
});
長いコード:高さを決めて縦にスクロールする

notes.css

.note-1 {
  margin-block-start: var(--rx-space-1);
}
.note-2 {
  margin-block-start: var(--rx-space-2);
}
.note-3 {
  margin-block-start: var(--rx-space-3);
}
.note-4 {
  margin-block-start: var(--rx-space-4);
}
.note-5 {
  margin-block-start: var(--rx-space-5);
}
.note-6 {
  margin-block-start: var(--rx-space-6);
}
.note-7 {
  margin-block-start: var(--rx-space-1);
}
.note-8 {
  margin-block-start: var(--rx-space-2);
}
.note-9 {
  margin-block-start: var(--rx-space-3);
}
.note-10 {
  margin-block-start: var(--rx-space-4);
}
.note-11 {
  margin-block-start: var(--rx-space-5);
}
.note-12 {
  margin-block-start: var(--rx-space-6);
}
.note-13 {
  margin-block-start: var(--rx-space-1);
}
.note-14 {
  margin-block-start: var(--rx-space-2);
}
.note-15 {
  margin-block-start: var(--rx-space-3);
}
.note-16 {
  margin-block-start: var(--rx-space-4);
}
.note-17 {
  margin-block-start: var(--rx-space-5);
}
.note-18 {
  margin-block-start: var(--rx-space-6);
}
.note-19 {
  margin-block-start: var(--rx-space-1);
}
.note-20 {
  margin-block-start: var(--rx-space-2);
}
.note-21 {
  margin-block-start: var(--rx-space-3);
}
.note-22 {
  margin-block-start: var(--rx-space-4);
}
.note-23 {
  margin-block-start: var(--rx-space-5);
}
.note-24 {
  margin-block-start: var(--rx-space-6);
}
.note-25 {
  margin-block-start: var(--rx-space-1);
}
.note-26 {
  margin-block-start: var(--rx-space-2);
}
.note-27 {
  margin-block-start: var(--rx-space-3);
}
.note-28 {
  margin-block-start: var(--rx-space-4);
}
.note-29 {
  margin-block-start: var(--rx-space-5);
}
.note-30 {
  margin-block-start: var(--rx-space-6);
}
着色しないコード:そのまま文字として表示する

コードはそのまま文字として表示します

<script>alert("実行されません")</script>
狭い場所

CSSの読み込み

<link rel="stylesheet" href="/retrix/components/button.css">
右から左に読むページ

الإعدادات

{
  "title": "秋の読書会",
  "published": false,
  "path": "/articles/abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789"
}

使いどころ

  • 設定・コマンド・短いコードを、改行と字下げを保って読ませる時に使います。
  • 一行の値をコピーさせる欄は CopyField、キー操作の表記は Keycap を使います。

使い方

code と label を渡します。名前とコピーの操作は LayerCard の層の見出しの行に、コードは層の上のカードの中の白い面に、見出しの題名と同じ書き始めで、等幅の11pxの文字で書きます。

tokens に色分けした区切りを渡すと着色します。改行も含めて、全ての content をつないだ文字列を code と一致させます。一致しない時は着色せずに元の code を書きます。ライブラリは整形器やハイライターを持たないので、tokens は利用側で作ります(見本はサーバー側でShikiの codeToTokens を使います)。tokens もHTMLも、文字としてエスケープして書きます。

lineNumbers で行の頭に番号を振り、highlight に1から数えた行の番号を渡すと、その行を黄色のハイライト(#ffffcc)で強調します。行番号はコピーする内容に含めません。

長い行は横に、高さが28remを超えるコードは縦に、コード領域の中でスクロールします。右から左に読むページでも、コードは左から右に書きます。

copy を付ける時は、ClipboardController を clipboard、CodeBlockController を code-block、ToastController を toast として登録します。コピーの操作はクリップボードに書き込める環境でだけ表示し、表示した全文をコピーして結果をToastで通知します。成功の通知は成功の色で出し、4秒で閉じ、ホバー中やフォーカスがある間は閉じません。失敗の通知は危険の色で出し、コードを選んでコピーするよう促して閉じるまで残します。

JavaScriptがない時はコピーの操作を出さず、コードは読めます。

キーボード

CodeBlockのキーボード操作
キー動作
Tabコード領域とコピーの操作へ移ります。フォーカスのあるコード領域は矢印キーでスクロールできます。
Escコピーの結果の通知が開いている時、フォーカスがCodeBlockの中にあれば通知を閉じます。

アクセシビリティ

  • コード領域は pre に role="region"・tabindex="0" を付け、label を名前にします。
  • コピーの操作は「labelをコピー」を名前に持ちます。成功は role="status" の通知で控えめに、失敗は role="alert" の通知ですぐに読み上げます。
  • 通知を閉じた時、フォーカスが通知の中にあればコピーの操作へ戻します。
  • 行番号はCSSで描き、選択とコピーに含めません。

イベント

CodeBlockが発火するイベント
イベント内容
clipboard:beforecopyコピーの操作を押した時、書き込む前に発火します。取り消せます。detailは text(コピーする全文)・source・reason(pointer・keyboard)です。
clipboard:copy書き込みを試みた後に発火します。detailは text・source・reason・ok(書き込めたか)・error(失敗した時の DOMException)です。

API

CodeBlock

トークンも通常の文字としてエスケープし、表示とコピーの内容を一致させる。

CodeBlockのprops
名前型既定値説明
code必須string表示してコピーするコードの全文。改行と字下げをそのまま保ち、HTMLも文字として書く。
label必須stringコードの名前(ファイル名や用途)。見出しの行と、コード領域のaria-labelにする。
tokensreadonly CodeToken[]着色した区切りの並び。全てのcontentをつないだ文字列がcodeと一致する時だけ使い、一致しなければ着色せずにcodeを書く。ハイライトは利用側で行う(Shikiの結果などを渡す)。
copybooleanfalse見出しの行にコピーの操作を置く。クリップボードに書き込める環境でだけ表示し、結果をToastで知らせる。成功はrole="status"の成功の色、失敗はrole="alert"の危険の色で知らせる。 ClipboardController・CodeBlockController・ToastControllerの登録が要る。
lineNumbersbooleanfalse行の先頭に番号を振る。番号はコピーする内容に含めない。
highlightreadonly number[]黄色のハイライトで目印にする行(1から数える)。

ほかに、<figure>へ標準のHTML属性を渡せます。

登録するcontroller:clipboard(ClipboardController)、code-block(CodeBlockController)、toast(ToastController)

読み込むCSS:layers.css、reset.css、tokens.css、base.css、layout.css、components/section.css、components/button.css、components/overlay.css、components/icon.css、components/layer-card.css、components/toast.css、components/code-block.css

CodeToken

着色の一区切り。

CodeToken
名前型既定値説明
content必須string区切りの文字列。改行を含めてよい。全てのcontentをつなぐとcodeと同じになるようにする。
colorstring文字の色(CSSの色の値)。渡さなければ地の文字の色で書く。空白だけの区切りには色を付けない。

コード

HTML
Hono JSX