mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-30 11:47:55 +01:00
chore: update
This commit is contained in:
@@ -62,10 +62,10 @@ const sections = [
|
|||||||
{ label: 'Getting Started', links: [{ label: 'Usage', to: '/' }, { label: 'Examples', to: '/examples' }, { label: 'Migration', to: '/migration' }, { label: 'Dark mode', to: '/dark' }] },
|
{ label: 'Getting Started', links: [{ label: 'Usage', to: '/' }, { label: 'Examples', to: '/examples' }, { label: 'Migration', to: '/migration' }, { label: 'Dark mode', to: '/dark' }] },
|
||||||
{ label: 'Elements', links: [{ label: 'Avatar', to: '/components/Avatar' }, { label: 'AvatarGroup', to: '/components/AvatarGroup' }, { label: 'Badge', to: '/components/Badge' }, { label: 'Button', to: '/components/Button' }, { label: 'Dropdown', to: '/components/Dropdown' }, { label: 'Icon', to: '/components/Icon' }] },
|
{ label: 'Elements', links: [{ label: 'Avatar', to: '/components/Avatar' }, { label: 'AvatarGroup', to: '/components/AvatarGroup' }, { label: 'Badge', to: '/components/Badge' }, { label: 'Button', to: '/components/Button' }, { label: 'Dropdown', to: '/components/Dropdown' }, { label: 'Icon', to: '/components/Icon' }] },
|
||||||
{ label: 'Feedback', links: [{ label: 'Alert', to: '/components/Alert' }] },
|
{ label: 'Feedback', links: [{ label: 'Alert', to: '/components/Alert' }] },
|
||||||
{ label: 'Forms', links: [{ label: 'Checkbox', to: '/components/Checkbox' }, { label: 'Input', to: '/components/Input' }, { label: 'InputGroup', to: '/components/InputGroup' }, { label: 'Radio', to: '/components/Radio' }, { label: 'RadioGroup', to: '/components/RadioGroup' }, { label: 'Select', to: '/components/Select' }, { label: 'SelectCustom', to: '/components/SelectCustom' }, { label: 'Textarea', to: '/components/Textarea' }, { label: 'Toggle', to: '/components/Toggle' }, { label: 'ToggleGroup', to: '/components/ToggleGroup' }] },
|
{ label: 'Forms', links: [{ label: 'Checkbox', to: '/components/Checkbox' }, { label: 'Input', to: '/components/Input' }, { label: 'FormGroup', to: '/components/FormGroup' }, { label: 'Radio', to: '/components/Radio' }, { label: 'RadioGroup', to: '/components/RadioGroup' }, { label: 'Select', to: '/components/Select' }, { label: 'SelectCustom', to: '/components/SelectCustom' }, { label: 'Textarea', to: '/components/Textarea' }, { label: 'Toggle', to: '/components/Toggle' }] },
|
||||||
{ label: 'Layout', links: [{ label: 'Card', to: '/components/Card' }, { label: 'Container', to: '/components/Container' }] },
|
{ label: 'Layout', links: [{ label: 'Card', to: '/components/Card' }, { label: 'Container', to: '/components/Container' }] },
|
||||||
{ label: 'Navigation', links: [{ label: 'Pills', to: '/components/Pills' }, { label: 'Tabs', to: '/components/Tabs' }, { label: 'VerticalNavigation', to: '/components/VerticalNavigation' }] },
|
{ label: 'Navigation', links: [{ label: 'Pills', to: '/components/Pills' }, { label: 'Tabs', to: '/components/Tabs' }, { label: 'VerticalNavigation', to: '/components/VerticalNavigation' }] },
|
||||||
{ label: 'Overlays', links: [{ label: 'Modal', to: '/components/Modal' }, { label: 'Notification', to: '/components/Notification' }, { label: 'Popover', to: '/components/Popover' }, { label: 'Slideover', to: '/components/Slideover' }, { label: 'Tooltip', to: '/components/Tooltip' }] }
|
{ label: 'Overlays', links: [{ label: 'Modal', to: '/components/Modal' }, { label: 'Notification', to: '/components/Notification' }, { label: 'Popover', to: '/components/Popover' }, { label: 'Tooltip', to: '/components/Tooltip' }] }
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,30 @@
|
|||||||
<template>
|
<template>
|
||||||
<UCard v-if="component" class="relative flex flex-col lg:max-h-[calc(100vh-10rem)]" body-class="px-4 py-5 sm:p-6 relative" footer-class="px-4 py-4 sm:px-6 flex-1 lg:overflow-y-auto">
|
<UCard v-if="component" class="relative flex flex-col lg:max-h-[calc(100vh-10rem)]" body-class="px-4 py-5 sm:p-6 relative" footer-class="px-4 py-4 sm:px-6 flex-1 lg:overflow-y-auto">
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<component :is="is" v-bind="boundProps">
|
<component :is="is" v-bind="{ ...boundProps, ...eventProps }">
|
||||||
<template v-if="defaultProps[params.component].slot" #default>
|
<template v-for="[key, slot] of Object.entries(defaultProps[params.component]?.slots || {}) || []" #[key]>
|
||||||
<component :is="`U${defaultProps[params.component].slot}`" v-bind="defaultProps[defaultProps[params.component].slot]" />
|
<template v-if="Array.isArray(slot)">
|
||||||
|
<div :key="key">
|
||||||
|
<component
|
||||||
|
:is="slot.component ? `U${slot.component}` : slot.tag"
|
||||||
|
v-for="(slot, index) of slot"
|
||||||
|
:key="index"
|
||||||
|
:class="slot.class"
|
||||||
|
v-bind="slot.props || defaultProps[slot.component]"
|
||||||
|
v-html="slot.html"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<component :is="slot.component ? `U${slot.component}` : slot.tag" :key="key" :class="slot.class" v-bind="slot.props || defaultProps[slot.component]" v-html="slot.html" />
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</component>
|
</component>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template v-if="props.length" #footer>
|
<template v-if="props.length" #footer>
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
<component
|
<UFormGroup
|
||||||
:is="prop.type === 'Boolean' ? 'UToggleGroup' : 'UInputGroup'"
|
|
||||||
v-for="prop of props"
|
v-for="prop of props"
|
||||||
:key="prop.key"
|
:key="prop.key"
|
||||||
class="capitalize"
|
class="capitalize"
|
||||||
@@ -54,7 +67,7 @@
|
|||||||
:rows="8"
|
:rows="8"
|
||||||
autoresize
|
autoresize
|
||||||
/>
|
/>
|
||||||
</component>
|
</UFormGroup>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</UCard>
|
</UCard>
|
||||||
@@ -70,6 +83,9 @@ const is = `U${params.component}`
|
|||||||
|
|
||||||
const component = nuxtApp.vueApp.component(is)
|
const component = nuxtApp.vueApp.component(is)
|
||||||
|
|
||||||
|
const toggle = ref(false)
|
||||||
|
const modal = ref(false)
|
||||||
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
Button: {
|
Button: {
|
||||||
label: 'Button text'
|
label: 'Button text'
|
||||||
@@ -115,14 +131,22 @@ const defaultProps = {
|
|||||||
name: 'input',
|
name: 'input',
|
||||||
placeholder: 'Enter text'
|
placeholder: 'Enter text'
|
||||||
},
|
},
|
||||||
InputGroup: {
|
FormGroup: {
|
||||||
name: 'input',
|
name: 'input',
|
||||||
label: 'Input group',
|
label: 'Input group',
|
||||||
slot: 'Input'
|
slots: {
|
||||||
|
default: {
|
||||||
|
component: 'Input',
|
||||||
|
props: {
|
||||||
|
name: 'input',
|
||||||
|
placeholder: 'Works with every form element'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ToggleGroup: {
|
Toggle: {
|
||||||
name: 'input',
|
modelValue: toggle,
|
||||||
label: 'Toggle group'
|
'onUpdate:modelValue': (v) => { toggle.value = v }
|
||||||
},
|
},
|
||||||
Checkbox: {
|
Checkbox: {
|
||||||
name: 'checkbox'
|
name: 'checkbox'
|
||||||
@@ -130,6 +154,20 @@ const defaultProps = {
|
|||||||
Radio: {
|
Radio: {
|
||||||
name: 'radio'
|
name: 'radio'
|
||||||
},
|
},
|
||||||
|
RadioGroup: {
|
||||||
|
name: 'radio',
|
||||||
|
label: 'Radio group',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'Option 1',
|
||||||
|
value: 'option-1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Option 2',
|
||||||
|
value: 'option-2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
Select: {
|
Select: {
|
||||||
name: 'select',
|
name: 'select',
|
||||||
options: ['English', 'Spanish', 'French', 'German', 'Chinese']
|
options: ['English', 'Spanish', 'French', 'German', 'Chinese']
|
||||||
@@ -144,13 +182,40 @@ const defaultProps = {
|
|||||||
id: '1',
|
id: '1',
|
||||||
title: 'Notification title',
|
title: 'Notification title',
|
||||||
callback: 'alert(\'Timer expired\')'
|
callback: 'alert(\'Timer expired\')'
|
||||||
|
},
|
||||||
|
Modal: {
|
||||||
|
modelValue: modal,
|
||||||
|
'onUpdate:modelValue': (v) => { modal.value = v },
|
||||||
|
slots: {
|
||||||
|
default: {
|
||||||
|
tag: 'div',
|
||||||
|
html: 'Modal content'
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
component: 'Button',
|
||||||
|
props: {
|
||||||
|
label: 'Close',
|
||||||
|
onClick: () => { modal.value = false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Popover: {
|
||||||
|
slots: {
|
||||||
|
panel: {
|
||||||
|
tag: 'div',
|
||||||
|
class: 'u-bg-gray-100 rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 p-6',
|
||||||
|
html: 'Popover content'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const componentDefaultProps = defaultProps[params.component] || {}
|
||||||
const { props: componentProps } = await component.__asyncLoader()
|
const { props: componentProps } = await component.__asyncLoader()
|
||||||
|
|
||||||
const refProps = Object.entries(componentProps).map(([key, prop]) => {
|
const refProps = Object.entries(componentProps).map(([key, prop]) => {
|
||||||
const defaultValue = (defaultProps[params.component] || {})[key]
|
const defaultValue = componentDefaultProps[key]
|
||||||
let value = defaultValue || (typeof prop.default === 'function' ? prop.default() : prop.default)
|
let value = defaultValue || (typeof prop.default === 'function' ? prop.default() : prop.default)
|
||||||
let type = prop.type
|
let type = prop.type
|
||||||
if (Array.isArray(type)) {
|
if (Array.isArray(type)) {
|
||||||
@@ -188,6 +253,13 @@ const refProps = Object.entries(componentProps).map(([key, prop]) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const eventProps = Object.entries(componentDefaultProps)
|
||||||
|
.filter(([key]) => !refProps.find(prop => prop.key === key))
|
||||||
|
.reduce((acc, [key, value]) => {
|
||||||
|
acc[key] = value
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
|
||||||
const props = ref(refProps)
|
const props = ref(refProps)
|
||||||
const boundProps = computed(() => {
|
const boundProps = computed(() => {
|
||||||
const bound = {}
|
const bound = {}
|
||||||
|
|||||||
@@ -153,21 +153,14 @@
|
|||||||
</UPopover>
|
</UPopover>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div>
|
<div>
|
||||||
<div class="font-medium text-sm mb-1 u-text-gray-700">
|
<div class="font-medium text-sm mb-1 u-text-gray-700">
|
||||||
Tooltip:
|
Tooltip:
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UTooltip>
|
<UTooltip text="Hello tooltip!">
|
||||||
<UIcon name="heroicons-outline:information-circle" class="w-6 h-6 text-black cursor-pointer" />
|
<UIcon name="heroicons-outline:information-circle" class="w-6 h-6 text-black cursor-pointer" />
|
||||||
</UTooltip>
|
</UTooltip>
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div class="font-medium text-sm mb-1 u-text-gray-700">
|
|
||||||
Toggle:
|
|
||||||
</div>
|
|
||||||
<UToggle v-model="isSwitchEnabled" icon-off="heroicons-solid:x" icon-on="heroicons-solid:check" />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -183,23 +176,21 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UCard @submit.prevent="onSubmit">
|
<UCard @submit.prevent="onSubmit">
|
||||||
<UInputGroup label="Email" name="email" class="mb-3">
|
<UFormGroup label="Email" name="email" class="mb-3" required>
|
||||||
<UInput type="email" name="email" autofocus />
|
<UInput type="email" name="email" required />
|
||||||
</UInputGroup>
|
</UFormGroup>
|
||||||
|
|
||||||
<UInputGroup label="Description" name="description" class="mb-3">
|
<UFormGroup label="Description" name="description" class="mb-3">
|
||||||
<UTextarea v-model="description" type="description" name="description" autoresize />
|
<UTextarea type="description" name="description" autoresize />
|
||||||
</UInputGroup>
|
</UFormGroup>
|
||||||
|
|
||||||
|
<UFormGroup label="Toggle" name="toggle" class="mb-3">
|
||||||
|
<UToggle v-model="isSwitchEnabled" name="toggle" icon-off="heroicons-solid:x" icon-on="heroicons-solid:check" />
|
||||||
|
</UFormGroup>
|
||||||
|
|
||||||
<UButton type="submit" label="Submit" />
|
<UButton type="submit" label="Submit" />
|
||||||
</UCard>
|
</UCard>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <UPopover v-slot="{ open }">
|
|
||||||
<UButton trailing variant="white" :icon="open ? 'heroicons-outline:chevron-up' : 'heroicons-outline:chevron-down'">
|
|
||||||
toto
|
|
||||||
</UButton>
|
|
||||||
</UPopover> -->
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -101,13 +101,6 @@ const components = [
|
|||||||
nuxt3: true,
|
nuxt3: true,
|
||||||
capi: true
|
capi: true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: 'ToggleGroup',
|
|
||||||
to: '/components/ToggleGroup',
|
|
||||||
nuxt3: true,
|
|
||||||
capi: true,
|
|
||||||
preset: true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: 'Alert',
|
label: 'Alert',
|
||||||
to: '/components/Alert'
|
to: '/components/Alert'
|
||||||
@@ -123,8 +116,8 @@ const components = [
|
|||||||
preset: true
|
preset: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'InputGroup',
|
label: 'FormGroup',
|
||||||
to: '/components/InputGroup',
|
to: '/components/FormGroup',
|
||||||
nuxt3: true,
|
nuxt3: true,
|
||||||
capi: true,
|
capi: true,
|
||||||
preset: true
|
preset: true
|
||||||
@@ -201,10 +194,6 @@ const components = [
|
|||||||
nuxt3: true,
|
nuxt3: true,
|
||||||
capi: true
|
capi: true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: 'Slideover',
|
|
||||||
to: '/components/Slideover'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: 'Tooltip',
|
label: 'Tooltip',
|
||||||
to: '/components/Tooltip',
|
to: '/components/Tooltip',
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
v-if="label"
|
v-if="label"
|
||||||
:for="name"
|
:for="name"
|
||||||
:class="labelClass"
|
:class="labelClass"
|
||||||
|
@click="onLabelClick"
|
||||||
>
|
>
|
||||||
{{ label }}
|
{{ label }}
|
||||||
<span v-if="required" :class="requiredClass">*</span>
|
<span v-if="required" :class="requiredClass">*</span>
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
<template>
|
|
||||||
<SwitchGroup as="div">
|
|
||||||
<slot name="label">
|
|
||||||
<div class="flex content-center justify-between">
|
|
||||||
<SwitchLabel
|
|
||||||
v-if="label"
|
|
||||||
:for="name"
|
|
||||||
:class="labelClass"
|
|
||||||
>
|
|
||||||
{{ label }}
|
|
||||||
<span v-if="required" :class="requiredClass">*</span>
|
|
||||||
</SwitchLabel>
|
|
||||||
<span v-if="$slots.hint || hint" :class="hintClass">
|
|
||||||
<slot name="hint">{{ hint }}</slot>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</slot>
|
|
||||||
<div :class="!!label && containerClass">
|
|
||||||
<slot />
|
|
||||||
<p v-if="help" :class="helpClass">
|
|
||||||
{{ help }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</SwitchGroup>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { SwitchGroup, SwitchLabel } from '@headlessui/vue'
|
|
||||||
import $ui from '#build/ui'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
SwitchGroup,
|
|
||||||
SwitchLabel
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
name: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
type: String,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
required: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
help: {
|
|
||||||
type: String,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
hint: {
|
|
||||||
type: String,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
containerClass: {
|
|
||||||
type: String,
|
|
||||||
default: () => $ui.toggleGroup.container
|
|
||||||
},
|
|
||||||
labelClass: {
|
|
||||||
type: String,
|
|
||||||
default: () => $ui.toggleGroup.label
|
|
||||||
},
|
|
||||||
requiredClass: {
|
|
||||||
type: String,
|
|
||||||
default: () => $ui.toggleGroup.required
|
|
||||||
},
|
|
||||||
hintClass: {
|
|
||||||
type: String,
|
|
||||||
default: () => $ui.toggleGroup.hint
|
|
||||||
},
|
|
||||||
helpClass: {
|
|
||||||
type: String,
|
|
||||||
default: () => $ui.toggleGroup.help
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -64,10 +64,6 @@ export default {
|
|||||||
modelValue: {
|
modelValue: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
default: null
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['update:modelValue'],
|
emits: ['update:modelValue'],
|
||||||
|
|||||||
@@ -1,210 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div v-if="showSlideover" ref="container" class="fixed inset-0 z-50 overflow-hidden slideover">
|
|
||||||
<div class="absolute inset-0 overflow-hidden">
|
|
||||||
<transition
|
|
||||||
appear
|
|
||||||
enter-class="opacity-0"
|
|
||||||
enter-active-class="duration-300 ease-out"
|
|
||||||
enter-to-class="opacity-100"
|
|
||||||
leave-class="opacity-100"
|
|
||||||
leave-active-class="duration-200 ease-in"
|
|
||||||
leave-to-class="opacity-0"
|
|
||||||
@before-leave="backdropLeaving = true"
|
|
||||||
@after-leave="backdropLeaving = false"
|
|
||||||
>
|
|
||||||
<div v-if="showBackdrop" class="fixed inset-0 transition-opacity bg-gray-800 sm:bg-opacity-75" @click="open = false" />
|
|
||||||
</transition>
|
|
||||||
|
|
||||||
<section class="absolute inset-y-0 right-0 flex max-w-full sm:pl-16">
|
|
||||||
<transition
|
|
||||||
appear
|
|
||||||
v-bind="transitionProps"
|
|
||||||
@before-leave="contentLeaving = true"
|
|
||||||
@after-leave="contentLeaving = false"
|
|
||||||
>
|
|
||||||
<Card
|
|
||||||
v-if="showContent"
|
|
||||||
v-bind="$attrs"
|
|
||||||
role="dialog"
|
|
||||||
aria-modal="true"
|
|
||||||
class="z-50 flex flex-col w-screen h-screen transition transform shadow-xl sm:max-w-md "
|
|
||||||
body-class="flex-1 overflow-y-auto"
|
|
||||||
ring-class="sm:ring-1 ring-transparent dark:ring-gray-700"
|
|
||||||
variant="white"
|
|
||||||
:rounded="false"
|
|
||||||
>
|
|
||||||
<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:leading-6 sm:text-lg u-text-gray-900">
|
|
||||||
{{ title }}
|
|
||||||
</h2>
|
|
||||||
<div class="flex items-center">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
aria-label="Close panel"
|
|
||||||
class="rounded-md u-text-gray-400 hover:u-text-gray-500 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
|
||||||
@click="open = false"
|
|
||||||
>
|
|
||||||
<Icon name="outline/x" class="w-6 h-6" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<slot />
|
|
||||||
<template v-if="$slots.footer" #footer>
|
|
||||||
<slot name="footer" />
|
|
||||||
</template>
|
|
||||||
</Card>
|
|
||||||
</transition>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// import focusLock from 'dom-focus-lock'
|
|
||||||
|
|
||||||
import Icon from '../elements/Icon'
|
|
||||||
import Card from '../layout/Card'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
Icon,
|
|
||||||
Card
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
value: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
default: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
showSlideover: false,
|
|
||||||
showBackdrop: false,
|
|
||||||
showContent: false,
|
|
||||||
backdropLeaving: false,
|
|
||||||
contentLeaving: false,
|
|
||||||
lock: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
head () {
|
|
||||||
if (this.open) {
|
|
||||||
return {
|
|
||||||
bodyAttrs: {
|
|
||||||
class: ['overflow-hidden']
|
|
||||||
},
|
|
||||||
htmlAttrs: {
|
|
||||||
style: ['touch-action: none;']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
transitionProps () {
|
|
||||||
// Same transition than Modal but only on mobile
|
|
||||||
if (this.$mq === 'xs') {
|
|
||||||
return {
|
|
||||||
enterClass: 'translate-y-4 opacity-0 sm:translate-y-0 sm:scale-95',
|
|
||||||
enterActiveClass: 'duration-300 ease-out',
|
|
||||||
enterToClass: 'translate-y-0 opacity-100 sm:scale-100',
|
|
||||||
leaveClass: 'translate-y-0 opacity-100 sm:scale-100',
|
|
||||||
leaveActiveClass: 'duration-200 ease-in',
|
|
||||||
leaveToClass: 'translate-y-4 opacity-0 sm:translate-y-0 sm:scale-95'
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
enterClass: 'translate-x-full',
|
|
||||||
enterActiveClass: 'transition duration-500 ease-in-out transform sm:duration-700',
|
|
||||||
enterToClass: 'translate-x-0',
|
|
||||||
leaveClass: 'translate-x-0',
|
|
||||||
leaveActiveClass: 'transition duration-500 ease-in-out transform sm:duration-700',
|
|
||||||
leaveToClass: 'translate-x-full'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
leaving () {
|
|
||||||
return this.backdropLeaving || this.contentLeaving
|
|
||||||
},
|
|
||||||
open: {
|
|
||||||
get () {
|
|
||||||
return this.value
|
|
||||||
},
|
|
||||||
set (open) {
|
|
||||||
this.$emit('input', open)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
open: {
|
|
||||||
handler (newValue) {
|
|
||||||
if (newValue) {
|
|
||||||
this.show()
|
|
||||||
} else {
|
|
||||||
this.close()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
immediate: true
|
|
||||||
},
|
|
||||||
leaving (newValue) {
|
|
||||||
if (newValue === false) {
|
|
||||||
this.showSlideover = false
|
|
||||||
this.open = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
beforeDestroy () {
|
|
||||||
if (this.lock) {
|
|
||||||
// focusLock.off(this.$refs.container)
|
|
||||||
this.lock = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
shortcuts: {
|
|
||||||
disabled () {
|
|
||||||
return !this.open
|
|
||||||
},
|
|
||||||
esc: 'esc'
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
show () {
|
|
||||||
this.showSlideover = true
|
|
||||||
this.showBackdrop = true
|
|
||||||
this.showContent = true
|
|
||||||
// Remove current focus if any, avoiding the close button to autofocus and break opening animation.
|
|
||||||
document.activeElement?.blur()
|
|
||||||
this.$nextTick(() => {
|
|
||||||
if (this.$refs.container && !this.lock) {
|
|
||||||
// focusLock.on(this.$refs.container)
|
|
||||||
this.lock = true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
close () {
|
|
||||||
this.showBackdrop = false
|
|
||||||
this.showContent = false
|
|
||||||
if (this.lock) {
|
|
||||||
// focusLock.off(this.$refs.container)
|
|
||||||
this.lock = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
esc () {
|
|
||||||
this.$listeners.close ? this.$listeners.close() : this.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.slideover {
|
|
||||||
margin: env(safe-area-inset-top) 0 0 env(safe-area-inset-left);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -44,7 +44,7 @@ export default {
|
|||||||
},
|
},
|
||||||
wrapperClass: {
|
wrapperClass: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'relative'
|
default: 'relative inline-flex'
|
||||||
},
|
},
|
||||||
containerClass: {
|
containerClass: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|||||||
Reference in New Issue
Block a user