mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-31 12:17:54 +01:00
chore: update components
This commit is contained in:
@@ -6,8 +6,9 @@
|
|||||||
</slot>
|
</slot>
|
||||||
</MenuButton>
|
</MenuButton>
|
||||||
|
|
||||||
<div ref="container" :class="containerClass">
|
<div v-if="open" ref="container" :class="containerClass">
|
||||||
<transition
|
<transition
|
||||||
|
appear
|
||||||
enter-active-class="transition duration-100 ease-out"
|
enter-active-class="transition duration-100 ease-out"
|
||||||
enter-from-class="transform scale-95 opacity-0"
|
enter-from-class="transform scale-95 opacity-0"
|
||||||
enter-to-class="transform scale-100 opacity-100"
|
enter-to-class="transform scale-100 opacity-100"
|
||||||
@@ -15,7 +16,7 @@
|
|||||||
leave-from-class="transform scale-100 opacity-100"
|
leave-from-class="transform scale-100 opacity-100"
|
||||||
leave-to-class="transform scale-95 opacity-0"
|
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">
|
<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 }">
|
<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)">
|
<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,
|
type: String,
|
||||||
default: 'mr-3 h-5 w-5 text-tw-gray-400 group-hover:text-tw-gray-500'
|
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) {
|
setup (props) {
|
||||||
const [trigger, container] = usePopper({
|
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"
|
class="flex items-center px-2 py-2 text-sm font-medium rounded-md group focus:outline-none"
|
||||||
:active-class="activeVariantClass"
|
:active-class="activeVariantClass"
|
||||||
:inactive-class="variantClass"
|
:inactive-class="variantClass"
|
||||||
@click.native="link.click && link.click()"
|
@click="link.click && link.click()"
|
||||||
@keyup.enter.native="$event.target.blur()"
|
@keyup.enter="$event.target.blur()"
|
||||||
>
|
>
|
||||||
<slot name="icon" :link="link">
|
<slot name="icon" :link="link">
|
||||||
<Icon
|
<Icon
|
||||||
|
|||||||
@@ -7,54 +7,34 @@
|
|||||||
as="template"
|
as="template"
|
||||||
enter="ease-out duration-300"
|
enter="ease-out duration-300"
|
||||||
enter-from="opacity-0"
|
enter-from="opacity-0"
|
||||||
enter-to="opacity-75"
|
enter-to="opacity-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-in duration-200"
|
||||||
leave-from="opacity-75"
|
leave-from="opacity-100"
|
||||||
leave-to="opacity-0"
|
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>
|
</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
|
<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-from="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
enter-to="opacity-100 translate-y-0 sm:scale-100"
|
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-from="opacity-100 translate-y-0 sm:scale-100"
|
||||||
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
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
|
<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"
|
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"
|
v-bind="$attrs"
|
||||||
variant="white"
|
|
||||||
ring-class="sm:ring-1 sm:ring-transparent dark:ring-gray-700"
|
ring-class="sm:ring-1 sm:ring-transparent dark:ring-gray-700"
|
||||||
>
|
>
|
||||||
<template v-if="$slots.header" #header>
|
<template v-if="$slots.header" #header>
|
||||||
<slot name="header" />
|
<slot name="header" />
|
||||||
</template>
|
</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 />
|
<slot />
|
||||||
<template v-if="$slots.footer" #footer>
|
<template v-if="$slots.footer" #footer>
|
||||||
<slot name="footer" />
|
<slot name="footer" />
|
||||||
@@ -71,7 +51,6 @@
|
|||||||
import { Dialog, DialogOverlay, TransitionRoot, TransitionChild } from '@headlessui/vue'
|
import { Dialog, DialogOverlay, TransitionRoot, TransitionChild } from '@headlessui/vue'
|
||||||
|
|
||||||
import Card from '../layout/Card'
|
import Card from '../layout/Card'
|
||||||
import Icon from '../elements/Icon'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -79,8 +58,7 @@ export default {
|
|||||||
DialogOverlay,
|
DialogOverlay,
|
||||||
TransitionRoot,
|
TransitionRoot,
|
||||||
TransitionChild,
|
TransitionChild,
|
||||||
Card,
|
Card
|
||||||
Icon
|
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
modelValue: {
|
modelValue: {
|
||||||
|
|||||||
@@ -1,211 +1,90 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<Popover v-slot="{ open }" :class="wrapperClass">
|
||||||
ref="container"
|
<PopoverButton ref="trigger" as="div">
|
||||||
class="inline whitespace-normal"
|
<slot :open="open">
|
||||||
@mouseover="mode === 'hover' ? mouseover() : () => {}"
|
Open
|
||||||
@mouseleave="mode === 'hover' ? mouseleave() : () => {}"
|
</slot>
|
||||||
>
|
</PopoverButton>
|
||||||
<slot :toggle="toggle" />
|
|
||||||
|
|
||||||
<Portal to="popover">
|
<div v-if="open" ref="container" :class="containerClass">
|
||||||
<transition
|
<transition
|
||||||
enter-class="transform scale-95 opacity-0"
|
appear
|
||||||
enter-active-class="transition duration-100 ease-out"
|
enter-active-class="transition ease-out duration-200"
|
||||||
enter-to-class="transform scale-100 opacity-100"
|
enter-from-class="opacity-0 translate-y-1"
|
||||||
leave-class="opacity-100"
|
enter-to-class="opacity-100 translate-y-0"
|
||||||
leave-active-class="duration-100 ease-in"
|
leave-active-class="transition ease-in duration-150"
|
||||||
leave-to-class="opacity-0"
|
leave-from-class="opacity-100 translate-y-0"
|
||||||
|
leave-to-class="opacity-0 translate-y-1"
|
||||||
>
|
>
|
||||||
<div
|
<PopoverPanel :class="panelClass" static>
|
||||||
v-if="show && ready && $slots.content"
|
<slot name="panel" />
|
||||||
ref="popover"
|
</PopoverPanel>
|
||||||
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>
|
|
||||||
</transition>
|
</transition>
|
||||||
</Portal>
|
</div>
|
||||||
</div>
|
</Popover>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { createPopper } from '@popperjs/core'
|
import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'
|
||||||
// import { directive as onClickaway } from 'vue-clickaway'
|
|
||||||
|
import { usePopper } from '../../utils'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
// directives: {
|
components: {
|
||||||
// onClickaway
|
Popover,
|
||||||
// },
|
PopoverButton,
|
||||||
|
PopoverPanel
|
||||||
|
},
|
||||||
props: {
|
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: {
|
placement: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'bottom'
|
default: 'bottom'
|
||||||
},
|
},
|
||||||
openDelay: {
|
strategy: {
|
||||||
type: Number,
|
type: String,
|
||||||
default: 300
|
default: 'absolute'
|
||||||
},
|
},
|
||||||
closeDelay: {
|
wrapperClass: {
|
||||||
type: Number,
|
type: String,
|
||||||
default: 100
|
default: 'relative'
|
||||||
},
|
},
|
||||||
ready: {
|
containerClass: {
|
||||||
type: Boolean,
|
type: String,
|
||||||
default: true
|
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 {
|
return {
|
||||||
show: false,
|
trigger,
|
||||||
instance: null,
|
container
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user