diff --git a/packages/vanilla/src/components/accordion/accordion.js b/packages/vanilla/src/components/accordion/accordion.js index a0270b72..12420be4 100644 --- a/packages/vanilla/src/components/accordion/accordion.js +++ b/packages/vanilla/src/components/accordion/accordion.js @@ -1,13 +1,25 @@ class Accordion { - constructor(domNode) { - this.accordionNode = domNode; + constructor(accordion) { + this.accordionNode = accordion; + this.accordionControl = this.accordionNode.querySelector('.cbp-accordion__control'); + this.accordionContent = this.accordionNode.querySelector('.cbp-accordion__content'); - this.accordionNode.addEventListener('click', this.toggle); + this.accordionControl.setAttribute('aria-expanded', false) + + this.accordionNode.addEventListener('click', () => { + this.toggle() + }); } - toggle(event) { - const wrapper = event.target.closest('.cbp-accordion__item'); - wrapper.classList.toggle('active'); + toggle() { + const previousState = + this.accordionControl.hasAttribute('aria-expanded') && + this.accordionControl.getAttribute('aria-expanded') === 'true' + ? true + : false; + + this.accordionControl.setAttribute('aria-expanded', !previousState); + this.accordionContent.toggleAttribute('hidden'); } } diff --git a/packages/vanilla/src/components/accordion/accordion.stories.js b/packages/vanilla/src/components/accordion/accordion.stories.js index 151a7306..cc01b335 100644 --- a/packages/vanilla/src/components/accordion/accordion.stories.js +++ b/packages/vanilla/src/components/accordion/accordion.stories.js @@ -1,52 +1,59 @@ export default { title: 'Patterns/Accordion', argTypes: { - label: { control: 'text' }, - onClick: { action: 'onClick' }, - }, + defaultAccordion: { + name: 'Accordion (Default)', + }, + badgeAccordion: { + name: 'Accordion w/ Badge', + }, + iconAccordion: { + name: 'Accordion w/ Icon', + } + } }; - - -const Template = ({ label, ...args }) => { +const Template = ({ defaultAccordion, badgeAccordion, iconAccordion }) => { return `
-
- - -
-
Content Heading
-
-

Accordion content here.

- +
-
- -
-
Content Heading
-
-

Accordion content here.

- + +
+ +
+ +
@@ -54,4 +61,17 @@ const Template = ({ label, ...args }) => { }; export const Accordion = Template.bind({}); -Accordion.args = {}; +Accordion.args = { + defaultAccordion: { + title: 'Accordion (Default)', + danger: false + }, + badgeAccordion: { + title: 'Accordion w/ Badge', + danger: false + }, + iconAccordion: { + title: 'Accordion w/ Icon', + danger: false + } +}; diff --git a/packages/vanilla/src/index.js b/packages/vanilla/src/index.js index e08839d9..2d8453d0 100644 --- a/packages/vanilla/src/index.js +++ b/packages/vanilla/src/index.js @@ -29,7 +29,7 @@ document.addEventListener('DOMContentLoaded', (event) => { /** * Accordion Component */ - SelectorEngine.findAll(".cbp-accordion__title").forEach((accordion) => { + SelectorEngine.findAll(".cbp-accordion__item").forEach((accordion) => { addOrInstantiate(Accordion, accordion); }); diff --git a/packages/vanilla/src/sass/components/accordion/_index.scss b/packages/vanilla/src/sass/components/accordion/_index.scss index b40e4dcb..4be67f82 100644 --- a/packages/vanilla/src/sass/components/accordion/_index.scss +++ b/packages/vanilla/src/sass/components/accordion/_index.scss @@ -1,148 +1,127 @@ -//@use '../../base/colors' as *; -@use '../../typography' as *; -@use './states' as *; -//@use '../../tokens/font' as *; - .cbp-accordion { - margin: 24px 0; + margin-top: var(--cbp-space-6x); + margin-bottom: var(--cbp-space-6x); width: 100%; +} - .cbp-accordion__item { - margin-bottom: 12px; - - &:last-of-type { - margin-bottom: 0; - } - } - - .cbp-accordion__title { - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - color: var(--cbp-color-text-darkest); - background: var(--cbp-color-interactive-neutral-lighter); - border: none; - outline: transparent; - padding: 16px; - transition: all 300ms; - - div:first-child i { - color: var(--cbp-color-text-darker); - font-size: var(--cbp-font-size-heading-md); - transition: transform .2s ease-in-out; - } +.cbp-accordion__item { + margin-bottom: var(--cbp-space-3x); +} - div:first-child span { - @extend .cbp-heading-s; - margin-left: 16px; - } +.cbp-accordion__control { + display: flex; + align-items: center; + background: var(--cbp-color-interactive-neutral-lighter); + border: none; + color: var(--cbp-color-text-darkest); + justify-content: space-between; + outline: 0; + min-height: var(--cbp-space-13x); + padding-left: var(--cbp-space-4x); + padding-right: var(--cbp-space-4x); + transition: all 300ms; + width: 100%; - &:hover { - background-color: var(--cbp-color-interactive-neutral-light); - } + & i { + font-size: var(--cbp-font-size-heading-md); - &:focus { - @include accordion-focus; - @include accordion-text-light; - @include accordion-badge(var(--cbp-color-white), var(--cbp-color-base-secondary-base)); + &:first-child { + margin-right: var(--cbp-space-2x); + transition: transform var(--cbp-motion-duration-shortest) ease-in-out; } + } - /* TODO: Leverage the cascade. Put states last. */ - &:focus + .cbp-accordion__content { - @include accordion-content-border(var(--cpb-color-interactive-focus-dark), true); - } + &:hover { + background-color: var(--cbp-color-interactive-neutral-light); } - .cbp-accordion__content { - background: var(--cbp-color-white); - display: none; - max-height: 0; - overflow: hidden; - transition: max-height 0.2s ease-in-out; - - /* TODO: wouldn't it be easier to apply padding to the content panel - rather than margin to every child inside of it, possibly overriding something? - */ - > * { - margin: 16px + &:focus { + background: var(--cbp-color-interactive-focus-dark); + color: var(--cbp-color-text-lightest); + outline-width: var(--cbp-border-size-md); + outline-style: solid; + outline-color: var(--cbp-color-white); + outline-offset: calc(-1 * var(--cbp-space-2x)); + + & > .cbp-badge { + background-color: var(--cbp-color-white); + color: var(--cbp-color-base-secondary-base); } } } +.cbp-accordion__control[aria-expanded="true"] { + background-color: var(--cbp-color-base-secondary-base); + color: var(--cbp-color-text-lightest); -.cbp-accordion__title--danger { - background: var(--cbp-color-danger-base); + & i:first-child { + transform: rotate(-180deg); + } - @include accordion-text-light; - @include accordion-badge(var(--cbp-color-white), var(--cbp-color-danger-base)); + & .cbp-badge { + background-color: var(--cbp-color-white); + color: var(--cbp-color-base-secondary-base); + } &:hover { - background: var(--cbp-color-danger-dark); + background-color: var(--cbp-color-base-secondary-dark); + + & + .cbp-accordion__content { + border-color: var(--cbp-color-base-secondary-dark); + } } &:focus { - @include accordion-focus; - @include accordion-badge(var(--cbp-color-white), var(--cbp-color-danger-base)); + background-color: var(--cbp-color-interactive-focus-dark); + + & + .cbp-accordion__content { + border-color: var(--cbp-color-interactive-focus-dark); + } } } -.active { - .cbp-accordion__title { - background-color: var(--cbp-color-base-secondary-base); - - @include accordion-text-light; +.cbp-accordion__title { + align-items: center; + display: flex; + font-weight: var(--cbp-font-weight-medium); + font-size: var(--cbp-font-size-heading-sm); +} - div:first-child i { - transform: rotate(-180deg); - } +.cbp-accordion__content { + background: var(--cbp-color-white); + border: var(--cbp-border-size-xl) solid var(--cbp-color-base-secondary-base); + border-top: 0; + padding: var(--cbp-space-4x); +} - @include accordion-badge(var(--cbp-color-white), var(--cbp-color-base-secondary-base)); - .cbp-accordion__title--danger { - background: var(--cbp-color-danger-base); - color: var(--cbp-color-text-lightest); - .cbp-badge span { - color: var(--cbp-color-danger-base); - } - } +.cbp-accordion__item--danger > .cbp-accordion__control { + background: var(--cbp-color-danger-base); + color: var(--cbp-color-text-lightest); - .cbp-accordion__title--danger + .cbp-accordion__content { - border-color: var(--cbp-color-danger-base); - } + & + .cbp-accordion__content { + border-color: var(--cbp-color-danger-base); } - - .cbp-accordion__content { - display: block; - max-height: fit-content; - @include accordion-content-border(var(--cbp-color-base-secondary-base)); - - .cbp-accordion__footer { - align-items: center; - display: flex; - justify-content: space-between; - margin-bottom: 16px; - margin-top: 16px; - } + + & .cbp-badge { + background-color: var(--cbp-color-white); + color: var(--cbp-color-danger-base); } -} -// Hover States -.cbp-accordion__item.active:hover { - .cbp-accordion__title { - background-color: var(--cbp-color-base-secondary-dark); - } + &:hover { + background: var(--cbp-color-danger-dark); - .cbp-accordion__content { - @include accordion-content-border(var(--cbp-color-base-secondary-base)); + & + .cbp-accordion__content { + border-color: var(--cbp-color-danger-dark); + } } - .cbp-accordion__title--danger { - background-color: var(--cbp-color-danger-dark); - } + &:focus { + background: var(--cbp-color-interactive-focus-dark); - .cbp-accordion__title--danger + .cbp-accordion__content { - @include accordion-content-border(var(--cbp-color-danger-dark)); + & + .cbp-accordion__content { + border-color: var(--cbp-color-interactive-focus-dark); + } } } diff --git a/packages/vanilla/src/sass/components/accordion/_states.scss b/packages/vanilla/src/sass/components/accordion/_states.scss deleted file mode 100644 index b2f1b414..00000000 --- a/packages/vanilla/src/sass/components/accordion/_states.scss +++ /dev/null @@ -1,41 +0,0 @@ -//@use '../../base/colors' as *; - -/* - TODO: investigate why/if important is needed. It shouldn't be. -*/ - -@mixin accordion-focus { - background: var(--cbp-color-interactive-focus-dark) !important; - color: var(--cbp-color-white); - outline: 2px solid var(--cbp-color-white) !important; - outline-offset: -4px !important; -} - -@mixin accordion-text-light { - div:first-child span, - div:first-child i { - color: var(--cbp-color-text-lightest); - } -} - -@mixin accordion-badge($bg-color, $text-color) { - .cbp-badge { - background-color: $bg-color; - - & span { - color: $text-color; - } - } -} - -@mixin accordion-content-border($border-color, $override: false) { - @if $override { - border-bottom: 4px solid $border-color !important; - border-left: 4px solid $border-color !important; - border-right: 4px solid $border-color !important; - } @else { - border-bottom: 4px solid $border-color; - border-left: 4px solid $border-color; - border-right: 4px solid $border-color; - } -} \ No newline at end of file