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/expand component stories #21

Merged
merged 9 commits into from
Apr 6, 2023
80 changes: 1 addition & 79 deletions packages/styles/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -191,85 +191,7 @@ <h6 class="cbp-banner__info-title d-none-sm">
</div>
</div>
<main>
<section class="cbp-grid-container">
<div class="cbp-row">
<div class="cbp-grid-col-full demo-container">
<div class="sandbox">
<div class="cbp-row sandbox__dropdown-container">
<div class="cbp-grid-col-2-sm cbp-grid-col-4-md cbp-grid-col-6-lg cbp-grid-col-6-xl">
<div class="cbp-form-wrapper">
<label for="pod2" class="cbp-form__label">Theme Selector</label>
<span class="cbp-form__description cbp-form__description--error" hidden><i class="fas fa-exclamation-triangle"></i>&nbsp;This field is required.</span>
<div class="cbp-dropdown__wrapper" id="dropdown-demo-2">
<button class="cbp-dropdown__custom" id="port-dropdown" data-toggle="dropdown">
<span class="cbp-dropdown__placeholder">Choose Theme</span>
</button>
<div class="cbp-dropdown" id="custom-dropdown-menu">
<a href="#" class="cbp-dropdown__item">Dark</a>
<a href="#" class="cbp-dropdown__item">Light</a>
</div>
</div>
</div>
</div>
<div class="cbp-grid-col-2-sm cbp-grid-col-4-md cbp-grid-col-6-lg cbp-grid-col-6-xl">
<div class="cbp-form-wrapper">
<label for="pod2" class="cbp-form__label">Variant Selector</label>
<span class="cbp-form__description cbp-form__description--error" hidden><i class="fas fa-exclamation-triangle"></i>&nbsp;This field is required.</span>
<div class="cbp-dropdown__wrapper" id="dropdown-demo-2">
<button class="cbp-dropdown__custom" id="port-dropdown" data-toggle="dropdown">
<span class="cbp-dropdown__placeholder">Choose Variant</span>
</button>
<div class="cbp-dropdown" id="custom-dropdown-menu">
<a href="#" class="cbp-dropdown__item">Single Button Card</a>
<a href="#" class="cbp-dropdown__item">Dual Button Card</a>
<a href="#" class="cbp-dropdown__item">Three Button Card</a>
<a href="#" class="cbp-dropdown__item">General Card</a>
<a href="#" class="cbp-dropdown__item">Clickable Card</a>
<a href="#" class="cbp-dropdown__item">Single Select Card (Radio)</a>
<a href="#" class="cbp-dropdown__item">Multi-Select Card (Checkbox)</a>
<a href="#" class="cbp-dropdown__item">Banner Card</a>
</div>
</div>
</div>
</div>
</div>
<div class="cbp-row">
<div class="cbp-grid-col-full">
<div class="sandbox__demo-container">
<div class="sandbox__demo">
<!-- *COMPONENT GOES HERE* -->
<label class="cbp-toggle demo-toggle" data-component="cbp-toggle">
<input type="checkbox" data-theme-toggle>
<span class="slider">
<i class="fas fa-moon" style="color: yellow;"></i>
<i class="fas fa-sun" style="color: orange;"></i>
</span>
</label>
</div>
<aside class="sandbox__modifiers">
<h2>State Modifiers</h2>
<fieldset style="padding: 20px 16px;">
<div class="form-check">
<input type="checkbox" name="modifier_1" class="cbp-form__checkbox" id="modifier_1">
<label for="readonly">Disable</label>
</div>
<div class="form-check">
<input type="checkbox" name="modifier_2" class="cbp-form__checkbox" id="modifier_2">
<label for="readonly">Error</label>
</div>
<div class="form-check">
<input type="checkbox" name="modifier_3" class="cbp-form__checkbox" id="modifier_3">
<label for="readonly">Read Only</label>
</div>
</fieldset>
</aside>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- KITCHEN SINK -->
</main>
<footer class="cbp-footer">
<ul class="cbp-footer__links">
Expand Down
48 changes: 39 additions & 9 deletions packages/styles/src/components/expand/expand.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,46 @@
class Expand {
constructor(component) {
this.expand = component;
this.title = component.querySelector('.cbp-expand__title');
this.activeClass = 'active';
constructor(expand) {
this.expand = expand;
this.title = this.expand.querySelector('.cbp-expand__title > span');
this.button = this.expand.querySelector('button');
this.expandContent = this.expand.querySelector('.cbp-expand__content');

this.addListener('click');
this.setAriaAttributes();

this.button.addEventListener('click', () => {
this.expand.classList.toggle('active');
this.setAriaExpanded(this.expand);
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way I handle this is to querySelector() the button/control and control.click() it, deferring the logic to the button's click handler. I'm not sure if it automatically transfers focus to the button with that technique, but it can be done with 1 more line: control.focus()


this.title.addEventListener('click', () => {
this.button.click();
this.button.focus();
})
}

addListener(type) {
this.title.addEventListener(type, () => {
this.expand.classList.toggle(this.activeClass);
});
generateId(ariaName) {
return `${ariaName}-${Math.random().toString(36).substring(2,7)}`;
}

setAriaExpanded(expand) {
if (!expand.classList.contains('active')) {
this.button.setAttribute('aria-expanded', 'false');
} else {
this.button.setAttribute('aria-expanded', 'true');
}
}

setAriaAttributes() {
const ariaLabelledById = this.generateId('aria-expand');
const ariaControlsId = this.generateId('expand-content');

this.button.setAttribute('aria-expanded', 'false')

this.button.setAttribute('aria-controls', ariaControlsId);
this.expandContent.setAttribute('id', ariaControlsId);

this.button.setAttribute('aria-labelledby', ariaLabelledById);
this.title.setAttribute('id', ariaLabelledById);
}
}

Expand Down
28 changes: 28 additions & 0 deletions packages/styles/src/components/expand/expand.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Expand Pattern

## Purpose

The Expand patterns are simple interface patterns that allow the user to expand and collapse content. This component is similiar to the Accordion pattern but used for much simpler hide/show elements and may be nested within Accordion pattterns to show hierarchy.

## Functional Requirements

* Focus on the title will be set to the <button> element that is in the `.cbp-expand__title` <div> element

## Technical Specifications

### User Interactions

* Click on the title will collapse/uncollapse the content of the expand component
* Tab will focus on the button element of the Expand title but the actual title will *not* receive focus.

### Responsiveness

* Long titles will wrap and be spaced correctly so that wrapped text will fall under the text and not the button.

### Accessibility

* `aria-controls` is placed on the <button> of the Expand title and the value is set to the ID of the Expand content ID attribute.
* `aria-expanded="true/false"` is placed on the button and changed with JS during open/close
* Interactive elements must have an accessible name, `aria-labelledby` can be used to reference a different element to define it's accessible name. Since the button in the Expand title is a <button> with only an icon (svg), `aria-labelledby="expand-title"` is placed on the <span> element indicating the element ID that describes the button

### Additional Notes and Considerations
76 changes: 39 additions & 37 deletions packages/styles/src/components/expand/expand.stories.js
Original file line number Diff line number Diff line change
@@ -1,61 +1,63 @@
export default {
title: 'Patterns/Expand',
argType: {},
parameters: {
html: {
root: '.wrapper'
},
},
argTypes: {
title: {
name: 'Expand Title',
description: 'Title of the Expand component to display',
type: { name: 'string' }
}
},
decorators: [
(Story) =>`<div class="wrapper" style="margin-top: 2rem; margin-left: 2rem;">${Story().outerHTML || Story()}</div>`
]
};

const Template = () => {
const ExpandTemplate = ({ title }) => {
return `
<div class="cbp-expand">
<div class="cbp-expand__title">
<button>
<button type="button">
<i class="fas fa-caret-down"></i>
</button>
<span>
This is a question about where frogs live.
</span>
<span>${title}</span>
</div>
<div class="cbp-expand__content">
<ul class="cbp-expand__list">
<li>There are different species of frogs and some make great pets!</li>
<li>Frogs can be bought at any pet store really. Here's a link to one <a href="http://petstore.com"
class="cbp-text-link" target="_blank" rel="noopener noreferrer">petstore.com</a></li>
</ul>
</div>
</div>
<div class="cbp-expand">
<div class="cbp-expand__title">
<button>
<i class="fas fa-caret-down"></i>
</button>
<span>
This is a question about where frogs live.
</span>
</div>
<div class="cbp-expand__content">
<ul class="cbp-expand__list">
<li>Frogs can be bought at any pet store really. Here's a link to one <a href="http://petstore.com"
target="_blank" rel="noopener noreferrer">petstore.com</a></li>
</ul>
<p class="cbp-text-body">There are different species of frogs and some make great pets!</p>
<p class="cbp-text-body cbp-margin-top-2x">Frogs can be bought at any pet store really. Here's a link to one <a href="http://petstore.com" class="cbp-text-link" target="_blank" rel="noopener noreferrer">petstore.com</a></p>
</div>
</div>
`;
};

const ExpandLongTitleTemplate = ({ title }) => {
return `
<div class="cbp-expand">
<div class="cbp-expand__title">
<button>
<button type="button">
<i class="fas fa-caret-down"></i>
</button>
<span>
Some facts about dinosaurs and their eating habits that you should teach your kids.
</span>
<span id="expand-title">${title}</span>
</div>
<div class="cbp-expand__content">
<ul class="cbp-expand__list">
<li>Frogs can be bought at any pet store really. Here's a link to one <a href="http://petstore.com"
target="_blank" rel="noopener noreferrer">petstore.com</a></li>
</ul>
<p class="cbp-text-body">There are different species of frogs and some make great pets!</p>
<p class="cbp-text-body cbp-margin-top-2x">Frogs can be bought at any pet store really. Here's a link to one <a href="http://petstore.com" class="cbp-text-link" target="_blank" rel="noopener noreferrer">petstore.com</a></p>
</div>
</div>
`;
};

export const Expand = Template.bind({});
Expand.args = {};
export const Expand = ExpandTemplate.bind({});
Expand.args = {
title: 'This is a question about where frogs live.'
};

export const ExpandLongTitle = ExpandLongTitleTemplate.bind({});
ExpandLongTitle.args = {
title: 'Some facts about dinosaurs and their eating habits that you should teach your kids.'
};
ExpandLongTitle.storyName = 'Expand w/ Long Title';
90 changes: 0 additions & 90 deletions packages/styles/src/sass/components/_expand.scss

This file was deleted.

2 changes: 1 addition & 1 deletion packages/styles/src/sass/components/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
@use 'card';
@use './checkbox';
@use './dropdown';
@use './expand';
@use 'expand';
@use './fileupload';
@use 'footer';
@use 'form';
Expand Down
Loading