From dfddde27a10e3e2b699a5ba915081c185a5a1d03 Mon Sep 17 00:00:00 2001 From: Ekaterina Kondareva <ekaterina.kondareva@helsinki.fi> Date: Wed, 16 Dec 2020 10:45:06 +0200 Subject: [PATCH] Nxstage 1136 mini accordions --- src/components.d.ts | 5 +- .../accordion-item/accordion-item.scss | 88 +++++++++++++++++ .../accordion-item/accordion-item.tsx | 96 +++++++++++-------- src/components/accordion-item/readme.md | 7 +- src/index.html | 14 --- src/utils/utils.ts | 5 + 6 files changed, 157 insertions(+), 58 deletions(-) diff --git a/src/components.d.ts b/src/components.d.ts index 4927e728..66dee2dd 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -5,8 +5,8 @@ * It contains typing information for all components that exist in this project. */ import {HTMLStencilElement, JSXBase} from '@stencil/core/internal'; -import {Breadcrumb} from './components/hy-breadcrumbs/hy-breadcrumbs'; import { + AccordionVariants, BreadcrumbVariants, ButtonVariants, ColorVariant, @@ -32,6 +32,7 @@ import { ProcessFlowBoxVariants, SiteLogoSize, } from './utils/utils'; +import {Breadcrumb} from './components/hy-breadcrumbs/hy-breadcrumbs'; import {TagValue} from './components/courses/hy-content-list-item/hy-content-list-item'; import {DesktopLinks} from './components/site-header/hy-desktop-menu-links/hy-desktop-menu-links'; import {IDropdownItem} from './components/hy-dropdown/hy-dropdown'; @@ -56,6 +57,7 @@ export namespace Components { } interface HyAccordionItem { accordiontitle?: string; + variant: AccordionVariants; } interface HyAdjacentImageText { imageAlt: string; @@ -1279,6 +1281,7 @@ declare namespace LocalJSX { } interface HyAccordionItem { accordiontitle?: string; + variant?: AccordionVariants; } interface HyAdjacentImageText { imageAlt?: string; diff --git a/src/components/accordion-item/accordion-item.scss b/src/components/accordion-item/accordion-item.scss index 3ad45862..ddeb1f52 100644 --- a/src/components/accordion-item/accordion-item.scss +++ b/src/components/accordion-item/accordion-item.scss @@ -22,6 +22,39 @@ } } +.hy-accordion__item.mini { + margin-bottom: 1rem; + margin-top: 1rem; +} +.hy-accordion__item__is-open.mini { + margin-bottom: 0; + margin-top: 0; + + .hy-accordion__item--container { + border-bottom: 1px solid var(--grayscale-medium-dark); + border-top: 1px solid var(--grayscale-medium-dark); + padding-top: 16px; + padding-bottom: 32px; + margin-top: -1px; + transition: padding 0.5s ease-in-out; + + @include breakpoint($narrow) { + padding-top: 28px; + padding-bottom: 30px; + } + @include breakpoint($wide) { + padding-top: 32px; + padding-bottom: 40px; + } + } +} + +.hy-accordion__item.hy-accordion__item__is-open.mini { + background-color: var(--grayscale-white); + border: none; + box-shadow: 0 -10px 10px -10px rgba(0, 49, 70, 0.05); +} + .hy-accordion--heading { justify-content: flex-start; letter-spacing: -0.69px; @@ -87,6 +120,55 @@ } } +.hy-accordion--heading.mini { + // accordion clickable header + .hy-accordion__button { + @include font-size(18px, 22px); + background-color: var(--grayscale-white); + color: var(--link-blue); + letter-spacing: -0.56px; + padding: 0; + + @include breakpoint($narrow) { + @include font-size(22px, 28px); + letter-spacing: -0.69px; + padding: 0; + } + + &[aria-expanded='true'] { + color: var(--grayscale-black); + + margin-bottom: 20px; + @include breakpoint($narrow) { + margin-bottom: 28px; + } + @include breakpoint($wide) { + margin-bottom: 32px; + } + } + } + + //accordion arrow + .hy-accordion--heading__icon { + margin-right: 0.5rem; + z-index: 0; + + @include breakpoint($narrow) { + margin-right: 10px; + } + + svg { + fill: var(--brand-main-light); + height: 14px; + width: 14px; + @include breakpoint($narrow) { + height: 16px; + width: 16px; + } + } + } +} + .hy-accordion__content { display: block; height: 0; @@ -104,3 +186,9 @@ } } } + +.hy-accordion__content.mini { + hy-box { + padding: 0; + } +} diff --git a/src/components/accordion-item/accordion-item.tsx b/src/components/accordion-item/accordion-item.tsx index fada4423..22760115 100644 --- a/src/components/accordion-item/accordion-item.tsx +++ b/src/components/accordion-item/accordion-item.tsx @@ -1,4 +1,16 @@ import {Component, Listen, Prop, State, Element, h} from '@stencil/core'; +import {AccordionVariants} from '../../utils/utils'; + +let keys = { + enter: 'Enter', //13 + tab: 'Tab', //9 + pageUp: 'PageUp', //33 + pageDown: 'PageDown', //34 + arrowUp: 'ArrowUp', // 38 + arrowDown: 'ArrowDown', //40 + home: 'Home', //36 + end: 'End', //35 +}; @Component({ tag: 'hy-accordion-item', @@ -8,6 +20,7 @@ import {Component, Listen, Prop, State, Element, h} from '@stencil/core'; export class AccordionItem { @Element() el: HTMLElement; @Prop() accordiontitle?: string; + @Prop() variant: AccordionVariants = AccordionVariants.default; @State() ready: boolean = false; componentDidLoad() { @@ -34,31 +47,28 @@ export class AccordionItem { const triggers = Array.prototype.slice.call(accordion.querySelectorAll('.hy-accordion__button')); let target = event.target as HTMLButtonElement; - const key = event.which.toString(); + const key = event.code; - // 33 = Page Up, 34 = Page Down - const ctrlModifier = event.ctrlKey && key.match(/33|34/); + const ctrlModifier = event.ctrlKey && [keys.pageDown, keys.pageUp].includes(key); //key.match(/33|34/); if (target.classList.contains('hy-accordion__button')) { // Up/ Down arrow and Control + Page Up/ Page Down keyboard operations - // 38 = Up, 40 = Down - if (key.match(/38|40/) || ctrlModifier) { + if ([keys.arrowDown, keys.arrowUp].includes(key) || ctrlModifier) { const index = triggers.indexOf(target); - const direction = key.match(/34|40/) ? 1 : -1; + const direction = [keys.arrowDown, keys.pageDown].includes(key) ? 1 : -1; const length = triggers.length; const newIndex = (index + length + direction) % length; triggers[newIndex].focus(); event.preventDefault(); - } else if (key.match(/35|36/)) { - // 35 = End, 36 = Home keyboard operations + } else if ([keys.home, keys.end].includes(key)) { switch (key) { // Go to first accordion - case '36': + case keys.home: triggers[0].focus(); break; // Go to last accordion - case '35': + case keys.end: triggers[triggers.length - 1].focus(); break; } @@ -179,40 +189,46 @@ export class AccordionItem { }); } - const classAttributes = ['hy-accordion__item']; + const classAttributes = ['hy-accordion__item', this.variant].join(' '); + const classInnerWrapper = ['hy-accordion__item--container', this.variant].join(' '); + const classHeadingAttributes = ['hy-accordion--heading', this.variant].join(' '); + const classContentAttributes = ['hy-accordion__content', this.variant].join(' '); + const titleAsId = this.accordiontitle.toLowerCase().replace(/\W/g, '-'); const accordionItemHref = '#' + titleAsId + '--title'; return ( - <div class={classAttributes.join(' ')}> - <div class="hy-accordion--heading"> - <a href={accordionItemHref} class="hy-accordion__link" tabindex="-1"> - <button - aria-expanded="false" - aria-controls={`${titleAsId}--content`} - class="hy-accordion__button" - id={`${titleAsId}--title`} - > - <span class="hy-accordion--heading__icon"> - <hy-icon icon={'hy-icon-caret-down'} size={20} /> - </span> - {this.accordiontitle} - </button> - </a> - </div> - <div - aria-labelledBy={`${titleAsId}--title`} - class="hy-accordion__content" - id={`${titleAsId}--content`} - role="region" - aria-hidden="true" - style={{display: 'none'}} - > - <hy-box pt="0" pb="0" pl="0.75" pr="0.75"> - <div class="hy-accordion__content--inner-wrapper"> - <slot></slot> - </div> - </hy-box> + <div class={classAttributes}> + <div class={classInnerWrapper}> + <div class={classHeadingAttributes}> + <a href={accordionItemHref} class="hy-accordion__link" tabindex="-1"> + <button + aria-expanded="false" + aria-controls={`${titleAsId}--content`} + class="hy-accordion__button" + id={`${titleAsId}--title`} + > + <span class="hy-accordion--heading__icon"> + <hy-icon icon={'hy-icon-caret-down'} size={20} /> + </span> + {this.accordiontitle} + </button> + </a> + </div> + <div + aria-labelledBy={`${titleAsId}--title`} + class={classContentAttributes} + id={`${titleAsId}--content`} + role="region" + aria-hidden="true" + style={{display: 'none'}} + > + <hy-box pt="0" pb="0" pl="0.75" pr="0.75"> + <div class="hy-accordion__content--inner-wrapper"> + <slot></slot> + </div> + </hy-box> + </div> </div> </div> ); diff --git a/src/components/accordion-item/readme.md b/src/components/accordion-item/readme.md index b54677a5..858fdfd9 100644 --- a/src/components/accordion-item/readme.md +++ b/src/components/accordion-item/readme.md @@ -39,9 +39,10 @@ Accordion component ## Properties -| Property | Attribute | Description | Type | Default | -| ---------------- | ---------------- | ----------- | -------- | ----------- | -| `accordiontitle` | `accordiontitle` | | `string` | `undefined` | +| Property | Attribute | Description | Type | Default | +| ---------------- | ---------------- | ----------- | ----------------------------------------------------- | --------------------------- | +| `accordiontitle` | `accordiontitle` | | `string` | `undefined` | +| `variant` | `variant` | | `AccordionVariants.default \| AccordionVariants.mini` | `AccordionVariants.default` | ## Dependencies diff --git a/src/index.html b/src/index.html index 1b9283f0..34c4f285 100644 --- a/src/index.html +++ b/src/index.html @@ -1078,20 +1078,6 @@ > </hy-content-list> </hy-main-content-wrapper> - - <hy-main-content-wrapper> - <hy-accordion-container accordionId="example-accordion"> - <hy-accordion-item accordiontitle="This is a accordion item 1"> - <hy-paragraph-text>Accordion content</hy-paragraph-text> - </hy-accordion-item> - <hy-accordion-item accordiontitle="This is a accordion item 2"> - <hy-paragraph-text>Accordion content</hy-paragraph-text> - </hy-accordion-item> - <hy-accordion-item accordiontitle="This is a accordion item 3"> - <hy-paragraph-text>Accordion content</hy-paragraph-text> - </hy-accordion-item> - </hy-accordion-container> - </hy-main-content-wrapper> </div> <aside class="layout-sidebar-first" role="complementary"> diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 61c8938c..c2224f9b 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -12,6 +12,11 @@ export type IconName = { [key: string]: (props: any) => FunctionalComponent; }; +export enum AccordionVariants { + default = 'default', + mini = 'mini', +} + export enum BreadcrumbVariants { default = 'default', landingLarge = 'large', -- GitLab