Vercel の UI SDK 0.1.0-beta.1 上に構築。API は変わる可能性があります。
Token input
Vercel の UI SDK 上のテキストフィールド。入力した文字に人・ファイル・コマンドのトークンを混ぜられ、@ と / で候補を出します。
- フォームのコンポーネント
- 15 個のパーツ
- 10 個の例
@tabler/icons-react@ui-sdk/core@ui-sdk/react
pnpm dlx shadcn@latest add https://hextaui.com/r/ui-sdk-token-input.jsonコンポーネント、HextaUIのテーマトークン、依存するHextaUIコンポーネントを追加します。
まだ追加していない場合は、グローバルCSSにテーマトークンを追加してください。
依存関係をインストールします。
pnpm add @ui-sdk/react@0.1.0-beta.1 @ui-sdk/core@0.1.0-beta.1 @tabler/icons-react cn次のコードをコピーしてプロジェクトに貼り付けてください。
components/ui/ui-sdk-token-input.tsx インポートパスは、お使いのプロジェクト構成に合わせて更新してください。
UI SDK は ui-sdk というカスケードレイヤーに少しだけ独自の CSS を追加します。自分のクラスが優先されるよう、グローバルスタイルシートの先頭、Tailwind の import より上でこのレイヤーを宣言してください。
値はテキストとトークンの配列です。各トークンには type、アプリ用の value、人が読む label があります。エディターが内容・選択・元に戻すを管理するので描画は任せ、見た目を変えるときは renderToken を渡します。渡さない場合は、ラベルと削除ボタンを表示します。
input 内の TriggerMenu は、@ や / などのトリガーが入力されるとトークンを提案します。トークンをコードから渡す場合は不要です。
ファイルは @、スキルは先頭で / を入力します。ファイルは読み込み中は保留になり、送信すると updateToken() で各スキルが実行中、次に完了になります。Enter で送信、Shift+Enter で改行します。
tokenDeletion はトークン上での Backspace の動作を決めます。whole は削除、select はまず選択、revert はテキストに戻します。
createTokenInputController() のコントローラーで、コードからトークンを挿入・更新・削除できます。resolve に Promise を渡すと、完了までトークンを保留中にします。
name を付けると、各トークンを [@label](type:value) と書いたテキストを送信します。required は空の送信を防ぎ、リセットで defaultValue に戻ります。
submitShortcut="mod+enter" では Enter で改行し、Command か Control+Enter で送信します。日本語や中国語で書く多くの人が好む設定です。
codec はトークンとテキストを相互に変換します。ここでは <@id> の形式です。copy="label" ではコピー時に読める文字列を書き出し、貼り戻すとトークンが復元されます。
readOnly ではテキストにフォーカスでき、選択でき、送信もされますが、入力・貼り付け・ドロップでは変わりません。
エディターはページの方向に従い、右から左のテキスト内でもトークンはひとかたまりのままです。
| キー | アクション |
|---|---|
| BackspaceDelete | tokenDeletion に従って、キャレットの前後のトークンを削除します。 |
| ←→ | 1 回の操作でキャレットがトークンを飛び越えます。トークンの内側では止まりません。 |
| ↑↓ | メニューが開いている間、候補を移動します。 |
| Enter | 送信します。メニューが開いているときはハイライト中の候補を選びます。 |
| Shift + Enter | 改行します。 |
| ⌘ + EnterCtrl + Enter | submitShortcut が mod+enter のとき送信します。その場合 Enter は改行です。 |
| ⌘ + ZCtrl + Z | 直前の操作を元に戻します。入力はまとめられ、貼り付けとトークンの変更はそれぞれ 1 ステップです。 |
| Esc | 候補を閉じます。 |
エディターは複数行のテキストボックスです。中のトリガーメニューが aria-autocomplete と aria-haspopup を追加し、矢印キーで候補を移動する間もフォーカスはテキストに残ります。各トークンは「routes.ts ファイル」のようにラベルと種類で読み上げられ、挿入や削除も通知されます。エディターには aria-label か周囲のラベルで名前を付けます。
Backspace でキーボードからトークンを削除できるため、削除ボタンはスクリーンリーダーから隠れています。タッチ画面ではヒット領域が広がり、保留中のトークンはモーションが許可されているときだけ点滅し、選択中のトークンは強制カラーモードでシステムのハイライト枠が付きます。
各パーツは同名の UI SDK パーツをラップし、render やパーツの状態を受け取る関数にもできる className を含むすべての props を受け付けます。
| プロパティ | 型 | デフォルト |
|---|---|---|
value | TokenInputValue | – |
defaultValue | TokenInputValue | – |
onValueChange入力、貼り付け、メニュー、元に戻す、コントローラー呼び出しで実行されます。details には理由と削除されたトークンが入ります。 | (value, details) => void | – |
onSubmit送信ショートカットで実行されます。メニューが開いているときや IME で変換中のときは実行されません。 | (value, details) => void | – |
submitShortcut | "enter" | "mod+enter" | "enter" |
tokenDeletion | "whole" | "select" | "revert" | "whole" |
renderTokenトークンを描画します。既定はラベルと削除ボタン付きの TokenInputToken です。 | (token: Token) => ReactNode | – |
copy | "codec" | "label" | "codec" |
codec | TokenCodec | – |
getTokenDescriptionトークンがラベル以外にスクリーンリーダーへ伝える内容。 | (token: Token) => string | – |
history | { limit, groupDelay } | – |
name | string | – |
form | string | – |
required | boolean | false |
disabled | boolean | false |
readOnly | boolean | false |
controllercreateTokenInputController() で作成します。 | TokenInputController | – |
| プロパティ | 型 | デフォルト |
|---|---|---|
placeholderinput が空の間、aria-placeholder で表示されます。 | string | – |
render | ReactElement | (props, state) => ReactElement | – |
| 属性 | 説明 |
|---|---|
data-slot="token-input-editor" | CSS でエディターを指定するときに使います。 |
data-empty | input が空の間に付きます。 |
data-disabled | 無効のときに存在します。 |
data-readonly | 読み取り専用のときに付与されます。 |
| 属性 | 説明 |
|---|---|
data-slot="token-input-token" | CSS でトークンを指定するときに使います。 |
data-token-type | トークンの種類。file や mention など。 |
data-selected | トークンが選択範囲にある間、または削除のために選択されている間に付きます。 |
data-pending | トークンの読み込み中に付きます。 |
data-unresolved | 曖昧なメンションなど、トークンにユーザーの対応が必要な間に付きます。 |
自分のトークンを削除し、フォーカスはエディターに残します。children を渡さなければ Tabler の X アイコンを描画し、input が無効または読み取り専用の間は隠れます。
| プロパティ | 型 | デフォルト |
|---|---|---|
triggersメニューを開く文字、それぞれが挿入するトークンの種類、その項目。 | TriggerDefinition[] | – |
onSelect項目を選んだときに実行されます。Promise を返すとトークンを保留中として挿入します。 | (value, details) => void | Promise | – |
autoHighlight | boolean | true |
loop | boolean | true |
| プロパティ | 型 | デフォルト |
|---|---|---|
align | "start" | "center" | "end" | "start" |
sideOffset | number | 6 |
collisionPadding | number | 8 |
| 属性 | 説明 |
|---|---|
data-slot="trigger-menu-content" | CSS でポップアップを指定するときに使います。 |
data-trigger | 現在のマッチのトリガー(@ など)。リストごとに見た目を変えられます。 |
data-starting-style | ポップアップが表示アニメーション中に付きます。 |
data-ending-style | ポップアップが非表示アニメーション中に付きます。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
value | T | – |
label内容がプレーンテキストでないときに、挿入・照合に使うテキスト。 | string | – |
disabled | boolean | false |
| 属性 | 説明 |
|---|---|
data-highlighted | ハイライト中の項目に付きます。フォーカスはエディターに残ります。 |
data-disabled | 項目を選べないときに付きます。 |
- Calendar単一、範囲、複数選択に対応する日付グリッドです。月のスライド、範囲のプレビュー、タッチしやすいサイズの日付セルを備えています。
- Checkboxチェックが描かれるように表示されるチェックボックスです。中間状態の親、グループ、ホバーを共有するラベルに対応します。
- Comboboxチップ、グループ、非同期の結果に対応した、絞り込み可能なセレクトです。入力に合わせてポップアップのサイズが変わります。
- Date picker押すとポップオーバーでカレンダーを開くボタンです。スマートフォンではボトムシートになり、単一の日付も範囲も選べます。
- Fieldコントロールに紐付いたラベル、説明、エラーです。バリデーション状態とフォーム向けのレイアウトを備えています。
- Input3つのサイズ、無効状態と読み取り専用状態、ネイティブのバリデーションスタイル、スマートフォンでズームされない16pxのタッチ用フォントを備えたテキスト入力です。