Closed16

Zag.js w/ Vue SFC

hctaw_srphctaw_srp

https://zagjs.com/

コンポーネントのstateハンドリングやアクセシビリティに関連する属性の振り出しを移譲出来る Zag.js をテスト書きしたが、Chakura UIがReactベースなこともあり、Vueのサンプルが使い物にならなかったので、スクラップで簡単に整理。

hctaw_srphctaw_srp

Vueで jsx tsx の類を利用するのもバカらしいので、vue でSFCとして書きたいので、サンプルをベースにモダン?なSFCでリライトをかけたい。

hctaw_srphctaw_srp

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
hctaw_srphctaw_srp

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>
hctaw_srphctaw_srp

Zag本体がカバーしてくれる内容はめちゃくちゃ良さそう。アクセシビリティも加味した属性設計は網羅感を出すのが大変だし、トグルの様なstateに紐付く挙動のコンポーネントも基盤をささっと作ってくれる。

hctaw_srphctaw_srp

ただし、ドキュメントがガバガバ感がある点はまだまだベータ版ゆえか。Panda CSSは割とちゃんとしているだけに、こちらにも期待(Chakura UI自体がちゃんとした運営体と思うので、あんまり不安も無い)

hctaw_srphctaw_srp

Zagをもうちょっと遊びながら、ドキュメントのちょっとした修正コード等あれば、このスクラップに書き足すことにしよう。

hctaw_srphctaw_srp

例えば、State Send は既存部品の物を渡したいが、connect 箇所、つまりイベント毎に再計算されてリフレッシュされる各種属性群の生成ロジックをカスタマイズしたい場合、State Send は既存部品の型情報を利用し、型安全に処理を書きたくなる。

が、node_modules を掘り下げる限り、部品パッケージの中で型をexposeしている様子が無い。

hctaw_srphctaw_srp

State Send を自前で作った場合の型定義もやり用があるのかな、、@zag-js/core にある StateMachine でやれないかな、等はもうちょっと読んでみたい。

hctaw_srphctaw_srp

https://github.com/chakra-ui/ark

👆がHTML+Zagで作ったChakura製のヘッドレスUIコンポーネントらしい。ちょっと使ったらCheckboxの最もシンプルな構成を作ったタイミングでエラー落ちした。SSR周りのバグの様子。

hctaw_srphctaw_srp

ヘッドレスUIコンポーネント+Pandaでフロントエンド開発は相当快適さが上がると思うので、ヘッドレス側でArk以外に有用なライブラリがあれば、世の中相当生きやすくなるのでは、との希望が。

有力なのはHeadless UIとRadixか。

https://headlessui.com/

https://www.radix-vue.com/

hctaw_srphctaw_srp

色々見た限りは、Panda CSSとRadixの取り合わせが一番良さそうだな、と感じた。Radix-Vueはプリミティブコンポーネントのサポートが無い(厳密に言えばあるのだが、WAI-ARIAまで考慮した感じと言うよりは、複合コンポーネントを作るための素程度の扱い)ため、複合コンポーネントの状態管理機構をアウトソースするぐらいのイメージでヘッドレスコンポーネントライブラリは使いたい。

このスクラップは2023/09/10にクローズされました