fix(ui): regression in submenu functionality; layout of low-height input
This commit is contained in:
parent
bd6eecbaba
commit
0101d6cf1e
|
@ -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>
|
||||||
|
|
|
@ -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)()),
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 />
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
|
@ -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" />
|
||||||
|
|
Loading…
Reference in New Issue