sobria
ページの一覧

JSX

関数と型の詳細は、sobria の API に記述しています。

ファイルの種類と JSX の型

JSX の型は、ファイルを配置したディレクトリで決まります。

項目src/elements/src/routes/src/ のそのほかのファイル
描画する場所ブラウザとサーバーサーバー使用した側
ネイティブのタグのイベントハンドラー使用できます型エラー型エラー
ref使用できます型エラー型エラー
要素に指定する load:*型エラー使用できます型エラー
記述できるコンポーネント要素、補助コンポーネント、共通のコンポーネントサーバーコンポーネント、要素、共通のコンポーネント共通のコンポーネント

src/ のそのほかのファイルに配置した共通のコンポーネントは、ページの中ではサーバーで、要素の中ではブラウザで描画します。共通のコンポーネントには、ref、load:*、ホストの属性を指定できません。

属性の名前

ネイティブのタグの属性は、HTML の属性名で記述します。

記述する名前型エラーになる名前
classclassName
forhtmlFor
tabindextabIndex

data-* と aria-* の属性は、名前を検査しません。SVG のタグと、名前に - を含むタグ(ほかのライブラリの Custom Element)も、属性の名前を検査しません。

属性の値

値出力
true値の無い属性(disabled)
false、null、undefined属性を出力しません
aria-*、draggable、spellcheck、contenteditable の真偽値"true" か "false"。false でも出力します
空の文字列空の値の属性(alt="")
class のオブジェクト値が真のキーを空白で区切った文字列。真のキーが無ければ出力しません
style のオブジェクトプロパティ:値 を ; で区切った文字列。値が null、undefined、false のプロパティを除き、残るプロパティが無ければ出力しません
そのほかの値文字列に変換した値
  • class には、文字列か、キーをクラスの名前とするオブジェクトを指定します
  • style には、文字列か、background-color のような CSS のプロパティ名と CSS 変数をキーとするオブジェクトを指定します。sobria は数値に単位を付与しないので、長さは "10px" のように文字列で指定します
<p class={{ active: selected(), done: false }} style={{ color: "red", "--gap": "4px" }}>
  …
</p>

プロパティに設定する値

要素の中では、次の値をプロパティに設定します。

タグプロパティ
inputvalue、checked
textareavalue
selectvalue
optionselected

サーバーで描画するときは、textarea の value をテキストの子として出力し、select の value に一致する option に selected を付与します。option の値は、value が無ければテキストの子の内容です。

値の更新

要素の中の JSX では、関数の呼び出し、プロパティの参照、タグ付きテンプレートのどれかを含む式が、Signal の値が変わるたびに再評価されます。

記述値が変わったときの動作
{count()}、{props.max}再評価して表示を更新します
class={{ active: selected() }}再評価して属性を更新します
リテラル、変数の名前だけの式更新しません
onClick、ref、key の値ノードを作成した時点の値を使用します

サーバーコンポーネントは 1 回だけ実行します。async のサーバーコンポーネントでは、<h1>{await greet()}</h1> のように JSX の中に await を記述できます。

子

値表示
文字列、数値、BigIntテキスト。HTML の特殊文字はエスケープします
true、false、null、undefined何も表示しません
配列要素を順に表示します
JSXそのノード
DOM の Nodeそのノードを表示します。要素の中でだけ記述できます
関数関数の戻り値。要素の中では、関数が参照する Signal の値が変わるたびに、表示を更新します

イベント

ネイティブのタグのイベントハンドラーは、要素のファイルでだけ記述できます。

// src/elements/counter.tsx
<button onClick={() => setCount(count() + 1)}>{count()}</button>
  • イベント名は、on の後の部分を小文字にした名前です。onClick は click、onDblClick は dblclick のリスナーになります
  • HTML のタグに記述できるのは、DOM の標準のイベントの名前(onClick、onInput など)だけです。ほかの名前は型エラーになります
  • SVG のタグと、名前に - を含むタグには、on と英字の大文字で始まる任意の名前を記述できます。onLikeClick は likeclick のリスナーになるので、これらのタグの on で始まる名前の属性では、like-click のように - を含む名前のイベントを受け取れません。受け取るには、ref の関数の中で addEventListener を呼び出します
  • イベントの currentTarget は、そのタグの DOM の要素の型になります
  • サーバーコンポーネントのタグに記述したイベントハンドラーは、ブラウザで実行されません。開発時は、SSR で警告を出力します

要素が発行するイベントの受け取り方は、関数の props とイベントに記述しています。

ref

ref には、ノードを受け取る関数を指定します。

項目内容
記述できるファイル要素のファイルだけです
ネイティブのタグノードを作成した時点で呼び出します
sobria の要素要素が起動し、ctx.expose を実行した後に呼び出します。引数の型は ElementRef<typeof X> です
戻り値関数を返すと、条件の分岐でノードが消えるときと、要素がページから外れるときに、その関数を呼び出します
SSR呼び出しません
// src/elements/chart.tsx
<canvas
  ref={(el) => {
    const chart = new Chart(el);
    return () => chart.destroy();
  }}
/>

補助コンポーネントは要素ではないので、Props の型に ref を宣言できます。宣言した ref は、ほかの props と同じく関数の引数に渡ります。

key

key には文字列か数値を指定します。key は data-ok 属性として出力し、描き直しでは、同じキーのノードどうしを対応付けます。{...props} のようなスプレッドの後に key を記述すると、ビルドのエラーになります。

load:*

load:* は、要素の起動のタイミングを、要素を使用する箇所ごとに指定します。src/routes/ のファイルで要素に指定したときだけ有効です。

属性起動する時点
load:loadすぐに起動します
load:idleブラウザの処理が空いた時点
load:visible要素が初めてビューポートに入った時点
load:media="クエリ"メディアクエリに一致した時点。最初から一致していれば、すぐに起動します
// src/routes/page.tsx
<Chart load:visible data={data} />
<Chart load:media="(min-width: 800px)" data={data} />
  • 要素のデフォルトの起動のタイミングは、要素のファイルの export const load に "load"、"idle"、"visible" のどれかの文字列のリテラルで記述します。それぞれ、load:load、load:idle、load:visible と同じ時点で起動します。変数などのほかの式を記述すると、ビルドのエラーになります。記述しなければ "load" です
  • 要素の Shadow DOM の中で使用した要素は、親の要素と同時に起動します。load:* と export const load は適用しません
  • SSR では、load:* を data-sobria-load 属性に変換して出力します

起動の詳細は読み込みと値の受け渡しに記述しています。

要素の props と属性

props の名前と属性の名前

props の属性の名前は、props の名前を kebab-case にしたものです。大文字の連続は 1 語として扱います。

props の名前属性の名前
userIduser-id
imageURLimage-url

2 つの props が同じ属性の名前になると、ビルドのエラーになります。

props の型と受け取り方

要素が props をどう受け取るかは、要素のファイルの Props の型で決まります。交差型や Pick で組み立てた型も、TypeScript が解決した各 props の型で、次の表の行が決まります。ホストのプロパティの名前は、props の名前と同じです。

Props の型受け取り方
string、number、boolean、それぞれのリテラル型、同じ種類のリテラル型のユニオン型("small" | "large" など)、enum、テンプレートのリテラル型プロパティと属性。属性の文字列を Props の型に変換します
関数プロパティだけ
JSX.Element、Slotスロット
オブジェクト、配列、Date、Map などプロパティだけ
そのほかの型(string と number のユニオン型、unknown など)プロパティと属性。属性の文字列をそのまま渡します

関数ではない型で宣言した props に関数を渡すと、sobria がその関数を呼び出し、戻り値を props の値として要素に渡します。

属性の文字列は、次のように変換します。number の props は、属性の値を Number で変換した数値を受け取るので、"" は 0 に、"abc" は NaN になります。

Props の型属性の値props の値
number"3"3
boolean"false"false
boolean"false" 以外の値true
すべての型属性を削除するundefined

サーバーコンポーネントから渡す値

値渡し方
文字列、数値、真偽値ホストの属性として出力します。false と null は属性を出力しません。属性の値から元の値に戻せない値(false、null、-0 と、文字列と数値のユニオン型のように属性の変換の方法を型から決定できない props に渡した数値と真偽値)は、ページにも埋め込み、要素が起動した後も同じ値で渡します
オブジェクト、配列、BigInt、Date、Map、Set、RegExp、型付き配列など、シリアライズできる値ページに埋め込み、型を保持したまま要素に渡します。要素はその値が届いてから起動します
サーバー関数要素から呼び出すと、サーバーで実行します。オブジェクトの中に入れても渡せます
JSXスロットの props にだけ渡せます

次の値は渡せません。オブジェクトや配列の中に入れても渡せません。渡すと、SSR の時点でエラーになります。

  • サーバー関数以外の関数
  • クラスのインスタンス
  • symbol
  • Promise。await で解決した値を渡します
  • Error。{ message } のようなオブジェクトに変換して渡します
  • スロットの props 以外に渡した JSX

エラーのメッセージは、要素のタグ名と props の名前で始まります。例えば、sobria-event-form の要素の onSave にサーバー関数以外の関数を渡すと、<sobria-event-form> onSave は関数なので、シリアライズできません。 で始まるエラーになります。

要素の中で別の要素に渡す値には、この制約はありません。

Props の型に記述しなくても受け付ける props

props内容
ref、key、load:*予約された props です。要素の Props の型に記述すると、ビルドのエラーになります
name、disabledフォームの部品の名前と無効の状態です(フォーム)。Props の型に宣言すると、その型で値を受け取ります
id、class、style、role、aria-*、data-* などホストの属性として、そのままホストに出力します
Props の型に無い、DOM の標準のイベントの名前(onClick など)の関数要素のファイルで記述すると、ホストのイベントのリスナーにします。イベント名は、on の後の部分を小文字にした名前です。src/routes/ のファイルで記述すると、型エラーになります

Props の型に無く、DOM の標準のイベントの名前でもない on で始まる名前(onLikeClick など)を sobria の要素のタグに記述すると、型エラーになります。

props にできない名前

ホストの属性やプロパティと衝突する名前は、props の名前にできません。Props の型に記述すると、ビルドのエラーになります。エラーのメッセージには、名前を使用できない理由と、代わりの名前の例が含まれます。

  • ホストにそのまま出力する属性(id、class、style、slot、role など)
  • ブラウザが動作を持つグローバル属性(title、hidden、lang など)
  • HTMLElement のプロパティとメソッド(remove、focus、textContent など)
  • フォームの部品の API の名前(form、labels、validity など)
  • ライフサイクルのコールバックの名前(connectedCallback など)
  • aria か data の後に英字の大文字が続く名前(ariaLabel、dataSource など)

Props の型をヘルパー型 Props<T> で包むと、エディタで同じ検査が実行されます。名前の無いスロットの children は、props にできます。

関数の props とイベント

Props の型で関数として宣言した onX の形(on の後が英字の大文字)の props は、使用する側が値を渡していなければイベントになります。要素がその props を呼び出すと、ホストが CustomEvent を発行します。

項目内容
イベント名on の後の部分を kebab-case にした名前。onSelect は select、onLikeClick は like-click です
detail呼び出したときの最初の引数
bubbles、composedtrue

sobria の JSX でイベントの props に関数を渡すと、要素はその関数を呼び出し、イベントを発行しません。要素の側では、関数が渡されたかどうかを判別できません。

// sobria の外から受け取る場合
el.addEventListener("like-click", (e) => e.detail);