From 3594eccce48152a2b852a60f0c7c0d113e27c7e4 Mon Sep 17 00:00:00 2001 From: Doug Gibson Date: Wed, 12 Apr 2023 16:48:01 -0400 Subject: [PATCH 1/6] Broke up combined story file into 3, added controls, and simplied markup --- .../src/components/badge/badge.stories.js | 23 ++++++ .../badgesChipsTags.stories.js | 77 ------------------- .../src/components/chip/chip.stories.js | 25 ++++++ .../styles/src/components/tag/tag.stories.js | 24 ++++++ 4 files changed, 72 insertions(+), 77 deletions(-) create mode 100644 packages/styles/src/components/badge/badge.stories.js delete mode 100644 packages/styles/src/components/badges-chips-tags/badgesChipsTags.stories.js create mode 100644 packages/styles/src/components/chip/chip.stories.js create mode 100644 packages/styles/src/components/tag/tag.stories.js diff --git a/packages/styles/src/components/badge/badge.stories.js b/packages/styles/src/components/badge/badge.stories.js new file mode 100644 index 00000000..5965188d --- /dev/null +++ b/packages/styles/src/components/badge/badge.stories.js @@ -0,0 +1,23 @@ +export default { + title: 'Patterns/Badges, Chips, and Tags', + argTypes: { + variant: { + control: { type: 'select' }, + options: ['', 'danger'], + description: 'Adds a modifier class to the component to display the danger variation (see generated HTML)' + }, + }, +}; + +const BadgeTemplate = (args) => { + const badgeType = args.variant ? `cbp-badge--${args.variant}` : null; + + return ` +
+ 5 +
+ `; +}; + +export const Badge = BadgeTemplate.bind({}); +Badge.args = {}; diff --git a/packages/styles/src/components/badges-chips-tags/badgesChipsTags.stories.js b/packages/styles/src/components/badges-chips-tags/badgesChipsTags.stories.js deleted file mode 100644 index 9e1310ee..00000000 --- a/packages/styles/src/components/badges-chips-tags/badgesChipsTags.stories.js +++ /dev/null @@ -1,77 +0,0 @@ -export default { - title: 'Patterns/Badges, Chips & Tags', - argTypes: {}, -}; - -const BadgeTemplate = () => { - return ` -
-
- 0 -
-
- 7 -
-
- 73 -
-
-
- 99+ -
-
-
-
- 7 -
-
-
- `; -}; - -const ChipTemplate = () => { - return ` -
-
- Hotlist -
- -
-
-
- Hotlist -
- -
-
-
- `; -}; - -const TagTemplate = () => { - return ` -
-
- Hotlist -
-
- Warning -
-
- Online -
-
- Danger -
-
- `; -}; - -export const Badges = BadgeTemplate.bind({}); -Badges.args = {}; - -export const Chips = ChipTemplate.bind({}); -Chips.args = {}; - -export const Tags = TagTemplate.bind({}); -Tags.args = {}; diff --git a/packages/styles/src/components/chip/chip.stories.js b/packages/styles/src/components/chip/chip.stories.js new file mode 100644 index 00000000..847423d6 --- /dev/null +++ b/packages/styles/src/components/chip/chip.stories.js @@ -0,0 +1,25 @@ +export default { + title: 'Patterns/Badges, Chips, and Tags', + argTypes: { + active: { + control: { type: 'boolean' }, + description: 'Adds a modifier class indicating an active/selected chip.' + }, + }, +}; + +const ChipTemplate = (args) => { + //const active = (args.active ==true) ? 'true' : 'false'; + + return ` + + `; +}; + +export const Chip = ChipTemplate.bind({}); +Chip.args = {}; \ No newline at end of file diff --git a/packages/styles/src/components/tag/tag.stories.js b/packages/styles/src/components/tag/tag.stories.js new file mode 100644 index 00000000..ef972b5b --- /dev/null +++ b/packages/styles/src/components/tag/tag.stories.js @@ -0,0 +1,24 @@ +export default { + title: 'Patterns/Badges, Chips, and Tags', + argTypes: { + variant: { + control: { type: 'select' }, + options: ['', 'danger', 'success', 'warning'], + description: 'Adds a modifier class to the component to display different color variations (see generated HTML)' + }, + }, +}; + + +const TagTemplate = (args) => { + const tagType = args.variant ? `cbp-tag--${args.variant}` : null; + + return ` +
+ Hotlist +
+ `; +}; + +export const Tag = TagTemplate.bind({}); +Tag.args = {}; \ No newline at end of file From ffadfab7d20736cbe500f879978cec2a6d918a35 Mon Sep 17 00:00:00 2001 From: Doug Gibson Date: Wed, 12 Apr 2023 16:54:05 -0400 Subject: [PATCH 2/6] Update/simplify CSS for simplified markup --- .../sass/components/_badges-chips-tags.scss | 105 +++++++++--------- 1 file changed, 50 insertions(+), 55 deletions(-) diff --git a/packages/styles/src/sass/components/_badges-chips-tags.scss b/packages/styles/src/sass/components/_badges-chips-tags.scss index 12725501..914c448c 100644 --- a/packages/styles/src/sass/components/_badges-chips-tags.scss +++ b/packages/styles/src/sass/components/_badges-chips-tags.scss @@ -1,22 +1,15 @@ -//@use '../base/colors' as *; - -.mr-2 { - margin-right: 8px; -} - // CBP Badges .cbp-badge { - align-items: center; - background-color: var(--cbp-color-info-base); - border-radius: 12px; + display: inline-block; + width: var(--cbp-space-6x); + height: var(--cbp-space-6x); color: var(--cbp-color-white); + background-color: var(--cbp-color-info-base); + border-radius: var(--cbp-border-radius-pill); cursor: default; - display: flex; - font-size: 10px; - height: 24px; - justify-content: center; + font-size: .625rem; text-align: center; - width: 24px; + line-height: var(--cbp-space-6x); &--danger { background-color: var(--cbp-color-danger-base); @@ -25,25 +18,22 @@ // CBP Tags .cbp-tag { - // @extend .cbp-text-subhead; - align-items: center; - background-color: var(--cbp-color-info-base); - border-radius: 14px; + display: inline-block; color: var(--cbp-color-white); + background-color: var(--cbp-color-info-base); + border-radius: var(--cbp-border-radius-pill); cursor: default; - display: flex; - height: 28px; - justify-content: center; - padding: 0 12px; - width: fit-content; + padding: 0 var(--cbp-space-3x); + text-align: center; + line-height: var(--cbp-space-7x); & > i::after { content: '\a0\a0'; } &--warning { - background-color: var(--cbp-color-warning-base); color: var(--cbp-color-black); + background-color: var(--cbp-color-warning-base); } &--success { @@ -56,58 +46,63 @@ } // CBP Chips -.cbp-chips { +.cbp-chip { // @extend .cbp-text-subhead; - align-items: center; - background-color: var(--cbp-color-interactive-neutral-base); - border-radius: 14px; - color: var(--cbp-color-white); display: flex; - height: 28px; + align-items: center; justify-content: center; - padding-left: 12px; - text-transform: uppercase; width: fit-content; - - &--active { + padding: 0 0 0 var(--cbp-space-3x); + color: var(--cbp-color-white); + background-color: var(--cbp-color-interactive-neutral-base); + border-width: 0; + border-radius: var(--cbp-border-radius-pill); + text-transform: uppercase; + line-height: var(--cbp-space-7x); + + & > .cbp-chip__label + .cbp-chip__icon { + display: flex; + align-items: center; + justify-content: center; + min-width: 28px; + min-height: 28px; + border-width: 0; + border-radius: 14px; + margin-left: 4px; + transition: var(--cbp-motion-duration-shortest); + } + + //&--active { + &[aria-pressed=true] { background-color: var(--cbp-color-interactive-active-dark); - - &:hover { - background-color: var(--cbp-color-interactive-active-dark); + + & > .cbp-chip__label + .cbp-chip__icon { + transform: rotate(-135deg); } - & > span + .plus-border { - transform: rotate(-45deg); + &:hover { + background-color: var(--cbp-color-interactive-active-dark); } } - & > span + .plus-border { - align-items: center; - border-radius: 14px; - display: flex; - height: 28px; - justify-content: center; - margin-left: 4px; - width: 28px; - } - &:hover { cursor: pointer; - > span + .plus-border { + > .cbp-chip__label + .cbp-chip__icon { background-color: #454540; // ToDo } } - &:focus { + &:focus-visible { background-color: var(--cbp-color-interactive-focus-dark); - outline: none; + outline: 0; - > span + .plus-border { + > .cbp-chip__label + .cbp-chip__icon { background-color: transparent; - border-color: var(--cbp-color-white); + border-color: var(--cbp-color-white); + outline: 2px solid white; + outline-offset: -4px; } } - } From e0325f3baa9499d750e2a7cbb8d3f87816a8ae61 Mon Sep 17 00:00:00 2001 From: Doug Gibson Date: Wed, 12 Apr 2023 16:54:18 -0400 Subject: [PATCH 3/6] Add chip interactivity --- packages/styles/src/components/chip/chip.js | 36 +++++++++++++++++++++ packages/styles/src/index.js | 8 +++++ 2 files changed, 44 insertions(+) create mode 100644 packages/styles/src/components/chip/chip.js diff --git a/packages/styles/src/components/chip/chip.js b/packages/styles/src/components/chip/chip.js new file mode 100644 index 00000000..07f6debb --- /dev/null +++ b/packages/styles/src/components/chip/chip.js @@ -0,0 +1,36 @@ +class Chip { + constructor(chip) { + this.chip = chip; + + this.chip.addEventListener('click', (e) => { + this.handleClick(e); + }); + } + + handleClick(e) { + // In case of nested elements, get the button they belong to (closest() is self-referencing) + const clickedButton = e.target.closest('button'); + + const previousState = clickedButton.hasAttribute('aria-pressed') && + clickedButton.getAttribute('aria-pressed') === 'true' + ? true + : false; + + // Toggle active class + clickedButton.setAttribute('aria-pressed', (!previousState).toString()); + + // Emit a custom event so that the developer can listen to the group rather than individual buttons + const toggleEvent = new CustomEvent('chipClick', { + detail: { + chip: this.chip, + label: this.chip.innerText, + value: this.chip.value, + active: !previousState, + nativeEvent: e, + }, + }); + this.chip.dispatchEvent(toggleEvent); + } +} + +export default Chip; diff --git a/packages/styles/src/index.js b/packages/styles/src/index.js index 884ac390..166c625a 100644 --- a/packages/styles/src/index.js +++ b/packages/styles/src/index.js @@ -2,6 +2,7 @@ import SelectorEngine from './utilities/selectorEngine'; import Accordion from './components/accordion/accordion'; import ApplicationHeader from './components/application-header/application-header'; import Banner from './components/banner/banner'; +import Chip from './components/chip/chip'; import Drawer from './components/drawer/drawer'; import Dropdown from './components/dropdown/dropdown'; import Expand from './components/expand/expand'; @@ -45,6 +46,13 @@ document.addEventListener('DOMContentLoaded', (event) => { addOrInstantiate(Banner, banner); }); + /** + * Chips + */ + SelectorEngine.findAll('.cbp-chip').forEach((chip) => { + addOrInstantiate(Chip, chip); + }); + /** * Drawer Components */ From af5edc781553ff058097ced21d9c28bb3d6a4823 Mon Sep 17 00:00:00 2001 From: Doug Gibson Date: Thu, 13 Apr 2023 13:32:27 -0400 Subject: [PATCH 4/6] Updated docs and custom event name --- packages/styles/src/components/chip/chip.js | 9 ++--- packages/styles/src/components/chip/chip.md | 37 +++++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 packages/styles/src/components/chip/chip.md diff --git a/packages/styles/src/components/chip/chip.js b/packages/styles/src/components/chip/chip.js index 07f6debb..901966d5 100644 --- a/packages/styles/src/components/chip/chip.js +++ b/packages/styles/src/components/chip/chip.js @@ -11,16 +11,17 @@ class Chip { // In case of nested elements, get the button they belong to (closest() is self-referencing) const clickedButton = e.target.closest('button'); - const previousState = clickedButton.hasAttribute('aria-pressed') && + const previousState = + clickedButton.hasAttribute('aria-pressed') && clickedButton.getAttribute('aria-pressed') === 'true' - ? true - : false; + ? true + : false; // Toggle active class clickedButton.setAttribute('aria-pressed', (!previousState).toString()); // Emit a custom event so that the developer can listen to the group rather than individual buttons - const toggleEvent = new CustomEvent('chipClick', { + const toggleEvent = new CustomEvent('chipToggle', { detail: { chip: this.chip, label: this.chip.innerText, diff --git a/packages/styles/src/components/chip/chip.md b/packages/styles/src/components/chip/chip.md new file mode 100644 index 00000000..51b252ff --- /dev/null +++ b/packages/styles/src/components/chip/chip.md @@ -0,0 +1,37 @@ +# Chip + +## Purpose + +A Chip acts like an interactive Tag and can be used to select or unselect items from a list of options. + +## Functional Requirements + +* Because the Chip is interactive, it should be semantically represented by a `button` element. +* Chips may have visible "active" or "inactive" states or be removed from the page by application logic. + + +## Technical Specifications + +### User Interactions + +* Activating the button within the chip will toggle the `active` class and emit a custom event in addition to the native button's `click` event. + +### Responsiveness + +* Chips should not contain long text and are not intended to wrap. + +### Accessibility + +* Because the Chip is interactive, it should be semantically represented by a `button` element per the provided pattern. Adding the `cbp-chip` class to any other element will result in accessibility defects. +* The `aria-pressed` attribute on the button is set to `true` to indicate the active state of a Chip. +* Chips/buttons without accessibile label text, such as icons, should use the `aria-label` attribute on the button to specify an accessible label. + +### Usage Notes and Additional Considerations + +* A custom event of `chipToggle` is emitted from the parent component tag. The custom event's `details` contain the following keys: + * `chip`: a DOM reference to the button element activated + * `nativeEvent`: the full native `click` event from the activated button + * `active`: a Boolean representing the active state of the button resulting from the user interaction + * `label`: the text label of the Chip/button activated, if one exists + * `value`: the value of the Chip/button activated, if specified +* Applications may tie custom functionality to this event to hide or remove deactivated Chips if desired. \ No newline at end of file From 2c610a2ed1fa4e459f4007f8fe5594934bd165be Mon Sep 17 00:00:00 2001 From: Doug Gibson Date: Fri, 14 Apr 2023 15:08:42 -0400 Subject: [PATCH 5/6] Replaced magic nunbers with CSS variables/tokens --- .../src/sass/components/_badges-chips-tags.scss | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/styles/src/sass/components/_badges-chips-tags.scss b/packages/styles/src/sass/components/_badges-chips-tags.scss index 914c448c..6c411034 100644 --- a/packages/styles/src/sass/components/_badges-chips-tags.scss +++ b/packages/styles/src/sass/components/_badges-chips-tags.scss @@ -1,4 +1,4 @@ -// CBP Badges +// Badges .cbp-badge { display: inline-block; width: var(--cbp-space-6x); @@ -16,7 +16,7 @@ } } -// CBP Tags +// Tags .cbp-tag { display: inline-block; color: var(--cbp-color-white); @@ -45,9 +45,8 @@ } } -// CBP Chips +// Chips .cbp-chip { - // @extend .cbp-text-subhead; display: flex; align-items: center; justify-content: center; @@ -64,10 +63,10 @@ display: flex; align-items: center; justify-content: center; - min-width: 28px; - min-height: 28px; + min-width: var(--cbp-space-7x); + min-height: var(--cbp-space-7x); border-width: 0; - border-radius: 14px; + border-radius: var(--cbp-border-radius-pill); margin-left: 4px; transition: var(--cbp-motion-duration-shortest); } @@ -99,8 +98,8 @@ > .cbp-chip__label + .cbp-chip__icon { background-color: transparent; - border-color: var(--cbp-color-white); - outline: 2px solid white; + border-color: var(--cbp-color-white); + outline: var(--cbp-border-size-md) solid var(--cbp-color-white); outline-offset: -4px; } } From d3944fc575217da3bd1e5f3335a4af824ab222fb Mon Sep 17 00:00:00 2001 From: Doug Gibson Date: Fri, 14 Apr 2023 15:08:55 -0400 Subject: [PATCH 6/6] Updated stories based on feedback --- .../src/components/badge/badge.stories.js | 21 ++++++++----------- .../src/components/chip/chip.stories.js | 21 ++++++++----------- .../styles/src/components/tag/tag.stories.js | 21 ++++++++----------- 3 files changed, 27 insertions(+), 36 deletions(-) diff --git a/packages/styles/src/components/badge/badge.stories.js b/packages/styles/src/components/badge/badge.stories.js index 5965188d..7c47ff98 100644 --- a/packages/styles/src/components/badge/badge.stories.js +++ b/packages/styles/src/components/badge/badge.stories.js @@ -1,23 +1,20 @@ export default { title: 'Patterns/Badges, Chips, and Tags', argTypes: { - variant: { - control: { type: 'select' }, - options: ['', 'danger'], + danger: { + name: 'Danger', + control: { type: 'boolean' }, description: 'Adds a modifier class to the component to display the danger variation (see generated HTML)' + }, }, }; -const BadgeTemplate = (args) => { - const badgeType = args.variant ? `cbp-badge--${args.variant}` : null; - - return ` -
- 5 -
- `; -}; +const BadgeTemplate = ({danger}) => (` +
+ 5 +
+`); export const Badge = BadgeTemplate.bind({}); Badge.args = {}; diff --git a/packages/styles/src/components/chip/chip.stories.js b/packages/styles/src/components/chip/chip.stories.js index 847423d6..181d9d03 100644 --- a/packages/styles/src/components/chip/chip.stories.js +++ b/packages/styles/src/components/chip/chip.stories.js @@ -2,24 +2,21 @@ export default { title: 'Patterns/Badges, Chips, and Tags', argTypes: { active: { + name: 'Active', control: { type: 'boolean' }, description: 'Adds a modifier class indicating an active/selected chip.' }, }, }; -const ChipTemplate = (args) => { - //const active = (args.active ==true) ? 'true' : 'false'; - - return ` - - `; -}; +const ChipTemplate = ({active}) => (` + +`); export const Chip = ChipTemplate.bind({}); Chip.args = {}; \ No newline at end of file diff --git a/packages/styles/src/components/tag/tag.stories.js b/packages/styles/src/components/tag/tag.stories.js index ef972b5b..cfdfc370 100644 --- a/packages/styles/src/components/tag/tag.stories.js +++ b/packages/styles/src/components/tag/tag.stories.js @@ -2,23 +2,20 @@ export default { title: 'Patterns/Badges, Chips, and Tags', argTypes: { variant: { + name: 'Variant', control: { type: 'select' }, options: ['', 'danger', 'success', 'warning'], - description: 'Adds a modifier class to the component to display different color variations (see generated HTML)' + description: + 'Adds a modifier class to the component to display different color variations (see generated HTML)', }, }, }; - -const TagTemplate = (args) => { - const tagType = args.variant ? `cbp-tag--${args.variant}` : null; - - return ` -
- Hotlist -
- `; -}; +const TagTemplate = ({ variant }) => ` +
+ Hotlist +
+`; export const Tag = TagTemplate.bind({}); -Tag.args = {}; \ No newline at end of file +Tag.args = {};