Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Accordion): add multiple prop and close others by default #364

Merged
merged 10 commits into from
Jul 3, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/components/content/examples/AccordionExampleBasic.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const items = [{
}, {
label: 'Theming',
icon: 'i-heroicons-eye-dropper',
closeOthers: 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: 'Layouts',
Expand Down
31 changes: 30 additions & 1 deletion docs/content/2.elements/5.accordion.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Pass an array to the `items` prop of the Accordion component. Each item can have
- `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.
- `closeOthers` - Determines whether the item click close others or not.

::component-example
#default
Expand All @@ -34,7 +35,12 @@ const items = [{
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',
closeOthers: 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>
Expand Down Expand Up @@ -130,6 +136,29 @@ excludedProps:
---
::

### Close others

Use the `close-others` prop to always close others when an item is opened.

::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:
closeOthers: true
excludedProps:
- defaultOpen
---
::

## Slots

You can use slots to customize the buttons and items content of the Accordion.
Expand Down
33 changes: 28 additions & 5 deletions src/runtime/components/elements/Accordion.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<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">
<HDisclosureButton :ref="() => updateClosesRefs(close, index)" 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">
<UButton v-bind="{ ...omit(ui.default, ['openIcon', 'closeIcon']), ...$attrs, ...omit(item, ['slot', 'disabled', 'content', 'defaultOpen']) }" class="w-full" @click="closeAll(index)">
<template #trailing>
<UIcon
:name="!open ? openIcon : closeIcon ? closeIcon : openIcon"
Expand Down Expand Up @@ -54,7 +54,7 @@ export default defineComponent({
inheritAttrs: false,
props: {
items: {
type: Array as PropType<Partial<Button & { slot: string, disabled: boolean, content: string, defaultOpen: boolean }>[]>,
type: Array as PropType<Partial<Button & { slot: string, disabled: boolean, content: string, defaultOpen: boolean, closeOthers: boolean }>[]>,
default: () => []
},
defaultOpen: {
Expand All @@ -69,6 +69,10 @@ export default defineComponent({
type: String,
default: () => appConfig.ui.accordion.default.closeIcon
},
closeOthers: {
type: Boolean,
default: false
},
ui: {
type: Object as PropType<Partial<typeof appConfig.ui.accordion>>,
default: () => appConfig.ui.accordion
Expand All @@ -82,12 +86,31 @@ export default defineComponent({

const uiButton = computed<Partial<typeof appConfig.ui.button>>(() => appConfig.ui.button)

const closesRefs = ref([])
oritwoen marked this conversation as resolved.
Show resolved Hide resolved

function updateClosesRefs (close, index) {
closesRefs.value[index] = close
}
oritwoen marked this conversation as resolved.
Show resolved Hide resolved

function closeAll (itemIndex) {
if (!props.items[itemIndex].closeOthers && !props.closeOthers) return

closesRefs.value.forEach((close, index) => {
if (index === itemIndex) return

close()
})
}

return {
// eslint-disable-next-line vue/no-dupe-keys
ui,
uiButton,
omit
omit,
closeAll,
closesRefs,
updateClosesRefs
}
}
})
</script>
</script>