fix(ui): regression in submenu functionality; layout of low-height input

This commit is contained in:
upsiflu 2025-03-09 13:07:38 +01:00
parent bd6eecbaba
commit 0101d6cf1e
8 changed files with 48 additions and 45 deletions

View File

@ -117,7 +117,7 @@ const model = defineModel<string|number>({ required: true })
class="input-right show-password" class="input-right show-password"
title="toggle visibility" title="toggle visibility"
@click="showPassword = !showPassword" @click="showPassword = !showPassword"
@blur="(e) => { console.log(e.relatedTarget); if (e.relatedTarget && 'value' in e.relatedTarget && e.relatedTarget.value === model) showPassword = showPassword; else showPassword = false; }" @blur="(e) => { if (e.relatedTarget && 'value' in e.relatedTarget && e.relatedTarget.value === model) showPassword = showPassword; else showPassword = false; }"
> >
<i class="bi bi-eye" /> <i class="bi bi-eye" />
</button> </button>

View File

@ -19,7 +19,7 @@ const columnWidth = props.columnWidth ?? '46px'
const maybeGap = Object.entries(props).find( const maybeGap = Object.entries(props).find(
([key, value]) => value === true && key.startsWith('gap')) ([key, value]) => value === true && key.startsWith('gap'))
const gapWidth = maybeGap ? `${maybeGap[0].replace('gap', '')}px` : '32px' const gapWidth = maybeGap ? `${maybeGap[0].replace('gap', '').replace('-', '')}px` : '32px'
const attributes = computed(() => ({ const attributes = computed(() => ({
...color(props)(width(props)()), ...color(props)(width(props)()),

View File

@ -12,7 +12,7 @@ import { type ColorProps, type DefaultProps, type RaisedProps, color } from '~/c
*/ */
const open = defineModel<boolean>({ default: false }) const isOpen = defineModel<boolean>({ default: false })
const { positioning = 'vertical', ...colorProps } = defineProps<{ const { positioning = 'vertical', ...colorProps } = defineProps<{
positioning?:'horizontal' | 'vertical' positioning?:'horizontal' | 'vertical'
@ -27,13 +27,13 @@ const inSlot = ref()
const mobileClickOutside = (event: MouseEvent) => { const mobileClickOutside = (event: MouseEvent) => {
const inPopover = !!(event.target as HTMLElement).closest('.funkwhale.popover') const inPopover = !!(event.target as HTMLElement).closest('.funkwhale.popover')
if (isMobile.value && !inPopover) { if (isMobile.value && !inPopover) {
open.value = false isOpen.value = false
} }
} }
onClickOutside(popover, async (event) => { onClickOutside(popover, async (event) => {
const inPopover = !!(event.target as HTMLElement).closest('.funkwhale.popover') const inPopover = !!(event.target as HTMLElement).closest('.funkwhale.popover')
if (!isMobile.value && !inPopover) { if (!isMobile.value && !inPopover) {
open.value = false isOpen.value = false
} }
}, { ignore: [slot] }) }, { ignore: [slot] })
@ -44,7 +44,7 @@ const { width: popoverWidth, height: popoverHeight } = useElementBounding(popove
windowScroll: false windowScroll: false
}) })
whenever(open, update, { immediate: true }) whenever(isOpen, update, { immediate: true })
const { width: screenWidth, height: screenHeight } = useScreenSize() const { width: screenWidth, height: screenHeight } = useScreenSize()
@ -93,9 +93,9 @@ if (!stack) {
provide(POPOVER_INJECTION_KEY, stack = shallowReactive([])) provide(POPOVER_INJECTION_KEY, stack = shallowReactive([]))
} }
stack.push(open) stack.push(isOpen)
onScopeDispose(() => { onScopeDispose(() => {
stack?.splice(stack.indexOf(open), 1) stack?.splice(stack.indexOf(isOpen), 1)
}) })
// Provide context for child items // Provide context for child items
@ -107,14 +107,14 @@ provide(POPOVER_CONTEXT_INJECTION_KEY, {
// Closing // Closing
const closeChild = () => { const closeChild = () => {
const ref = stack?.[stack.indexOf(open) + 1] const ref = stack?.[stack.indexOf(isOpen) + 1]
if (!ref) return if (!ref) return
ref.value = false ref.value = false
} }
// Recursively close popover tree // Recursively close popover tree
watch(open, (isOpen) => { watch(isOpen, (isOpen) => {
if (isOpen) return if (isOpen) return
closeChild() closeChild()
}) })
@ -128,15 +128,15 @@ watch(open, (isOpen) => {
> >
<slot <slot
ref="inSlot" ref="inSlot"
:is-open="open" :is-open="isOpen"
:toggle-open="() => open = !open" :toggle-open="() => isOpen = !isOpen"
:open="() => open = true" :open="() => isOpen = true"
:close="() => open = false" :close="() => isOpen = false"
/> />
</div> </div>
<teleport <teleport
v-if="open" v-if="isOpen"
to="body" to="body"
> >
<div <div

View File

@ -62,7 +62,7 @@
left: 0; left: 0;
bottom: 0; bottom: 0;
height: 48px; height: 100%;
min-width: 48px; min-width: 48px;
display: flex; display: flex;
@ -80,7 +80,7 @@
position: absolute; position: absolute;
right: 0px; right: 0px;
bottom: 0px; bottom: 0px;
height: 48px; height: 100%;
min-width: 48px; min-width: 48px;
display: flex; display: flex;

View File

@ -5,7 +5,7 @@ import { POPOVER_CONTEXT_INJECTION_KEY, type PopoverContext } from '~/injection-
import Button from '~/components/ui/Button.vue' import Button from '~/components/ui/Button.vue'
const setId = defineEmit<[value: number]>('internal:id') const emit = defineEmits<{ setId: [value: number] }>()
const { parentPopoverContext, to } = defineProps<{ const { parentPopoverContext, to } = defineProps<{
parentPopoverContext?: PopoverContext; parentPopoverContext?: PopoverContext;
@ -18,7 +18,7 @@ const { items, hoveredItem } = parentPopoverContext ?? inject(POPOVER_CONTEXT_IN
}) })
const id = items.value++ const id = items.value++
setId(id) emit('setId', id)
</script> </script>
<template> <template>
@ -34,8 +34,9 @@ setId(id)
/> />
<slot /> <slot />
<div class="after" /> <div class="after">
<slot name="after" /> <slot name="after" />
</div>
</a> </a>
<RouterLink <RouterLink
v-else-if="to" v-else-if="to"
@ -49,13 +50,15 @@ setId(id)
/> />
<slot /> <slot />
<div class="after" /> <div class="after">
<slot name="after" /> <slot name="after" />
</div>
</RouterLink> </RouterLink>
<Button <Button
v-else v-else
ghost ghost
thin-font thin-font
v-bind="$attrs"
style=" style="
width: 100%; width: 100%;
textAlign: left; textAlign: left;
@ -80,7 +83,6 @@ setId(id)
<style lang="scss"> <style lang="scss">
.popover .popover-item { .popover .popover-item {
cursor: pointer; cursor: pointer;
color: var(--color) !important;
text-decoration: none; text-decoration: none;
padding: 0px 8px; padding: 0px 8px;
height: 32px; height: 32px;
@ -116,6 +118,7 @@ setId(id)
} }
span { span {
width: 100%; width: 100%;
position: relative;
i { i {
font-size: 14px; font-size: 14px;
} }
@ -123,8 +126,13 @@ setId(id)
margin-right: 14px !important; margin-right: 14px !important;
} }
.after { .after {
margin-right: 0px; position: absolute;
float: right; right: -12px;
top: 0;
height: 100%;
display: flex;
place-items: center;
gap: 8px;
} }
} }
} }

View File

@ -10,22 +10,22 @@ const context = inject(POPOVER_CONTEXT_INJECTION_KEY, {
hoveredItem: ref(-2) hoveredItem: ref(-2)
}) })
const open = ref(false) const isOpen = ref(false)
const id = ref(-1) const id = ref(-1)
watchEffect(() => { watchEffect(() => {
open.value = context.hoveredItem.value === id.value isOpen.value = context.hoveredItem.value === id.value
}) })
</script> </script>
<template> <template>
<Popover <Popover
v-model="open" v-model="isOpen"
positioning="horizontal" positioning="horizontal"
> >
<PopoverItem <PopoverItem
:parent-popover-context="context" :parent-popover-context="context"
class="submenu" class="submenu"
@click="open = !open" @click="isOpen = !isOpen"
@internal:id="id = $event" @internal:id="id = $event"
> >
<slot /> <slot />

View File

@ -93,8 +93,3 @@ export const align = <TProps extends Partial<AlignmentProps>>(
(Object.entries(defaults)) as Entries<Partial<AlignmentProps>> (Object.entries(defaults)) as Entries<Partial<AlignmentProps>>
)).map(getStyle(props)) )).map(getStyle(props))
) )
const trace = <T extends unknown>(a:T):T => {
console.log(a)
return a
}

View File

@ -190,7 +190,7 @@ const bcPrivacy = ref("pod");
<Popover v-model="isOpen"> <Popover v-model="isOpen">
<template #default="{ toggleOpen }"> <template #default="{ toggleOpen }">
<Pill <Pill
@click="(e) => { @click="() => {
console.log('Pill clicked'); console.log('Pill clicked');
console.log('Before toggleOpen:', isOpen); console.log('Before toggleOpen:', isOpen);
toggleOpen(); toggleOpen();
@ -397,12 +397,12 @@ To create more complex menus, you can use submenus (`PopoverSubmenu`). Submenus
```vue{10-18} ```vue{10-18}
<script setup lang="ts"> <script setup lang="ts">
const bc = ref(false) const bc = ref(false)
const open = ref(false) const isOpen = ref(false)
</script> </script>
<template> <template>
<Popover v-model="open"> <Popover v-model="isOpen">
<OptionsButton @click="open = !open" /> <OptionsButton @click="isOpen = !isOpen" />
<template #items> <template #items>
<PopoverSubmenu> <PopoverSubmenu>
<i class="bi bi-collection" /> <i class="bi bi-collection" />
@ -442,12 +442,12 @@ You can add extra items to the right hand side of a popover item by nesting them
const bc = ref(false) const bc = ref(false)
const privacyChoices = ['public', 'private', 'pod'] const privacyChoices = ['public', 'private', 'pod']
const bcPrivacy = ref('pod') const bcPrivacy = ref('pod')
const open = ref(false) const isOpen = ref(false)
</script> </script>
<template> <template>
<Popover v-model="open"> <Popover v-model="isOpen">
<OptionsButton @click="open = !open" /> <OptionsButton @click="isOpen = !isOpen" />
<template #items> <template #items>
<PopoverSubmenu> <PopoverSubmenu>
<i class="bi bi-collection" /> <i class="bi bi-collection" />
@ -552,7 +552,7 @@ Here is an example of a completed menu containing all supported features.
```vue ```vue
<script setup lang="ts"> <script setup lang="ts">
const open = ref(false); const isOpen = ref(false);
const bc = ref(false); const bc = ref(false);
const cc = ref(false); const cc = ref(false);
const share = ref(false); const share = ref(false);
@ -562,8 +562,8 @@ const privacyChoices = ["private", "pod", "public"];
</script> </script>
<template> <template>
<Popover v-model="open"> <Popover v-model="isOpen">
<OptionsButton @click="open = !open" /> <OptionsButton @click="isOpen = !isOpen" />
<template #items> <template #items>
<PopoverSubmenu> <PopoverSubmenu>
<i class="bi bi-music-note-list" /> <i class="bi bi-music-note-list" />