👶
[headlessUI]Menuを閉じる方法
始めに
本記事は特定環境でbuildした際に著しくパフォーマンスが落ちるか、build後の静的解析でエラーが発生する可能性があります。
ご注意ください。
概要
- OSSコントリビュートの一環で、headlessUIで構築しているものの挙動を変えたいというissueがあったので対応してみた。
- 課題としては、ミートボールメニュー中にディスクロージャーが存在しているが、ディスクロージャー中のメニューをクリックしても親のミートボールメニューが閉じてくれないので、閉じるように変更したい。
- Nuxtで構築されていたが、今回の件には影響なし。
結論
- Menuコンポーネント下で、MenuButtonを利用すればクリック時にMenuを閉じる挙動になる。
- どうやるかなあ...とか考えてドキュメント眺めてたら答え書いてた。
修正後
ざっくりこんな感じ。
<template>
<Menu as="div" class="relative inline-block text-left">
<div>
<MenuButton
class="justify-center select-none rounded-md text-light-text dark:text-dark-text active:text-light-cta-orange active:dark:text-dark-cta-orange focus-brand"
>
<div>
<Icon name="bi:three-dots-vertical" size="1.5em" />
</div>
</MenuButton>
</div>
<transition
enter-active-class="transition duration-100 ease-out"
enter-from-class="opacity-0 transform scale-95"
enter-to-class="opacity-100 transform scale-100"
leave-active-class="transition duration-75 ease-in"
leave-from-class="opacity-100 transform scale-100"
leave-to-class="opacity-0 transform scale-95"
>
<MenuItems
class="absolute right-0 mt-2 border shadow-lg origin-top-right rounded-md bg-light-content dark:bg-dark-content ring-1 ring-black ring-opacity-5 focus:outline-none border-light-text dark:border-dark-text overflow-clip"
>
<div class="w-full mx-auto grid divide-y grid-row-2">
<Disclosure v-slot="{ open }">
<DisclosureButton
:class="[
open
? 'bg-light-cta-orange dark:bg-dark-cta-orange text-light-content dark:text-dark-content'
: 'text-light-text dark:text-dark-text hover:bg-light-highlight dark:hover:bg-dark-highlight',
'flex w-full items-center pr-6',
]"
>
<div
class="relative z-0 flex items-center w-full px-3 py-2 text-sm font-medium text-left space-x-2"
>
<Icon
v-if="$colorMode.preference == 'system'"
name="bi:circle-half"
/>
<Icon v-if="$colorMode.preference == 'light'" name="bi:sun" />
<Icon
v-else-if="$colorMode.preference == 'dark'"
name="bi:moon"
/>
<p>{{ $t("theme") }}</p>
</div>
<Icon
name="bi:chevron-down"
:class="
open
? 'absolute right-0 mr-2 rotate-180 transform'
: 'absolute right-0 mr-2'
"
/>
</DisclosureButton>
<DisclosurePanel class="px-3 py-2">
<MenuButton
class="flex items-center w-full px-2 py-2 text-sm rounded-md group text-light-text dark:text-dark-text hover:bg-light-highlight dark:hover:bg-dark-highlight"
@click="$colorMode.preference = 'system'"
>
<Icon name="bi:circle-half" size="1em" />
<p class="px-1">System</p>
</MenuButton>
<MenuButton
class="flex items-center w-full px-2 py-2 text-sm rounded-md group text-light-text dark:text-dark-text hover:bg-light-highlight dark:hover:bg-dark-highlight"
@click="$colorMode.preference = 'light'"
>
<Icon name="bi:sun" size="1em" />
<p class="px-1">Light</p>
</MenuButton>
<MenuButton
class="flex items-center w-full px-2 py-2 text-sm rounded-md group text-light-text dark:text-dark-text hover:bg-light-highlight dark:hover:bg-dark-highlight"
@click="$colorMode.preference = 'dark'"
>
<Icon name="bi:moon" size="1em" />
<p class="px-1">Dark</p>
</MenuButton>
</DisclosurePanel>
</Disclosure>
</div>
</MenuItems>
</transition>
</Menu>
</template>
実装検討中のメモ
- Disclosureというコンポーネントが使われていた。関連コンポーネントのDisclosureButtonは、一番近いラップされたコンポーネントの状態を変更する。(DisclosurePannelでラップしていたらそれを変更するっぽい)
- これで解決できそうかなと意気揚々と実装したが、最上位のMenuの状態遷移をさせるには少し機能不足だった。
- ボタンクリックでMenuの状態を変更することも考えたが、状態管理が増えて煩雑になりそうだった。
- UIライブラリだけで完結できないかを模索
最後に
OSSで色んな人とやりとりするの楽しいからおすすめです(´・ω・`)
Discussion