Skip to content

Commit

Permalink
Merge pull request #141 from US-CBP/feature/cbp-expand
Browse files Browse the repository at this point in the history
Feature/cbp expand
  • Loading branch information
dgibson666 authored May 7, 2024
2 parents d7928ce + aa07c9a commit bfa62dc
Show file tree
Hide file tree
Showing 18 changed files with 369 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const CbpCard = /*@__PURE__*/createReactComponent<JSX.CbpCard, HTMLCbpCar
export const CbpChip = /*@__PURE__*/createReactComponent<JSX.CbpChip, HTMLCbpChipElement>('cbp-chip');
export const CbpContainer = /*@__PURE__*/createReactComponent<JSX.CbpContainer, HTMLCbpContainerElement>('cbp-container');
export const CbpDrawer = /*@__PURE__*/createReactComponent<JSX.CbpDrawer, HTMLCbpDrawerElement>('cbp-drawer');
export const CbpExpand = /*@__PURE__*/createReactComponent<JSX.CbpExpand, HTMLCbpExpandElement>('cbp-expand');
export const CbpFlex = /*@__PURE__*/createReactComponent<JSX.CbpFlex, HTMLCbpFlexElement>('cbp-flex');
export const CbpFlexItem = /*@__PURE__*/createReactComponent<JSX.CbpFlexItem, HTMLCbpFlexItemElement>('cbp-flex-item');
export const CbpFooter = /*@__PURE__*/createReactComponent<JSX.CbpFooter, HTMLCbpFooterElement>('cbp-footer');
Expand Down
5 changes: 5 additions & 0 deletions packages/web-components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ This CHANGELOG.md tracks the updates to the web components package of the CBP de

The React components are wrappers generated from this package and will share the same changes.

## [unreleased] TBD

* First cut of `cbp-expand`.
* Renamed `data-container-theme` to `data-cbp-container-context` to convey that a specific container/DOM node is being displayed light or dark.

## [0.0.1-develop.8] 04-29-2024

* First cut of `cbp-accordion` and `cbp-accordion-item` components.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@

--cbp-accordion-item-control-gap: var(--cbp-space-3x);
--cbp-accordion-item-control-padding: var(--cbp-space-3x);
--uef-accordion-item-control-direction: row;
--cbp-accordion-item-control-direction: row;

--cbp-accordion-item-content-font-size: var(--cbp-font-size-md);
--cbp-accordion-item-content-font-family: inherit;
--cbp-accordion-item-content-font-weight: var(--cbp-font-weight-regular);
--cbp-accordion-item-content-padding: var(--cbp-space-3x);
--cbp-accordion-item-toggle-color: var(--cbp-color-black, #000);
}
}

cbp-accordion-item {
display: flex;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export class CbpAccordionItem {
aria-describedby={this.headingId}
ref={el => (this.control = el)}
>
<cbp-icon name="chevron-right" color="currentColor" class="hydrated"></cbp-icon>
<cbp-icon name="chevron-right"></cbp-icon>
</cbp-button>
</cbp-flex-item>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ cbp-app-header {
min-height: var(--cbp-space-14x);
padding: 0 var(--cbp-responsive-spacing-outer);
background-color: var(--cbp-color-white);
box-shadow: var(--cbp-shadow-level-1-down);
box-shadow: var(--cbp-shadow-level-3-down);
z-index: var(--cbp-z-index-level-1);

// Style all nav items consistently, whether links or button controls for menu/dropdown.
// This may need to be refactored or pulled out and placed into a new component, e.g., cbp-nav-item
// This may need to be refactored or pulled out and placed into a new component, e.g., cbp-nav-item.
// Actually rendering them as cbp-button components would cut down on the redundant CSS and support most cases as drawer controls and links.
//.nav-home,
//.cbp-nav-item,
//.cbp-menu-dropdown,
Expand All @@ -30,13 +31,30 @@ cbp-app-header {
white-space: nowrap;
border-color: transparent;
border-style: solid;
border-width: 0 0 var(--cbp-border-size-md) 0;
border-width: 0 0 var(--cbp-border-size-xl) 0;
outline-color: var(--cbp-color-white);
outline-style: solid;
outline-width: 0;
outline-offset: calc(-1 * var(--cbp-space-1x));
cursor: pointer;

&:hover {
color: var(--cbp-color-text-darkest);
color: var(--cbp-color-interactive-secondary-darker);
background-color: var(--cbp-color-interactive-secondary-lighter);
border-color: var(--cbp-color-interactive-secondary-darker);
}

&:focus {
color: var(--cbp-color-text-lightest);
background-color: var(--cbp-color-interactive-focus-dark);
border-color: var(--cbp-color-interactive-focus-dark);
outline-width: var(--cbp-border-size-md);
}

&:active {
background-color: var(--cbp-color-interactive-active-dark);
border-color: var(--cbp-color-interactive-active-dark);
}
}

[slot=cbp-home] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,6 @@ cbp-button {
}

&[fill=ghost] {
--cbp-button-color-fill-active: transparent;
--cbp-button-color-border-active: transparent;

&[color=primary] {
--cbp-button-color-text: var(--cbp-color-interactive-primary-dark);
--cbp-button-color-text-hover: var(--cbp-color-interactive-primary-dark);
Expand Down
27 changes: 25 additions & 2 deletions packages/web-components/src/components/cbp-button/cbp-button.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, Prop, Element, Event, EventEmitter, Host, h } from '@stencil/core';
import { setCSSProps } from '../../utils/utils';
import { setCSSProps, getElementAttrs } from '../../utils/utils';
//import state from './store';

/**
Expand All @@ -13,8 +13,10 @@ export class CbpButton {
private button: any; // HTMLButtonElement or HTMLAnchorElement
private controlTarget: any;

@Element() host: HTMLElement;
private persistedAttrs: any;

@Element() host: HTMLElement;

/** Specifies whether the button is a true button element or "link button." */
@Prop() tag: 'button' | 'a' = 'button';
/** The `type` attribute of the button: button, submit, or reset. Defaults to "button." */
Expand Down Expand Up @@ -111,6 +113,20 @@ export class CbpButton {
setCSSProps(this.host, {
...this.sx,
});

/*
* For internal use primarily:
* Persist aria-* (and role) attributes on the host down to the rendered element, then remove them from the host.
* This is done once and is not reactive.
* Needs testing and possibly refinement/refactoring.
*/
let hostattrs=getElementAttrs(this.host);
//console.log('Host Attributes: ',getElementAttrs(this.host));
this.persistedAttrs = Object.fromEntries(
Object.entries(hostattrs).filter(
([key]) => ( key.includes('aria') || key == 'role' )
)
);
}

componentDidLoad() {
Expand All @@ -119,6 +135,11 @@ export class CbpButton {
'min-height': this.height
});

// Remove any persisted aria-* attributes from the host because they don't really make sense there.
for (const [key] of Object.entries(this.persistedAttrs)) {
this.host.removeAttribute(key);
};

this.componentLoad.emit({
host: this.host,
nativeElement: this.button,
Expand Down Expand Up @@ -147,6 +168,7 @@ export class CbpButton {
return (
<Host>
<button
{...this.persistedAttrs}
{...attrs}
tabindex={this.pointerOnly || this.disabled ? -1 : 0}
aria-label={this.accessibilityText}
Expand All @@ -165,6 +187,7 @@ export class CbpButton {
return (
<Host>
<a
{...this.persistedAttrs}
{...attrs}
tabindex={this.pointerOnly || this.disabled ? -1 : 0}
aria-label={this.accessibilityText}
Expand Down
64 changes: 64 additions & 0 deletions packages/web-components/src/components/cbp-expand/cbp-expand.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
:root {
--cbp-accordion-item-control-font-size: var(--cbp-font-size-heading-sm);
--cbp-accordion-item-control-font-weight: var(--cbp-font-weight-semibold);
--cbp-expand-control-gap: var(--cbp-space-1x);
--cbp-expand-control-padding: var(--cbp-space-3x);
--cbp-expand-content-padding: var(--cbp-space-3x);
}

cbp-expand {
display: block;

&:not([open]) {
--cbp-expand-rotate-icon: rotate(-90deg);
}

&:not([open]) .cbp-expand--content {
display: none;
}

&[open] {
--cbp-expand-color: var(--cbp-color-text-lighter);
--cbp-expand-color-fill: var(--cbp-color-gray-cool-60);

.cbp-expand--control {
--cbp-accordion-rotate-icon: rotate(90deg);
--cbp-accordion-toggle: expandTo 500ms;
//--cbp-expand-color-border: var(--cbp-color-gray-cool-60);
}
}

.cbp-expand--control {
//display: flex;
//gap: var(--cbp-expand-control-gap);
//min-height: var(--cbp-space-13x);
font-size: var(--cbp-expand-control-font-size);
//font-weight: var(--cbp-expand-control-font-weight);
//padding: var(--cbp-expand-control-padding);
cursor: pointer;

.cbp-expand--toggle {
--cbp-button-padding: 0;
--cbp-button-border-width: 0;

cbp-icon svg {
transition: transform 150ms;
transform: var(--cbp-expand-rotate-icon);
}
}

&:hover .cbp-expand--toggle {
--cbp-button-color-text: var(--cbp-color-text-lightest);
--cbp-button-color-fill: var(--cbp-color-interactive-secondary-darker);
--cbp-button-color-text-hover: var(--cbp-color-text-lightest);
--cbp-button-color-fill-hover: var(--cbp-color-interactive-secondary-darker);
}
}

.cbp-expand--content {
padding-left: var(--cbp-space-7x);
}

}


Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Meta } from '@storybook/addon-docs';

<Meta title="Components/Expand/Specifications" />

# cbp-expand

## Purpose

The Expand component is a standalone component used for progressive disclosure, organizing content under a relevant heading which is used as a control for revealing and hiding its content.

## Functional Requirements

* The Expand component is made up of a heading, control, and content.
* While the entire heading is not a button, clicking anywhere on it will toggle its content.
* The "caret" icon button will gain focus when using the keyboard for navigation.
* By default the content is hidden, but the Expand component may be specified as `open` via property.

## Technical Specifications

### User Interactions

* The Expand component's content is toggled via its heading.
* While the entire heading is not a button, clicking anywhere on it will toggle its content.
* When using keyboard navigation, the actual caret button will gain focus and activation will toggle the content visibility.

### Responsiveness

* The component heading and content will wrap as needed based on the viewport/device.

### Accessibility

* Expand component headings default to `h4` tags, but should use the appropriate heading level for the document structure.
* When the component heading is activated, whether content is expanded or collapsed, focus is sent to the actual button control.
* The button control has the `aria-expanded` attribute applied to convey statefulness of the control.
* The button control also contains the `aria-controls` attribute, referencing the `id` of the content wrapper.

### Additional Notes and Considerations

* The Expand component may be used inside of an Accordion Item, but an Accordion should never be placed inside of the Expand component.
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
export default {
title: 'Components/Expand',
tags: ['autodocs'],
argTypes: {
label: {
description: 'Label text making up the heading control for the Expand component.',
control: 'text',
},
content: {
name: 'content (slotted)',
description: 'Content to be hidden/revealed. May include markup, but not supported by Storybook.',
control: 'text',
},
headingLevel: {
description: 'Specifies the heading level for the component heading, which acts as the expand control. Defaults to "h4".',
control: 'select',
options: ['h2', 'h3', 'h4', 'h5', 'h6'],
},
open: {
description: 'Indicates whether the component is in an "open" or "closed" state affecting content visibility.',
control: 'boolean',
},
sx: {
description: 'Supports adding inline styles as an object of key-value pairs comprised of CSS properties and values. Values should reference design tokens when possible.',
control: 'object',
},
},
args: {
label: 'This is the Expand label.',
content: 'This is the hidden/revealed content.',
},
};

const Template = ({ label, content, open, headingLevel, sx }) => {
return `
<cbp-expand
${label ? `label="${label}"` : ''}
${headingLevel ? `heading-level="${headingLevel}"` : ''}
${open ? `open` : ''}
${sx ? `sx=${JSON.stringify(sx)}` : ''}
>
${content}
</cbp-expand>
`;
};
export const Expand = Template.bind({});

/*
const StackedTemplate = ({ label, content, open, headingLevel, sx }) => {
return `
<cbp-expand
${label ? `label="${label}"` : ''}
${headingLevel ? `heading-level="${headingLevel}"` : ''}
${open ? `open` : ''}
${sx ? `sx=${JSON.stringify(sx)}` : ''}
>
${content}
</cbp-expand>
<cbp-expand
${label ? `label="${label}"` : ''}
${headingLevel ? `heading-level="${headingLevel}"` : ''}
${open ? `open` : ''}
${sx ? `sx=${JSON.stringify(sx)}` : ''}
>
${content}
</cbp-expand>
`;
};
export const Stacked = StackedTemplate.bind({});
*/
Loading

0 comments on commit bfa62dc

Please sign in to comment.