feat(ui-docs): add usability warning; make encapsulating popover state the default example; add example with long list; add TOC
This commit is contained in:
		
							parent
							
								
									e1072b9dbb
								
							
						
					
					
						commit
						adec453e83
					
				| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
<script setup lang="ts">
 | 
			
		||||
import { ref } from 'vue'
 | 
			
		||||
import { SUPPORTED_LOCALES, setI18nLanguage } from '~/init/locale'
 | 
			
		||||
 | 
			
		||||
import Button from "~/components/ui/Button.vue"
 | 
			
		||||
import OptionsButton from "~/components/ui/button/Options.vue"
 | 
			
		||||
| 
						 | 
				
			
			@ -51,22 +52,55 @@ Common uses:
 | 
			
		|||
- Settings menus
 | 
			
		||||
- Context menus (right-click menus)
 | 
			
		||||
 | 
			
		||||
::: warning
 | 
			
		||||
 | 
			
		||||
This component has severe usability issues and cannot be used as-is:
 | 
			
		||||
 | 
			
		||||
- I can't operate the popup with a keyboard. Remove barrier for people not using a mouse (A11y)
 | 
			
		||||
- Switching to submenus is error-prone. When moving cursor into freshly opened submenu, it should not close if the cursor crosses another menu item
 | 
			
		||||
- Large menus disappear. When menus get big, they need to scroll.
 | 
			
		||||
 | 
			
		||||
Common Ui libraries in the Vue ecosystem such as vuetify or shadcn-vue all implement these features. It may be prudent to use their components.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
| Prop   | Data type | Required? | Description                                                |
 | 
			
		||||
| ------ | --------- | --------- | ---------------------------------------------------------- |
 | 
			
		||||
| `open` | Boolean   | No        | Controls whether the popover is open. Defaults to `false`. |
 | 
			
		||||
 | 
			
		||||
## Options button
 | 
			
		||||
[[toc]]
 | 
			
		||||
 | 
			
		||||
The options button (`OptionsButton`) is a stylized button you can use to hide and show your popover. Use [Vue event handling](https://vuejs.org/guide/essentials/event-handling.html) to map the button to a boolean value.
 | 
			
		||||
```vue-html
 | 
			
		||||
<Popover>
 | 
			
		||||
  <template #default="{ toggleOpen }">
 | 
			
		||||
    <OptionsButton @click="toggleOpen" />
 | 
			
		||||
  </template>
 | 
			
		||||
</Popover>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
<Popover>
 | 
			
		||||
  <template #default="{ toggleOpen }">
 | 
			
		||||
    <OptionsButton @click="toggleOpen" />
 | 
			
		||||
  </template>
 | 
			
		||||
</Popover>
 | 
			
		||||
 | 
			
		||||
Destructure the function `toggleOpen` and let
 | 
			
		||||
a [default dropdown button: `OptionsButton`](./button/options.md) trigger it. This way, the state of the component is encapsulated.
 | 
			
		||||
 | 
			
		||||
## Bind to `isOpen`
 | 
			
		||||
 | 
			
		||||
If you want to process or influence the expansion of the menu in the containing component, you can bind it to a `ref`.
 | 
			
		||||
 | 
			
		||||
Use [Vue event handling](https://vuejs.org/guide/essentials/event-handling.html) to map the button to a boolean value.
 | 
			
		||||
 | 
			
		||||
```vue{7}
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
  const open = ref(false)
 | 
			
		||||
  const isOpen = ref(false)
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <Popover v-model:open="open">
 | 
			
		||||
    <OptionsButton @click="open = !open" />
 | 
			
		||||
  <Popover v-model:open="isOpen">
 | 
			
		||||
    <OptionsButton @click="isOpen = !isOpen" />
 | 
			
		||||
  </Popover>
 | 
			
		||||
</template>
 | 
			
		||||
```
 | 
			
		||||
| 
						 | 
				
			
			@ -75,25 +109,27 @@ The options button (`OptionsButton`) is a stylized button you can use to hide an
 | 
			
		|||
  <OptionsButton @click="emptyMenu = !emptyMenu" />
 | 
			
		||||
</Popover>
 | 
			
		||||
 | 
			
		||||
You can also use the `toggleOpen` prop in the `<template #default`> tag if you prefer not to use refs to control the menu's visibility.
 | 
			
		||||
## Customize the dropdown button
 | 
			
		||||
 | 
			
		||||
```vue{8-12}
 | 
			
		||||
```vue
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
const open = ref(false)
 | 
			
		||||
const privacyChoices = ['pod', 'public', 'private']
 | 
			
		||||
const bcPrivacy = ref('pod')
 | 
			
		||||
const open = ref(false);
 | 
			
		||||
const privacyChoices = ["pod", "public", "private"];
 | 
			
		||||
const bcPrivacy = ref("pod");
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <Popover v-model:open="isOpen">
 | 
			
		||||
    <template #default="{ toggleOpen }">
 | 
			
		||||
      <Pill
 | 
			
		||||
      @click="(e) => {
 | 
			
		||||
        console.log('Pill clicked');
 | 
			
		||||
        console.log('Before toggleOpen:', isOpen);
 | 
			
		||||
        toggleOpen();
 | 
			
		||||
        console.log('After toggleOpen:', isOpen);
 | 
			
		||||
      }"
 | 
			
		||||
        @click="
 | 
			
		||||
          (e) => {
 | 
			
		||||
            console.log('Pill clicked');
 | 
			
		||||
            console.log('Before toggleOpen:', isOpen);
 | 
			
		||||
            toggleOpen();
 | 
			
		||||
            console.log('After toggleOpen:', isOpen);
 | 
			
		||||
          }
 | 
			
		||||
        "
 | 
			
		||||
        :blue="bcPrivacy === 'pod'"
 | 
			
		||||
        :red="bcPrivacy === 'public'"
 | 
			
		||||
      >
 | 
			
		||||
| 
						 | 
				
			
			@ -101,7 +137,7 @@ const bcPrivacy = ref('pod')
 | 
			
		|||
      </Pill>
 | 
			
		||||
    </template>
 | 
			
		||||
    <template #items>
 | 
			
		||||
      <PopoverRadio v-model="bcPrivacy" :choices="privacyChoices"/>
 | 
			
		||||
      <PopoverRadio v-model="bcPrivacy" :choices="privacyChoices" />
 | 
			
		||||
    </template>
 | 
			
		||||
  </Popover>
 | 
			
		||||
</template>
 | 
			
		||||
| 
						 | 
				
			
			@ -426,6 +462,19 @@ const privacyChoices = ["private", "pod", "public"];
 | 
			
		|||
  <Popover v-model:open="open">
 | 
			
		||||
    <OptionsButton @click="open = !open" />
 | 
			
		||||
    <template #items>
 | 
			
		||||
      <PopoverSubmenu>
 | 
			
		||||
        <i class="bi bi-music-note-list" />
 | 
			
		||||
        Change language
 | 
			
		||||
        <template #items>
 | 
			
		||||
          <PopoverItem
 | 
			
		||||
            v-for="(language, key) in SUPPORTED_LOCALES"
 | 
			
		||||
            :key="key"
 | 
			
		||||
            @click="setI18nLanguage(key)"
 | 
			
		||||
          >
 | 
			
		||||
            {{ language }}
 | 
			
		||||
          </PopoverItem>
 | 
			
		||||
        </template>
 | 
			
		||||
      </PopoverSubmenu>
 | 
			
		||||
      <PopoverItem>
 | 
			
		||||
        <i class="bi bi-arrow-up-right" />
 | 
			
		||||
        Play next
 | 
			
		||||
| 
						 | 
				
			
			@ -536,6 +585,17 @@ const privacyChoices = ["private", "pod", "public"];
 | 
			
		|||
      <i class="bi bi-arrow-down-right" />
 | 
			
		||||
      Append to queue
 | 
			
		||||
    </PopoverItem>
 | 
			
		||||
    <PopoverSubmenu>
 | 
			
		||||
      <i class="bi bi-music-note-list" />
 | 
			
		||||
      Change language
 | 
			
		||||
      <template #items>
 | 
			
		||||
        <PopoverItem v-for="(language, key) in SUPPORTED_LOCALES"
 | 
			
		||||
        :key="key"
 | 
			
		||||
        @click="setI18nLanguage(key)" >
 | 
			
		||||
          {{ language }}
 | 
			
		||||
        </PopoverItem>
 | 
			
		||||
      </template>
 | 
			
		||||
    </PopoverSubmenu>
 | 
			
		||||
    <PopoverSubmenu>
 | 
			
		||||
      <i class="bi bi-music-note-list" />
 | 
			
		||||
      Add to playlist
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue