mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-21 15:31:46 +01:00
chore: update components
This commit is contained in:
@@ -6,8 +6,9 @@
|
||||
</slot>
|
||||
</MenuButton>
|
||||
|
||||
<div ref="container" :class="containerClass">
|
||||
<div v-if="open" ref="container" :class="containerClass">
|
||||
<transition
|
||||
appear
|
||||
enter-active-class="transition duration-100 ease-out"
|
||||
enter-from-class="transform scale-95 opacity-0"
|
||||
enter-to-class="transform scale-100 opacity-100"
|
||||
@@ -15,7 +16,7 @@
|
||||
leave-from-class="transform scale-100 opacity-100"
|
||||
leave-to-class="transform scale-95 opacity-0"
|
||||
>
|
||||
<MenuItems :class="itemsClass">
|
||||
<MenuItems :class="itemsClass" static>
|
||||
<div v-for="(subItems, index) of items" :key="index" class="py-1">
|
||||
<MenuItem v-for="(item, subIndex) of subItems" :key="subIndex" v-slot="{ active, disabled }">
|
||||
<Component v-bind="item" :is="(item.to && 'NuxtLink') || (item.href && 'a') || 'button'" :class="resolveItemClass({ active, disabled })" @click="onItemClick(item)">
|
||||
@@ -97,14 +98,6 @@ export default {
|
||||
type: String,
|
||||
default: 'mr-3 h-5 w-5 text-tw-gray-400 group-hover:text-tw-gray-500'
|
||||
}
|
||||
// openDelay: {
|
||||
// type: Number,
|
||||
// default: 100
|
||||
// },
|
||||
// closeDelay: {
|
||||
// type: Number,
|
||||
// default: 0
|
||||
// },
|
||||
},
|
||||
setup (props) {
|
||||
const [trigger, container] = usePopper({
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
class="flex items-center px-2 py-2 text-sm font-medium rounded-md group focus:outline-none"
|
||||
:active-class="activeVariantClass"
|
||||
:inactive-class="variantClass"
|
||||
@click.native="link.click && link.click()"
|
||||
@keyup.enter.native="$event.target.blur()"
|
||||
@click="link.click && link.click()"
|
||||
@keyup.enter="$event.target.blur()"
|
||||
>
|
||||
<slot name="icon" :link="link">
|
||||
<Icon
|
||||
|
||||
@@ -7,54 +7,34 @@
|
||||
as="template"
|
||||
enter="ease-out duration-300"
|
||||
enter-from="opacity-0"
|
||||
enter-to="opacity-75"
|
||||
enter-to="opacity-100"
|
||||
leave="ease-in duration-200"
|
||||
leave-from="opacity-75"
|
||||
leave-from="opacity-100"
|
||||
leave-to="opacity-0"
|
||||
entered="opacity-75"
|
||||
>
|
||||
<DialogOverlay class="fixed inset-0 bg-gray-500 transition-opacity" />
|
||||
<DialogOverlay class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
|
||||
</TransitionChild>
|
||||
|
||||
<!-- This element is to trick the browser into centering the modal contents. -->
|
||||
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span>
|
||||
|
||||
<TransitionChild
|
||||
enter="ease-out transform duration-300"
|
||||
as="template"
|
||||
enter="ease-out duration-300"
|
||||
enter-from="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
enter-to="opacity-100 translate-y-0 sm:scale-100"
|
||||
leave="ease-in transform duration-200"
|
||||
leave="ease-in duration-200"
|
||||
leave-from="opacity-100 translate-y-0 sm:scale-100"
|
||||
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<!-- This element is to trick the browser into centering the modal contents. -->
|
||||
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">
|
||||
​
|
||||
</span>
|
||||
|
||||
<Card
|
||||
class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
|
||||
v-bind="$attrs"
|
||||
variant="white"
|
||||
ring-class="sm:ring-1 sm:ring-transparent dark:ring-gray-700"
|
||||
>
|
||||
<template v-if="$slots.header" #header>
|
||||
<slot name="header" />
|
||||
</template>
|
||||
<template v-else-if="title" #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="font-medium sm:text-lg sm:leading-6 text-tw-gray-900">
|
||||
{{ title }}
|
||||
</h2>
|
||||
<div class="flex items-center">
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Close panel"
|
||||
class="rounded-md text-tw-gray-400 hover:text-tw-gray-500 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||
@click="isOpen = false"
|
||||
>
|
||||
<Icon name="heroicons-outline:x" class="w-6 h-6" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<slot />
|
||||
<template v-if="$slots.footer" #footer>
|
||||
<slot name="footer" />
|
||||
@@ -71,7 +51,6 @@
|
||||
import { Dialog, DialogOverlay, TransitionRoot, TransitionChild } from '@headlessui/vue'
|
||||
|
||||
import Card from '../layout/Card'
|
||||
import Icon from '../elements/Icon'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -79,8 +58,7 @@ export default {
|
||||
DialogOverlay,
|
||||
TransitionRoot,
|
||||
TransitionChild,
|
||||
Card,
|
||||
Icon
|
||||
Card
|
||||
},
|
||||
props: {
|
||||
modelValue: {
|
||||
|
||||
@@ -1,211 +1,90 @@
|
||||
<template>
|
||||
<div
|
||||
ref="container"
|
||||
class="inline whitespace-normal"
|
||||
@mouseover="mode === 'hover' ? mouseover() : () => {}"
|
||||
@mouseleave="mode === 'hover' ? mouseleave() : () => {}"
|
||||
>
|
||||
<slot :toggle="toggle" />
|
||||
<Popover v-slot="{ open }" :class="wrapperClass">
|
||||
<PopoverButton ref="trigger" as="div">
|
||||
<slot :open="open">
|
||||
Open
|
||||
</slot>
|
||||
</PopoverButton>
|
||||
|
||||
<Portal to="popover">
|
||||
<div v-if="open" ref="container" :class="containerClass">
|
||||
<transition
|
||||
enter-class="transform scale-95 opacity-0"
|
||||
enter-active-class="transition duration-100 ease-out"
|
||||
enter-to-class="transform scale-100 opacity-100"
|
||||
leave-class="opacity-100"
|
||||
leave-active-class="duration-100 ease-in"
|
||||
leave-to-class="opacity-0"
|
||||
appear
|
||||
enter-active-class="transition ease-out duration-200"
|
||||
enter-from-class="opacity-0 translate-y-1"
|
||||
enter-to-class="opacity-100 translate-y-0"
|
||||
leave-active-class="transition ease-in duration-150"
|
||||
leave-from-class="opacity-100 translate-y-0"
|
||||
leave-to-class="opacity-0 translate-y-1"
|
||||
>
|
||||
<div
|
||||
v-if="show && ready && $slots.content"
|
||||
ref="popover"
|
||||
class="z-30 flex bg-white rounded-md shadow ring-1 ring-gray-200 dark:ring-gray-700"
|
||||
:class="[
|
||||
popoverClass,
|
||||
darken ? 'dark:bg-gray-900' : 'dark:bg-gray-800',
|
||||
mode === 'click' ? '' : 'invisible lg:visible'
|
||||
]"
|
||||
@mouseover="mode === 'hover' ? mouseover() : () => {}"
|
||||
@mouseleave="mode === 'hover' ? mouseleave() : () => {}"
|
||||
>
|
||||
<slot name="content" :toggle="toggle" />
|
||||
</div>
|
||||
<PopoverPanel :class="panelClass" static>
|
||||
<slot name="panel" />
|
||||
</PopoverPanel>
|
||||
</transition>
|
||||
</Portal>
|
||||
</div>
|
||||
</div>
|
||||
</Popover>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { createPopper } from '@popperjs/core'
|
||||
// import { directive as onClickaway } from 'vue-clickaway'
|
||||
import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'
|
||||
|
||||
import { usePopper } from '../../utils'
|
||||
|
||||
export default {
|
||||
// directives: {
|
||||
// onClickaway
|
||||
// },
|
||||
components: {
|
||||
Popover,
|
||||
PopoverButton,
|
||||
PopoverPanel
|
||||
},
|
||||
props: {
|
||||
darken: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
popoverClass: {
|
||||
type: String,
|
||||
default: 'w-auto h-auto'
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'hover',
|
||||
validator (value) {
|
||||
return ['click', 'hover'].includes(value)
|
||||
}
|
||||
},
|
||||
strategy: {
|
||||
type: String,
|
||||
default: 'fixed'
|
||||
},
|
||||
placement: {
|
||||
type: String,
|
||||
default: 'bottom'
|
||||
},
|
||||
openDelay: {
|
||||
type: Number,
|
||||
default: 300
|
||||
strategy: {
|
||||
type: String,
|
||||
default: 'absolute'
|
||||
},
|
||||
closeDelay: {
|
||||
type: Number,
|
||||
default: 100
|
||||
wrapperClass: {
|
||||
type: String,
|
||||
default: 'relative'
|
||||
},
|
||||
ready: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
containerClass: {
|
||||
type: String,
|
||||
default: 'z-10'
|
||||
},
|
||||
panelClass: {
|
||||
type: String,
|
||||
default: 'transform'
|
||||
}
|
||||
},
|
||||
data () {
|
||||
setup (props) {
|
||||
const [trigger, container] = usePopper({
|
||||
placement: props.placement,
|
||||
strategy: props.strategy,
|
||||
modifiers: [{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [0, 8]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'computeStyles',
|
||||
options: {
|
||||
gpuAcceleration: false,
|
||||
adaptive: false
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'preventOverflow',
|
||||
options: {
|
||||
padding: 8
|
||||
}
|
||||
}]
|
||||
})
|
||||
|
||||
return {
|
||||
show: false,
|
||||
instance: null,
|
||||
openTimeout: null,
|
||||
closeTimeout: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
show (value) {
|
||||
this.$emit('show', value)
|
||||
|
||||
if (!value || !this.ready) {
|
||||
// let the 100ms hide animation proceed before destroying the popper instance
|
||||
setTimeout(() => {
|
||||
// if popover reshow, abort destroy
|
||||
if (this.show && this.ready) {
|
||||
return
|
||||
}
|
||||
this.destroyPopper()
|
||||
}, 120)
|
||||
return
|
||||
}
|
||||
|
||||
this.createPopper()
|
||||
},
|
||||
ready (value) {
|
||||
if (!value || !this.show) {
|
||||
// let the 100ms hide animation proceed before destroying the popper instance
|
||||
setTimeout(() => {
|
||||
// if popover reshow, abort destroy
|
||||
if (this.show && this.ready) {
|
||||
return
|
||||
}
|
||||
this.destroyPopper()
|
||||
}, 120)
|
||||
return
|
||||
}
|
||||
|
||||
this.createPopper()
|
||||
}
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.destroyPopper()
|
||||
},
|
||||
methods: {
|
||||
createPopper () {
|
||||
// https://portal-vue.linusb.org/guide/caveats.html#refs
|
||||
this.$nextTick().then(
|
||||
this.$nextTick().then(() => {
|
||||
setTimeout(() => {
|
||||
if (this.instance) {
|
||||
this.instance.forceUpdate()
|
||||
return
|
||||
}
|
||||
|
||||
this.instance = createPopper(this.$refs.container, this.$refs.popover, {
|
||||
strategy: this.strategy,
|
||||
placement: this.placement,
|
||||
modifiers: [
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [0, 8]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'computeStyles',
|
||||
options: {
|
||||
gpuAcceleration: false,
|
||||
adaptive: false
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'preventOverflow',
|
||||
options: {
|
||||
padding: 8
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
}, 1)
|
||||
})
|
||||
)
|
||||
},
|
||||
destroyPopper () {
|
||||
if (this.instance) {
|
||||
this.instance.destroy()
|
||||
this.instance = null
|
||||
}
|
||||
},
|
||||
mouseover () {
|
||||
clearTimeout(this.closeTimeout)
|
||||
this.closeTimeout = null
|
||||
if (this.show) {
|
||||
return
|
||||
}
|
||||
this.openTimeout = this.openTimeout || setTimeout(() => {
|
||||
this.open()
|
||||
this.openTimeout = null
|
||||
}, this.openDelay)
|
||||
},
|
||||
mouseleave () {
|
||||
clearTimeout(this.openTimeout)
|
||||
this.openTimeout = null
|
||||
if (!this.show) {
|
||||
return
|
||||
}
|
||||
this.closeTimeout = this.closeTimeout || setTimeout(() => {
|
||||
this.close()
|
||||
this.closeTimeout = null
|
||||
}, this.closeDelay)
|
||||
},
|
||||
toggle () {
|
||||
this.show = !this.show
|
||||
},
|
||||
open () {
|
||||
this.show = true
|
||||
},
|
||||
close () {
|
||||
this.show = false
|
||||
},
|
||||
onClickaway () {
|
||||
if (this.mode !== 'hover') {
|
||||
this.close()
|
||||
}
|
||||
trigger,
|
||||
container
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user