mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-24 00:40:34 +01:00
feat(Drawer): handle direction + handle props
This commit is contained in:
@@ -10,7 +10,7 @@ const appConfig = _appConfig as AppConfig & { ui: { drawer: Partial<typeof theme
|
||||
|
||||
const drawer = tv({ extend: tv(theme), ...(appConfig.ui?.drawer || {}) })
|
||||
|
||||
export interface DrawerProps extends Pick<DrawerRootProps, 'activeSnapPoint' | 'closeThreshold' | 'defaultOpen' | 'direction' | 'dismissible' | 'fadeFromIndex' | 'fixed' | 'modal' | 'nested' | 'open' | 'scrollLockTimeout' | 'shouldScaleBackground' | 'snapPoints'> {
|
||||
export interface DrawerProps extends Pick<DrawerRootProps, 'activeSnapPoint' | 'closeThreshold' | 'defaultOpen' | 'direction' | 'dismissible' | 'fadeFromIndex' | 'fixed' | 'modal' | 'nested' | 'direction' | 'open' | 'scrollLockTimeout' | 'shouldScaleBackground' | 'snapPoints'> {
|
||||
/**
|
||||
* The element or component this component should render as.
|
||||
* @defaultValue 'div'
|
||||
@@ -25,6 +25,11 @@ export interface DrawerProps extends Pick<DrawerRootProps, 'activeSnapPoint' | '
|
||||
* @defaultValue true
|
||||
*/
|
||||
overlay?: boolean
|
||||
/**
|
||||
* Render a handle on the drawer.
|
||||
* @defaultValue true
|
||||
*/
|
||||
handle?: boolean
|
||||
/**
|
||||
* Render the drawer in a portal.
|
||||
* @defaultValue true
|
||||
@@ -49,23 +54,26 @@ export interface DrawerSlots {
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { toRef } from 'vue'
|
||||
import { computed, toRef } from 'vue'
|
||||
import { useForwardPropsEmits } from 'radix-vue'
|
||||
import { DrawerRoot, DrawerTrigger, DrawerPortal, DrawerOverlay, DrawerContent, DrawerTitle, DrawerDescription } from 'vaul-vue'
|
||||
import { reactivePick } from '@vueuse/core'
|
||||
|
||||
const props = withDefaults(defineProps<DrawerProps>(), {
|
||||
direction: 'bottom',
|
||||
portal: true,
|
||||
overlay: true
|
||||
overlay: true,
|
||||
handle: true
|
||||
})
|
||||
const emits = defineEmits<DrawerEmits>()
|
||||
const slots = defineSlots<DrawerSlots>()
|
||||
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'activeSnapPoint', 'closeThreshold', 'defaultOpen', 'dismissible', 'fadeFromIndex', 'fixed', 'modal', 'nested', 'open', 'scrollLockTimeout', 'shouldScaleBackground', 'snapPoints'), emits)
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'activeSnapPoint', 'closeThreshold', 'defaultOpen', 'dismissible', 'fadeFromIndex', 'fixed', 'modal', 'nested', 'direction', 'open', 'scrollLockTimeout', 'shouldScaleBackground', 'snapPoints'), emits)
|
||||
const contentProps = toRef(() => props.content)
|
||||
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
const ui = drawer()
|
||||
const ui = computed(() => drawer({
|
||||
direction: props.direction
|
||||
}))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -79,7 +87,7 @@ const ui = drawer()
|
||||
|
||||
<DrawerContent :class="ui.content({ class: [props.class, props.ui?.content] })" v-bind="contentProps">
|
||||
<slot name="handle">
|
||||
<div :class="ui.handle({ class: props.ui?.handle })" />
|
||||
<div v-if="handle" :class="ui.handle({ class: props.ui?.handle })" />
|
||||
</slot>
|
||||
|
||||
<slot name="content">
|
||||
|
||||
@@ -1,13 +1,46 @@
|
||||
export default {
|
||||
slots: {
|
||||
overlay: 'fixed inset-0 z-50 bg-gray-200/75 dark:bg-gray-800/75',
|
||||
content: 'fixed inset-x-0 bottom-0 z-50 mt-24 bg-white dark:bg-gray-900 ring ring-gray-200 dark:ring-gray-800 rounded-t-lg h-auto max-h-[96%] flex flex-col focus:outline-none',
|
||||
handle: 'mx-auto w-12 my-4 h-1.5 shrink-0 rounded-full bg-gray-200 dark:bg-gray-700',
|
||||
container: 'mx-auto w-full max-w-md flex flex-col gap-4 px-4 pb-8 overflow-y-auto',
|
||||
content: 'fixed z-50 bg-white dark:bg-gray-900 ring ring-gray-200 dark:ring-gray-800 flex focus:outline-none',
|
||||
handle: 'shrink-0 rounded-full bg-gray-200 dark:bg-gray-700',
|
||||
container: 'w-full flex flex-col gap-4 p-4 overflow-y-auto',
|
||||
header: '',
|
||||
title: 'text-gray-900 dark:text-white font-semibold',
|
||||
description: 'mt-1 text-gray-500 dark:text-gray-400 text-sm',
|
||||
body: 'flex-1',
|
||||
footer: 'flex flex-col gap-1.5'
|
||||
}
|
||||
},
|
||||
variants: {
|
||||
direction: {
|
||||
top: {
|
||||
content: 'top-0 mb-24 flex-col-reverse rounded-b-lg',
|
||||
handle: 'mb-4'
|
||||
},
|
||||
right: {
|
||||
content: 'right-4 flex-row',
|
||||
handle: 'ml-4'
|
||||
},
|
||||
bottom: {
|
||||
content: 'bottom-0 mt-24 flex-col rounded-t-lg',
|
||||
handle: 'mt-4'
|
||||
},
|
||||
left: {
|
||||
content: 'left-4 flex-row-reverse',
|
||||
handle: 'mr-4'
|
||||
}
|
||||
}
|
||||
},
|
||||
compoundVariants: [{
|
||||
direction: ['top', 'bottom'],
|
||||
class: {
|
||||
content: 'inset-x-0 h-auto max-h-[96%]',
|
||||
handle: 'w-12 h-1.5 mx-auto'
|
||||
}
|
||||
}, {
|
||||
direction: ['right', 'left'],
|
||||
class: {
|
||||
content: 'inset-y-4 w-auto max-w-[96%] rounded-lg after:hidden',
|
||||
handle: 'h-12 w-1.5 mt-auto mb-auto'
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user