Skip to content
This repository has been archived by the owner on Jan 3, 2024. It is now read-only.

Commit

Permalink
Merge pull request #911 from owncloud/oc-accordion-style
Browse files Browse the repository at this point in the history
New accordion component
  • Loading branch information
kulmann authored Oct 28, 2020
2 parents 80db406 + 5730882 commit c2b8b49
Show file tree
Hide file tree
Showing 8 changed files with 259 additions and 94 deletions.
5 changes: 5 additions & 0 deletions changelog/unreleased/accordion
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Change: New accordion component implementation

We rewrote the accordion component to remove UIKit styles and align with our own styling. Some accessibility aspects are already implement, for example expanding and collapsing accordion items by pressing space or enter already works. More will come later on.

https://github.com/owncloud/owncloud-design-system/pull/911
83 changes: 83 additions & 0 deletions src/elements/OcAccordion.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<template>
<ul class="oc-accordion">
<!-- @slot Many oc-accordion-item elements -->
<slot />
</ul>
</template>
<script>
export default {
name: "oc-accordion",
status: "review",
release: "1.0.0",
props: {
/**
* Allow multiple items to be expanded at the same time
*/
multiple: {
type: Boolean,
required: false,
default: false,
},
},
mounted() {
this.$on("toggle", id => this.$_ocAccordion_toggleItem(id))
this.$_ocAccordion_init()
},
methods: {
$_ocAccordion_toggleItem(id) {
const collapseOthers = !this.multiple
this.$children.forEach(child => {
const toggled = child.$_ocAccordionItem_id === id
if (toggled) {
return child.$data.expanded = !child.$data.expanded
}
if (collapseOthers) {
child.$data.expanded = false
}
})
},
$_ocAccordion_init() {
if (!this.multiple) {
let found = false
this.$children.forEach(child => {
if (!found && child.$props.expandedByDefault) {
return found = true
}
if (found) {
child.$data.expanded = false
}
})
}
}
}
}
</script>
<docs>
An accordion is a vertically stacked set of interactive headings that each contain a title, content snippet, or thumbnail representing a section of content.
The headings function as controls that enable users to reveal or hide their associated sections of content.
Accordions are commonly used to reduce the need to scroll when presenting multiple sections of content on a single page.

The accordion component is using `oc-accordion-item` as its children.
To see documentation on how to use this component, see [oc-accordion-item](/#/Elements/oc-accordion-item).

```jsx
<oc-accordion :multiple=false class="uk-width-1-2">
<oc-accordion-item :expandedByDefault=true title="My accordion item" icon="folder">
<p>
I am the content of this accordion
</p>
</oc-accordion-item>
<oc-accordion-item title="Something else with content" description="And a subtitle" icon="file">
<p>Enter some text!</p>
<oc-text-input label="Text"></oc-text-input>
</oc-accordion-item>
</oc-accordion>
```
</docs>
128 changes: 128 additions & 0 deletions src/elements/OcAccordionItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<template>
<li :id="$_ocAccordionItem_id" class="oc-accordion-item">
<component :is="'h' + headingLevel" :id="$_ocAccordionItem_titleId" class="oc-accordion-title">
<oc-button
variation="raw"
justify-content="space-between"
class="uk-text-left uk-width-1-1"
:aria-expanded="expanded"
:aria-controls="$_ocAccordionItem_contentId"
@click="$_ocAccordionItem_toggleExpanded"
@keydown.space="$_ocAccordionItem_toggleExpanded"
@keydown.enter="$_ocAccordionItem_toggleExpanded"
>
<div class="uk-width-1-1">
<oc-grid flex>
<oc-icon v-if="icon" :name="icon" class="oc-mr-s" aria-hidden="true" />
<div class="uk-width-expand" v-text="title" />
<oc-icon name="expand_more" class="oc-ml-xs" :class="{'rotate': expanded}" size="large" />
</oc-grid>
<oc-grid v-if="description">
<div v-if="icon" class="oc-icon-m oc-mr-s" />
<div class="uk-text-meta">{{ description }}</div>
</oc-grid>
</div>
</oc-button>
</component>
<div class="oc-accordion-content" :aria-labelledby="$_ocAccordionItem_titleId" :id="$_ocAccordionItem_contentId" role="region">
<!-- @slot Content of the accordion item -->
<slot v-if="expanded" />
</div>
</li>
</template>
<script>
import * as _uniqueId from "../utils/uniqueId"
export default {
name: "oc-accordion-item",
status: "review",
release: "1.0.0",
props: {
/**
* Icon to be displayed on the left side of the accordion title.
*/
icon: {
type: String,
required: false,
default: null,
},
/**
* Title to be displayed.
*/
title: {
type: String,
required: true,
},
/**
* Description of the accordion item to be displayed below the accordion title.
*/
description: {
type: String,
required: false,
default: null
},
/**
* Asserts whether the accordion item should be expanded by default. If the accordion doesn't allow multiple items
* to be expanded, but multiple items have only the first one to be found will actually be expanded.
*/
expandedByDefault: {
type: Boolean,
required: false,
default: false
},
/**
* Id of the accordion item. If not specified, a unique id will be generated.
*/
id: {
type: String,
required: false,
default: null,
},
/**
* Id of the accordion title. If not specified, a unique id will be generated.
*/
titleId: {
type: String,
required: false,
default: null
},
/**
* Id of the content of the accordion item. If not specified, a unique id will be generated.
*/
contentId: {
type: String,
required: false,
default: null,
},
/**
* Heading level of the accordion title. Defaults to 3 (i.e. `h3`).
*/
headingLevel: {
type: String,
required: false,
default: "3"
}
},
data: () => ({
expanded: false
}),
computed: {
$_ocAccordionItem_id() {
return this.id || _uniqueId("oc-accordion-id-")
},
$_ocAccordionItem_titleId() {
return this.titleId || _uniqueId("oc-accordion-title-")
},
$_ocAccordionItem_contentId() {
return this.contentId || _uniqueId("oc-accordion-content-")
},
},
mounted() {
this.expanded = this.expandedByDefault
},
methods: {
$_ocAccordionItem_toggleExpanded() {
this.$parent.$emit("toggle", this.$_ocAccordionItem_id)
}
}
}
</script>
34 changes: 0 additions & 34 deletions src/elements/_OcAccordionItem.vue

This file was deleted.

57 changes: 0 additions & 57 deletions src/patterns/OcAccordion.vue

This file was deleted.

5 changes: 3 additions & 2 deletions src/styles/_owncloud.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
@import '../../node_modules/uikit/src/scss/variables-theme';
@import '../../node_modules/uikit/src/scss/mixins-theme';

// // 4. Import UIkit.
// 3. Import UIkit.
@import '../../node_modules/uikit/src/scss/uikit-theme';

// 3. Your custom mixin overwrites.
// 4. Your custom mixin overwrites.
@import 'theme/helper';
@import 'theme/oc-spacing';
@import 'theme/background';
Expand Down Expand Up @@ -51,3 +51,4 @@
@import 'theme/oc-modal';
@import 'theme/oc-sidebar';
@import 'theme/oc-radio';
@import 'theme/oc-accordion';
39 changes: 39 additions & 0 deletions src/styles/theme/oc-accordion.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
.oc-accordion {
list-style: none;
padding: 0;

&-item + &-item {
margin-top: $space-medium;
}

&-title {
@extend .oc-mb-rm;

display: block;
font-size: $medium-font-size;

> .oc-button,
> .oc-button:hover,
> .oc-button:focus {
color: $color;
outline: none;
text-decoration: none;

.oc-icon {
transition-duration: 0.3s;

&.rotate {
transform: rotate(180deg);
}

> svg {
fill: $color;
}
}
}
}

&-content {
margin-top: $space-small;
}
}
2 changes: 1 addition & 1 deletion src/tokens/font-size.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ props:
small-font-size:
value: "0.875rem"
font-size:
value: "15px"
value: "1rem"
medium-font-size:
value: "1.25rem"
large-font-size:
Expand Down

0 comments on commit c2b8b49

Please sign in to comment.