mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-19 22:41:42 +01:00
chore(Collapsible): new component
This commit is contained in:
@@ -5,7 +5,7 @@ useHead({
|
||||
}
|
||||
})
|
||||
|
||||
const components = ['button', 'tooltip']
|
||||
const components = ['button', 'collapsible', 'tooltip']
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
11
playground/pages/collapsible.vue
Normal file
11
playground/pages/collapsible.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<div class="flex gap-1.5">
|
||||
<UCollapsible>
|
||||
<UButton label="Open" />
|
||||
|
||||
<template #content>
|
||||
<div class="bg-red-500 h-12" />
|
||||
</template>
|
||||
</UCollapsible>
|
||||
</div>
|
||||
</template>
|
||||
74
src/runtime/components/Collapsible.vue
Normal file
74
src/runtime/components/Collapsible.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<script lang="ts">
|
||||
import { tv } from 'tailwind-variants'
|
||||
import type { CollapsibleRootProps, CollapsibleRootEmits } from 'radix-vue'
|
||||
import appConfig from '#build/app.config'
|
||||
import theme from '#build/ui/collapsible'
|
||||
|
||||
const collapsible = tv({ extend: tv(theme), ...(appConfig.ui?.collapsible || {}) })
|
||||
|
||||
export interface CollapsibleProps extends Omit<CollapsibleRootProps, 'as' | 'asChild'> {
|
||||
content?: string
|
||||
class?: any
|
||||
ui?: Partial<typeof collapsible.slots>
|
||||
}
|
||||
|
||||
export interface CollapsibleEmits extends CollapsibleRootEmits {}
|
||||
|
||||
export interface CollapsibleSlots {
|
||||
default(): any
|
||||
content(): any
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { CollapsibleRoot, CollapsibleTrigger, CollapsibleContent, useForwardPropsEmits } from 'radix-vue'
|
||||
import { reactivePick } from '@vueuse/core'
|
||||
|
||||
defineOptions({ inheritAttrs: false })
|
||||
|
||||
const props = defineProps<CollapsibleProps>()
|
||||
const emits = defineEmits<CollapsibleEmits>()
|
||||
const slots = defineSlots<CollapsibleSlots>()
|
||||
|
||||
const forwardRoot = useForwardPropsEmits(reactivePick(props, 'defaultOpen', 'open', 'disabled'), emits)
|
||||
|
||||
// FIXME: Cannot extend multiple times
|
||||
// const ui = computed(() => tv({ extend: collapsible, slots: props.ui })())
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
const ui = computed(() => collapsible())
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CollapsibleRoot v-bind="forwardRoot">
|
||||
<CollapsibleTrigger as-child>
|
||||
<slot />
|
||||
</CollapsibleTrigger>
|
||||
|
||||
<CollapsibleContent v-bind="$attrs" :class="ui.content({ class: props.class })">
|
||||
<slot name="content">
|
||||
{{ content }}
|
||||
</slot>
|
||||
</CollapsibleContent>
|
||||
</CollapsibleRoot>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
@keyframes collapsibleSlideDown {
|
||||
from {
|
||||
height: 0;
|
||||
}
|
||||
to {
|
||||
height: var(--radix-collapsible-content-height);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes collapsibleSlideUp {
|
||||
from {
|
||||
height: var(--radix-collapsible-content-height);
|
||||
}
|
||||
to {
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
5
src/theme/collapsible.ts
Normal file
5
src/theme/collapsible.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export default {
|
||||
slots: {
|
||||
content: 'data-[state=open]:animate-[collapsibleSlideDown_200ms_ease-out] data-[state=closed]:animate-[collapsibleSlideUp_200ms_ease-out] overflow-hidden'
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
export { default as button } from './button'
|
||||
export { default as collapsible } from './collapsible'
|
||||
export { default as container } from './container'
|
||||
export { default as icons } from './icons'
|
||||
export { default as tooltip } from './tooltip'
|
||||
Reference in New Issue
Block a user