mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-18 14:08:06 +01:00
feat(Accordion): new component (#301)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
committed by
GitHub
parent
0bfe4b01bd
commit
e50f377b94
@@ -3,6 +3,7 @@ module.exports = {
|
||||
extends: ['@nuxt/eslint-config'],
|
||||
rules: {
|
||||
'semi': ['error', 'never'],
|
||||
'quotes': ['error', 'single'],
|
||||
'comma-dangle': ['error', 'never'],
|
||||
'space-before-function-paren': ['error', 'always'],
|
||||
'vue/multi-word-component-names': 0,
|
||||
|
||||
33
docs/components/content/examples/AccordionExampleBasic.vue
Normal file
33
docs/components/content/examples/AccordionExampleBasic.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<script setup>
|
||||
const items = [{
|
||||
label: 'Getting Started',
|
||||
icon: 'i-heroicons-information-circle',
|
||||
defaultOpen: true,
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}, {
|
||||
label: 'Installation',
|
||||
icon: 'i-heroicons-arrow-down-tray',
|
||||
disabled: true,
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}, {
|
||||
label: 'Theming',
|
||||
icon: 'i-heroicons-eye-dropper',
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}, {
|
||||
label: 'Layouts',
|
||||
icon: 'i-heroicons-rectangle-group',
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}, {
|
||||
label: 'Components',
|
||||
icon: 'i-heroicons-square-3-stack-3d',
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}, {
|
||||
label: 'Utilities',
|
||||
icon: 'i-heroicons-wrench-screwdriver',
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UAccordion :items="items" />
|
||||
</template>
|
||||
@@ -0,0 +1,52 @@
|
||||
<script setup>
|
||||
const items = [{
|
||||
label: 'Getting Started',
|
||||
icon: 'i-heroicons-information-circle',
|
||||
defaultOpen: true,
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}, {
|
||||
label: 'Installation',
|
||||
icon: 'i-heroicons-arrow-down-tray',
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}, {
|
||||
label: 'Theming',
|
||||
icon: 'i-heroicons-eye-dropper',
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}, {
|
||||
label: 'Layouts',
|
||||
icon: 'i-heroicons-rectangle-group',
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}, {
|
||||
label: 'Components',
|
||||
icon: 'i-heroicons-square-3-stack-3d',
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}, {
|
||||
label: 'Utilities',
|
||||
icon: 'i-heroicons-wrench-screwdriver',
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UAccordion :items="items" :ui="{ wrapper: 'flex flex-col w-full' }">
|
||||
<template #default="{ item, index, open }">
|
||||
<UButton color="gray" variant="ghost" class="border-b border-gray-200 dark:border-gray-700" :ui="{ rounded :'rounded-none', padding: { sm:'p-3' } }">
|
||||
<template #leading>
|
||||
<div class="w-6 h-6 rounded-full bg-primary-500 dark:bg-primary-400 flex items-center justify-center -my-1">
|
||||
<UIcon :name="item.icon" class="w-4 h-4 text-white dark:text-gray-900" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<span class="truncate">{{ index + 1 }}. {{ item.label }}</span>
|
||||
|
||||
<template #trailing>
|
||||
<UIcon
|
||||
name="i-heroicons-chevron-right-20-solid"
|
||||
class="w-5 h-5 ms-auto transform transition-transform duration-200"
|
||||
:class="[open && 'rotate-90']"
|
||||
/>
|
||||
</template>
|
||||
</UButton>
|
||||
</template>
|
||||
</UAccordion>
|
||||
</template>
|
||||
@@ -0,0 +1,74 @@
|
||||
<script setup>
|
||||
const items = [{
|
||||
label: 'Getting Started',
|
||||
icon: 'i-heroicons-information-circle',
|
||||
defaultOpen: true,
|
||||
slot: 'getting-started'
|
||||
}, {
|
||||
label: 'Installation',
|
||||
icon: 'i-heroicons-arrow-down-tray',
|
||||
defaultOpen: true,
|
||||
slot: 'installation'
|
||||
}, {
|
||||
label: 'Theming',
|
||||
icon: 'i-heroicons-eye-dropper',
|
||||
defaultOpen: true,
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}, {
|
||||
label: 'Layouts',
|
||||
icon: 'i-heroicons-rectangle-group',
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}, {
|
||||
label: 'Components',
|
||||
icon: 'i-heroicons-square-3-stack-3d',
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}, {
|
||||
label: 'Utilities',
|
||||
icon: 'i-heroicons-wrench-screwdriver',
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UAccordion :items="items">
|
||||
<template #item="{ item }">
|
||||
<p class="italic text-gray-900 dark:text-white text-center">
|
||||
{{ item.description }}
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<template #getting-started>
|
||||
<div class="flex flex-col justify-center items-center gap-1">
|
||||
<NuxtLink to="/getting-started" class="flex items-end gap-1.5 font-bold text-xl text-gray-900 dark:text-white">
|
||||
<Logo class="w-8 h-8 text-primary-500 dark:text-primary-400" />
|
||||
|
||||
<span class="hidden sm:block">NuxtLabs</span><span class="sm:text-primary-500 dark:sm:text-primary-400">UI</span>
|
||||
</NuxtLink>
|
||||
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Fully styled and customizable components for Nuxt.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #installation="{ description }">
|
||||
<div class="flex flex-col justify-center items-center gap-1 mb-4">
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white">
|
||||
Installation
|
||||
</h3>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Install <code>@nuxthq/ui</code> dependency to your project:
|
||||
</p>
|
||||
<p>
|
||||
{{ description }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col items-center">
|
||||
<code>$ npm install @nuxtlabs/ui</code>
|
||||
<code>$ nnpm install -D @nuxthq/ui</code>
|
||||
<code>$ pnpm i -D @nuxthq/ui</code>
|
||||
</div>
|
||||
</template>
|
||||
</UAccordion>
|
||||
</template>
|
||||
@@ -8,7 +8,7 @@ const groups = computed(() => {
|
||||
return []
|
||||
}
|
||||
|
||||
const users = await $fetch(`https://jsonplaceholder.typicode.com/users`, { params: { q } })
|
||||
const users = await $fetch('https://jsonplaceholder.typicode.com/users', { params: { q } })
|
||||
|
||||
return users.map(user => ({ id: user.id, label: user.name, suffix: user.email }))
|
||||
}
|
||||
|
||||
258
docs/content/2.elements/5.accordion.md
Normal file
258
docs/content/2.elements/5.accordion.md
Normal file
@@ -0,0 +1,258 @@
|
||||
---
|
||||
github: true
|
||||
description: Display togglable accordion panels.
|
||||
headlessui:
|
||||
label: 'Accordion'
|
||||
to: 'https://headlessui.com/vue/disclosure'
|
||||
navigation:
|
||||
badge: 'Edge'
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
Pass an array to the `items` prop of the Accordion component. Each item can have any property from the [Button](/elements/button) component such as `label`, `icon`, `color`, `variant`, `size`, etc. but also:
|
||||
|
||||
- `slot` - A key to customize the item with a slot.
|
||||
- `content` - The content to display in the panel by default.
|
||||
- `disabled` - Determines whether the item is disabled or not.
|
||||
- `defaultOpen` - Determines whether the item is initially open or closed.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:accordion-example-basic
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const items = [{
|
||||
label: 'Getting Started',
|
||||
icon: 'i-heroicons-information-circle',
|
||||
defaultOpen: true,
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}, {
|
||||
label: 'Installation',
|
||||
icon: 'i-heroicons-arrow-down-tray',
|
||||
disabled: true,
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}, ...]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UAccordion :items="items" />
|
||||
</template>
|
||||
```
|
||||
::
|
||||
|
||||
### Style
|
||||
|
||||
You can also pass any prop from the [Button](/elements/button) component directly to the Accordion component to style the buttons.
|
||||
|
||||
::component-card
|
||||
---
|
||||
baseProps:
|
||||
items:
|
||||
- label: "1. What is NuxtLabs UI?"
|
||||
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
|
||||
- label: "2. Getting Started"
|
||||
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
|
||||
- label: "3. Theming"
|
||||
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
|
||||
- label: "4. Components"
|
||||
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
|
||||
props:
|
||||
color: 'primary'
|
||||
variant: 'soft'
|
||||
size: 'sm'
|
||||
ui:
|
||||
variant:
|
||||
solid: 1
|
||||
outline: 1
|
||||
ghost: 1
|
||||
soft: 1
|
||||
link: 1
|
||||
size:
|
||||
2xs: ''
|
||||
xs: ''
|
||||
sm: ''
|
||||
md: ''
|
||||
lg: ''
|
||||
xl: ''
|
||||
---
|
||||
::
|
||||
|
||||
### Icon
|
||||
|
||||
Use any icon from [Iconify](https://icones.js.org) by setting the `open-icon` and `close-icon` props by using this pattern: `i-{collection_name}-{icon_name}` or change it globally in `ui.accordion.default.openIcon` and `ui.accordion.default.closeIcon`.
|
||||
|
||||
You can also set them to `null` to hide the icons.
|
||||
|
||||
::component-card
|
||||
---
|
||||
baseProps:
|
||||
items:
|
||||
- label: "1. What is NuxtLabs UI?"
|
||||
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
|
||||
- label: "2. Getting Started"
|
||||
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
|
||||
- label: "3. Theming"
|
||||
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
|
||||
- label: "4. Components"
|
||||
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
|
||||
props:
|
||||
openIcon: 'i-heroicons-plus'
|
||||
closeIcon: 'i-heroicons-minus'
|
||||
excludedProps:
|
||||
- openIcon
|
||||
- closeIcon
|
||||
---
|
||||
::
|
||||
|
||||
### Open
|
||||
|
||||
Use the `default-open` prop to open all items by default.
|
||||
|
||||
::component-card
|
||||
---
|
||||
baseProps:
|
||||
items:
|
||||
- label: "What is NuxtLabs UI?"
|
||||
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
|
||||
- label: "Getting Started"
|
||||
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
|
||||
- label: "Theming"
|
||||
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
|
||||
- label: "Components"
|
||||
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
|
||||
props:
|
||||
defaultOpen: true
|
||||
excludedProps:
|
||||
- defaultOpen
|
||||
---
|
||||
::
|
||||
|
||||
## Slots
|
||||
|
||||
You can use slots to customize the buttons and items content of the Accordion.
|
||||
|
||||
### `default`
|
||||
|
||||
Use the `#default` slot to customize the trigger buttons. You will have access to the `item`, `index`, `open` properties and `close` method in the slot scope.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:accordion-example-default-slot
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const items = [...]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UAccordion :items="items" :ui="{ wrapper: 'flex flex-col w-full' }">
|
||||
<template #default="{ item, index, open }">
|
||||
<UButton color="gray" variant="ghost" class="border-b border-gray-200 dark:border-gray-700" :ui="{ rounded :'rounded-none', padding: { sm:'p-3' } }">
|
||||
<template #leading>
|
||||
<div class="w-6 h-6 rounded-full bg-primary-500 dark:bg-primary-400 flex items-center justify-center -my-1">
|
||||
<UIcon :name="item.icon" class="w-4 h-4 text-white dark:text-gray-900" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<span class="truncate">{{ index + 1 }}. {{ item.label }}</span>
|
||||
|
||||
<template #trailing>
|
||||
<UIcon
|
||||
name="i-heroicons-chevron-right-20-solid"
|
||||
class="w-5 h-5 ms-auto transform transition-transform duration-200"
|
||||
:class="[open && 'rotate-90']"
|
||||
/>
|
||||
</template>
|
||||
</UButton>
|
||||
</template>
|
||||
</UAccordion>
|
||||
</template>
|
||||
```
|
||||
::
|
||||
|
||||
### `item`
|
||||
|
||||
Use the `#item` slot to customize the items content or pass a `slot` property to customize a specific item. You will have access to the `item`, `index`, `open` properties and `close` method in the slot scope.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:accordion-example-item-slot
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const items = [{
|
||||
label: 'Getting Started',
|
||||
icon: 'i-heroicons-information-circle',
|
||||
defaultOpen: true,
|
||||
slot: 'getting-started'
|
||||
}, {
|
||||
label: 'Installation',
|
||||
icon: 'i-heroicons-arrow-down-tray',
|
||||
defaultOpen: true,
|
||||
slot: 'installation'
|
||||
}, {
|
||||
label: 'Theming',
|
||||
icon: 'i-heroicons-eye-dropper',
|
||||
defaultOpen: true,
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}, ...]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UAccordion :items="items">
|
||||
<template #item="{ item }">
|
||||
<p class="italic text-gray-900 dark:text-white text-center">
|
||||
{{ item.description }}
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<template #getting-started>
|
||||
<div class="flex flex-col justify-center items-center gap-1">
|
||||
<NuxtLink to="/getting-started" class="flex items-end gap-1.5 font-bold text-xl text-gray-900 dark:text-white">
|
||||
<Logo class="w-8 h-8 text-primary-500 dark:text-primary-400" />
|
||||
|
||||
<span class="hidden sm:block">NuxtLabs</span><span class="sm:text-primary-500 dark:sm:text-primary-400">UI</span>
|
||||
</NuxtLink>
|
||||
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Fully styled and customizable components for Nuxt.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #installation="{ description }">
|
||||
<div class="flex flex-col justify-center items-center gap-1 mb-4">
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white">
|
||||
Installation
|
||||
</h3>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Install <code>@nuxthq/ui</code> dependency to your project:
|
||||
</p>
|
||||
<p>
|
||||
{{ description }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col items-center">
|
||||
<code>$ npm install @nuxtlabs/ui</code>
|
||||
<code>$ nnpm install -D @nuxthq/ui</code>
|
||||
<code>$ pnpm i -D @nuxthq/ui</code>
|
||||
</div>
|
||||
</template>
|
||||
</UAccordion>
|
||||
</template>
|
||||
```
|
||||
::
|
||||
|
||||
## Props
|
||||
|
||||
:component-props
|
||||
|
||||
## Preset
|
||||
|
||||
:component-preset
|
||||
@@ -1,4 +1,4 @@
|
||||
import { hexToRgb } from "../../src/runtime/utils"
|
||||
import { hexToRgb } from '../../src/runtime/utils'
|
||||
import colors from '#tailwind-config/theme/colors'
|
||||
|
||||
export default defineNuxtPlugin({
|
||||
|
||||
@@ -137,7 +137,7 @@ export default defineNuxtModule<ModuleOptions>({
|
||||
config: {
|
||||
darkMode: 'class',
|
||||
plugins: [
|
||||
require("@tailwindcss/forms")({ strategy: 'class' }),
|
||||
require('@tailwindcss/forms')({ strategy: 'class' }),
|
||||
require('@tailwindcss/aspect-ratio'),
|
||||
require('@tailwindcss/typography'),
|
||||
require('@tailwindcss/container-queries')
|
||||
|
||||
@@ -248,7 +248,7 @@ const dropdown = {
|
||||
enterActiveClass: 'transition duration-100 ease-out',
|
||||
enterFromClass: 'transform scale-95 opacity-0',
|
||||
enterToClass: 'transform scale-100 opacity-100',
|
||||
leaveActiveClass: 'transition duration-75 ease-out',
|
||||
leaveActiveClass: 'transition duration-75 ease-in',
|
||||
leaveFromClass: 'transform scale-100 opacity-100',
|
||||
leaveToClass: 'transform scale-95 opacity-0'
|
||||
},
|
||||
@@ -258,6 +258,29 @@ const dropdown = {
|
||||
}
|
||||
}
|
||||
|
||||
const accordion = {
|
||||
wrapper: 'w-full flex flex-col gap-y-2',
|
||||
item: {
|
||||
base: '',
|
||||
size: 'text-sm',
|
||||
color: 'text-gray-500 dark:text-gray-400',
|
||||
padding: 'py-2'
|
||||
},
|
||||
transition: {
|
||||
enterActiveClass: 'transition duration-100 ease-in',
|
||||
enterFromClass: 'transform opacity-0',
|
||||
enterToClass: 'transform opacity-100',
|
||||
leaveActiveClass: 'transition duration-75 ease-out',
|
||||
leaveFromClass: 'transform opacity-100',
|
||||
leaveToClass: 'transform opacity-0'
|
||||
},
|
||||
default: {
|
||||
openIcon: 'i-heroicons-chevron-down-20-solid',
|
||||
closeIcon: '',
|
||||
variant: 'soft'
|
||||
}
|
||||
}
|
||||
|
||||
const kbd = {
|
||||
base: 'inline-flex items-center justify-center text-gray-900 dark:text-white',
|
||||
padding: 'px-1',
|
||||
@@ -387,7 +410,7 @@ const formGroup = {
|
||||
label: {
|
||||
wrapper: 'flex content-center justify-between',
|
||||
base: 'block text-sm font-medium text-gray-700 dark:text-gray-200',
|
||||
required: `after:content-['*'] after:ms-0.5 after:text-red-500 dark:after:text-red-400`
|
||||
required: 'after:content-[\'*\'] after:ms-0.5 after:text-red-500 dark:after:text-red-400'
|
||||
},
|
||||
description: 'text-sm text-gray-500 dark:text-gray-400',
|
||||
container: 'mt-1 relative',
|
||||
@@ -541,7 +564,7 @@ const range = {
|
||||
background: 'bg-{color}-500 dark:bg-{color}-400'
|
||||
},
|
||||
thumb: {
|
||||
base: `[&::-webkit-slider-thumb]:relative [&::-moz-range-thumb]:relative [&::-webkit-slider-thumb]:z-[1] [&::-moz-range-thumb]:z-[1] [&::-webkit-slider-thumb]:appearance-none [&::-moz-range-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0`,
|
||||
base: '[&::-webkit-slider-thumb]:relative [&::-moz-range-thumb]:relative [&::-webkit-slider-thumb]:z-[1] [&::-moz-range-thumb]:z-[1] [&::-webkit-slider-thumb]:appearance-none [&::-moz-range-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0',
|
||||
color: 'text-{color}-500 dark:text-{color}-400',
|
||||
background: '[&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:dark:bg-gray-900 [&::-moz-range-thumb]:bg-current',
|
||||
ring: '[&::-webkit-slider-thumb]:ring-2 [&::-webkit-slider-thumb]:ring-current',
|
||||
@@ -926,6 +949,7 @@ export default {
|
||||
buttonGroup,
|
||||
dropdown,
|
||||
kbd,
|
||||
accordion,
|
||||
input,
|
||||
formGroup,
|
||||
textarea,
|
||||
|
||||
93
src/runtime/components/elements/Accordion.vue
Normal file
93
src/runtime/components/elements/Accordion.vue
Normal file
@@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<div :class="ui.wrapper">
|
||||
<HDisclosure v-for="(item, index) in items" v-slot="{ open, close }" :key="index" :default-open="defaultOpen || item.defaultOpen">
|
||||
<HDisclosureButton as="template" :disabled="item.disabled">
|
||||
<slot :item="item" :index="index" :open="open" :close="close">
|
||||
<UButton v-bind="{ ...omit(ui.default, ['openIcon', 'closeIcon']), ...$attrs, ...omit(item, ['slot', 'disabled', 'content', 'defaultOpen']) }" class="w-full">
|
||||
<template #trailing>
|
||||
<UIcon
|
||||
:name="!open ? openIcon : closeIcon ? closeIcon : openIcon"
|
||||
class="ms-auto transform"
|
||||
:class="[
|
||||
open && !closeIcon ? '-rotate-180' : '',
|
||||
uiButton.icon.size[item.size || uiButton.default.size]
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
</UButton>
|
||||
</slot>
|
||||
</HDisclosureButton>
|
||||
|
||||
<Transition v-bind="ui.transition">
|
||||
<HDisclosurePanel :class="[ui.item.base, ui.item.size, ui.item.color, ui.item.padding]">
|
||||
<slot :name="item.slot || 'item'" :item="item" :index="index" :open="open" :close="close">
|
||||
{{ item.content }}
|
||||
</slot>
|
||||
</HDisclosurePanel>
|
||||
</Transition>
|
||||
</HDisclosure>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { Disclosure as HDisclosure, DisclosureButton as HDisclosureButton, DisclosurePanel as HDisclosurePanel } from '@headlessui/vue'
|
||||
import { defu } from 'defu'
|
||||
import { omit } from 'lodash-es'
|
||||
import UIcon from '../elements/Icon.vue'
|
||||
import UButton from '../elements/Button.vue'
|
||||
import type { Button } from '../../types/button'
|
||||
import { useAppConfig } from '#imports'
|
||||
// TODO: Remove
|
||||
// @ts-expect-error
|
||||
import appConfig from '#build/app.config'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
HDisclosure,
|
||||
HDisclosureButton,
|
||||
HDisclosurePanel,
|
||||
UIcon,
|
||||
UButton
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
items: {
|
||||
type: Array as PropType<Partial<Button & { slot: string, disabled: boolean, content: string, defaultOpen: boolean }>[]>,
|
||||
default: () => []
|
||||
},
|
||||
defaultOpen: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
openIcon: {
|
||||
type: String,
|
||||
default: () => appConfig.ui.accordion.default.openIcon
|
||||
},
|
||||
closeIcon: {
|
||||
type: String,
|
||||
default: () => appConfig.ui.accordion.default.closeIcon
|
||||
},
|
||||
ui: {
|
||||
type: Object as PropType<Partial<typeof appConfig.ui.accordion>>,
|
||||
default: () => appConfig.ui.accordion
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
// TODO: Remove
|
||||
const appConfig = useAppConfig()
|
||||
|
||||
const ui = computed<Partial<typeof appConfig.ui.accordion>>(() => defu({}, props.ui, appConfig.ui.accordion))
|
||||
|
||||
const uiButton = computed<Partial<typeof appConfig.ui.button>>(() => appConfig.ui.button)
|
||||
|
||||
return {
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
ui,
|
||||
uiButton,
|
||||
omit
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user