Zag.js w/ Vue SFC
コンポーネントのstateハンドリングやアクセシビリティに関連する属性の振り出しを移譲出来る Zag.js
をテスト書きしたが、Chakura UIがReactベースなこともあり、Vueのサンプルが使い物にならなかったので、スクラップで簡単に整理。
Zag.jsの公式ドキュメントでは、Vueのサンプルとして下記を提供している。
Zag works seamlessly with Vue's JSX approach. Here's how to use the same toggle logic in Vue:
!?
Vueで jsx
tsx
の類を利用するのもバカらしいので、vue
でSFCとして書きたいので、サンプルをベースにモダン?なSFCでリライトをかけたい。
Toggleのサンプルは下記。
import { computed, defineComponent, h, Fragment } from "vue"
import * as toggle from "@zag-js/toggle"
import { useMachine, normalizeProps } from "@zag-js/vue"
export default defineComponent({
name: "Toggle",
setup() {
const [state, send] = useMachine(toggle.machine({
id: "1"
}))
const apiRef = computed(() => toggle.connect(state, send, normalizeProps))
return () => {
const api = apiRef.value
return (
<button {...api.buttonProps}>
{api.isPressed ? "On" : "Off"}
</button>
)
}
},
})
これを実行すると、そもそも正常な挙動をしてくれない。下記2点の問題がある。
-
toggle.connect
に渡すstate
が型不一致- ここは
state.value
をパスすることで解決
- ここは
-
apiRef
を参照するため、値変更に対してcomputed
が発火しない(つまり、ボタン押下で値が変わらない-
apiRef
で無くapi
参照でOK
-
Vueで書き直すとこうなった。
<script setup lang="ts">
import { computed } from 'vue'
import { useMachine, normalizeProps } from '@zag-js/vue'
import * as toggle from '@zag-js/toggle'
const [state, send] = useMachine(
toggle.machine({
id: '1',
}),
)
const api = computed(() => toggle.connect(state.value, send, normalizeProps))
</script>
<template>
<button v-bind="{ ...api.buttonProps }">
{{ api.isPressed ? 'On' : 'Off' }}
</button>
</template>
Zag本体がカバーしてくれる内容はめちゃくちゃ良さそう。アクセシビリティも加味した属性設計は網羅感を出すのが大変だし、トグルの様なstateに紐付く挙動のコンポーネントも基盤をささっと作ってくれる。
ただし、ドキュメントがガバガバ感がある点はまだまだベータ版ゆえか。Panda CSSは割とちゃんとしているだけに、こちらにも期待(Chakura UI自体がちゃんとした運営体と思うので、あんまり不安も無い)
Zagをもうちょっと遊びながら、ドキュメントのちょっとした修正コード等あれば、このスクラップに書き足すことにしよう。
👇も触れてみた。コンポーネントのハンドリングに必要な属性とイベントをカスタムで作る方法。
例えば、State
Send
は既存部品の物を渡したいが、connect
箇所、つまりイベント毎に再計算されてリフレッシュされる各種属性群の生成ロジックをカスタマイズしたい場合、State
Send
は既存部品の型情報を利用し、型安全に処理を書きたくなる。
が、node_modules
を掘り下げる限り、部品パッケージの中で型をexposeしている様子が無い。
State
Send
を自前で作った場合の型定義もやり用があるのかな、、@zag-js/core
にある StateMachine
でやれないかな、等はもうちょっと読んでみたい。
SFCの例が無い!と書いたが、後続にあるコンポーネント単位のドキュメントでは書いてあった、、
ただ、下記を総量として見た時に、ドキュメント側と個数の乖離がある様な(Toggleが無かったり)
もはやタイトルの内容から逸脱してきたが、Segun Adebayo氏のブログをベースに、Chakura UIのマイクロプロジェクトたち全般にも目を向けることにした。
👆がHTML+Zagで作ったChakura製のヘッドレスUIコンポーネントらしい。ちょっと使ったらCheckboxの最もシンプルな構成を作ったタイミングでエラー落ちした。SSR周りのバグの様子。
ヘッドレスUIコンポーネント+Pandaでフロントエンド開発は相当快適さが上がると思うので、ヘッドレス側でArk以外に有用なライブラリがあれば、世の中相当生きやすくなるのでは、との希望が。
有力なのはHeadless UIとRadixか。
色々見た限りは、Panda CSSとRadixの取り合わせが一番良さそうだな、と感じた。Radix-Vueはプリミティブコンポーネントのサポートが無い(厳密に言えばあるのだが、WAI-ARIAまで考慮した感じと言うよりは、複合コンポーネントを作るための素程度の扱い)ため、複合コンポーネントの状態管理機構をアウトソースするぐらいのイメージでヘッドレスコンポーネントライブラリは使いたい。