Skip to content

Commit

Permalink
[card-group]: Refactor to use subgrid in favor of sameHeight (#12063)
Browse files Browse the repository at this point in the history
### Related Ticket(s)

Closes #11998

### Description

This is a refactoring of card group to make use of CSS subgrid instead of the Javascript `sameHeight` logic on all the pieces of the card group.

### Changelog

**Changed**

- Use CSS subgrid for layout out the card elements within a card group

<!-- React and Web Component deploy previews are enabled by default. -->
<!-- To enable additional available deploy previews, apply the following -->
<!-- labels for the corresponding package: -->
<!-- *** "test: e2e": Codesandbox examples and e2e integration tests -->
<!-- *** "package: services": Services -->
<!-- *** "package: utilities": Utilities -->
<!-- *** "RTL": React / Web Components (RTL) -->
<!-- *** "feature flag": React / Web Components (experimental) -->
  • Loading branch information
m4olivei authored Oct 10, 2024
1 parent be8d15b commit 86e3290
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 186 deletions.
64 changes: 60 additions & 4 deletions packages/styles/scss/components/card-group/_card-group.scss
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,42 @@
}

:host(#{$c4d-prefix}-card-group-item) {
display: contents;

.#{$prefix}--card {
display: grid;
border: 0;
grid-row: span 10;
grid-template-rows: subgrid;
margin-block-end: $spacing-07;
outline: 1px solid $border-tile-01;
outline-offset: 0;

.#{$prefix}--card__wrapper {
display: grid;
justify-content: revert;
grid-row: span 10;
grid-template-rows: subgrid;

&::before,
&::after {
content: revert;
}
}

.#{$prefix}--card__content {
display: grid;
grid-row: span 10;
grid-template-rows: subgrid;
row-gap: 0;
}

.#{$prefix}--card__copy {
display: grid;
grid-row: span 2;
grid-template-rows: subgrid;
row-gap: 0;
}
}

.#{$prefix}--image {
Expand All @@ -84,6 +116,30 @@
outline-offset: -1px;
}
}

&[grid-mode='narrow'] {
.#{$prefix}--card {
margin-block-end: $spacing-05;
}
}

&[grid-mode='condensed'] {
.#{$prefix}--card {
margin-block-end: 0;
}
}

::slotted(#{$c4d-prefix}-card-footer) {
display: revert;
margin-block-start: revert;
}

// Selects elements that contain tags which are slotted into the default
// slot. Note that this does not work in Chrome at time of writing.
// @see https://developer.chrome.com/blog/has-m105/#performance_and_limitations
::slotted(:not([slot]):has(#{$prefix}-tag, #{$c4d-prefix}-tag)) {
grid-row: -1;
}
}

:host(#{$c4d-prefix}-card-group-item[href='']) {
Expand All @@ -110,24 +166,24 @@

:host(#{$c4d-prefix}-card-group)[grid-mode='narrow'] {
@include breakpoint(sm) {
gap: $spacing-03;
gap: 0 $spacing-03;
padding-block-start: $spacing-03;
}

@include breakpoint(md) {
gap: $spacing-05;
gap: 0 $spacing-05;
padding-block-start: $spacing-05;
}
}

:host(#{$c4d-prefix}-card-group)[grid-mode='default'] {
@include breakpoint(sm) {
gap: $spacing-07;
gap: 0 $spacing-07;
padding-block-start: $spacing-03;
}

@include breakpoint(md) {
gap: $spacing-07;
gap: 0 $spacing-07;
padding-block-start: $spacing-05;
}
}
Expand Down
14 changes: 12 additions & 2 deletions packages/styles/scss/components/card/_card.scss
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,13 @@

.#{$prefix}--card__heading,
.#{$prefix}--card__copy {
@include content-width;

color: $text-primary;
max-inline-size: to-rem(640px);
padding-inline-end: 10%;

@include breakpoint(md) {
padding-inline-end: $spacing-07;
}
}

.#{$prefix}--card__copy:not([hidden]) {
Expand Down Expand Up @@ -185,6 +189,10 @@
}
}

.#{$prefix}--card__pictogram-wrapper {
display: flex;
}

&[pictogram] .#{$prefix}--card {
::slotted(#{$c4d-prefix}-card-heading) {
padding-block-start: 0;
Expand Down Expand Up @@ -417,6 +425,7 @@

:host(#{$c4d-prefix}-card-eyebrow),
.#{$prefix}--card__eyebrow {
display: block;
@include content-width;
@include type-style('label-02');

Expand Down Expand Up @@ -597,6 +606,7 @@

:host(#{$c4d-prefix}-card-heading),
:host(#{$c4d-prefix}-card-link-heading) {
display: block;
@include content-width;

color: $text-primary;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import settings from '@carbon/ibmdotcom-utilities/es/utilities/settings/settings
import { carbonElement as customElement } from '@carbon/web-components/es/globals/decorators/carbon-element.js';
import C4DCard from '../card/card';
import styles from './card-group.scss';
import { GRID_MODE } from './defs';

const { stablePrefix: c4dPrefix } = settings;

Expand All @@ -23,16 +24,17 @@ const { stablePrefix: c4dPrefix } = settings;
@customElement(`${c4dPrefix}-card-group-item`)
class C4DCardGroupItem extends C4DCard {
/**
* `true` if the card group is using border.
* `true` if the card group item is empty.
*/
@property({ type: Boolean, reflect: true })
border = false;
empty = false;

/**
* `true` if the card group item is empty.
* The inherited grid mode the card group item lives within.
* Condensed (1px) | Narrow (16px) | Default(32px).
*/
@property({ type: Boolean, reflect: true })
empty = false;
@property({ attribute: 'grid-mode', reflect: true })
gridMode = GRID_MODE.DEFAULT;

static get stableSelector() {
return `${c4dPrefix}--card-group-item`;
Expand Down
160 changes: 7 additions & 153 deletions packages/web-components/src/components/card-group/card-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import { LitElement, html } from 'lit';
import { property, state } from 'lit/decorators.js';
import settings from '@carbon/ibmdotcom-utilities/es/utilities/settings/settings.js';
import sameHeight from '@carbon/ibmdotcom-utilities/es/utilities/sameHeight/sameHeight.js';
import { GRID_MODE } from './defs';
import styles from './card-group.scss';
import StableSelectorMixin from '../../globals/mixins/stable-selector';
Expand All @@ -20,9 +19,6 @@ export { GRID_MODE };

const { stablePrefix: c4dPrefix } = settings;

// tag constants used for same height calculations
const headingBottomMargin = 64;

/**
* Card Group.
*
Expand All @@ -35,55 +31,6 @@ class C4DCardGroup extends StableSelectorMixin(LitElement) {
*/
private _childItems: any[] = [];

/**
* Array to hold the card-heading elements within child items.
*/
private _childItemHeadings: any[] = [];

/**
* Array to hold the card-eyebrow elements within child items.
*/
private _childItemEyebrows: any[] = [];

/**
* Array to hold the tag-group elements within child items.
*/
private _childItemTagGroup: any[] = [];

/**
* Array to hold the paragraph elements within child items.
*/
private _childItemParagraphs: any[] = [];

/**
* Array to hold the card-cta-footer elements within child items.
*/
private _childItemFooters: any[] = [];

/**
* The observer for the resize of the viewport.
*/
private _observerResizeRoot: any | null = null; // TODO: Wait for `.d.ts` update to support `ResizeObserver`

/**
* Cleans-up and creats the resize observer for the scrolling container.
*
* @param [options] The options.
* @param [options.create] `true` to create the new resize observer.
*/
private _cleanAndCreateObserverResize({ create }: { create?: boolean } = {}) {
if (this._observerResizeRoot) {
this._observerResizeRoot.disconnect();
this._observerResizeRoot = null;
}
if (create) {
// TODO: Wait for `.d.ts` update to support `ResizeObserver`
// @ts-ignore
this._observerResizeRoot = new ResizeObserver(this._resizeHandler);
this._observerResizeRoot.observe(this.ownerDocument!.documentElement);
}
}

/**
* Handler for @slotchange, set the height of all headings to the tallest height.
*
Expand All @@ -98,37 +45,12 @@ class C4DCardGroup extends StableSelectorMixin(LitElement) {
)
);

// retrieve item heading, eyebrows, and footers to set same height
// Retrieve item heading, eyebrows, and footers to set same height.
if (this._childItems) {
this._childItems.forEach((e) => {
if (!e.hasAttribute('href') && this.gridMode === GRID_MODE.CONDENSED) {
this.gridMode = GRID_MODE.DEFAULT;
}
this._childItemEyebrows.push(
(e as HTMLElement).querySelector(
(this.constructor as typeof C4DCardGroup).selectorItemEyebrow
)
);
this._childItemParagraphs.push(
(e as HTMLElement).querySelector(
(this.constructor as typeof C4DCardGroup).selectorItemParagraph
)
);
this._childItemTagGroup.push(
(e as HTMLElement).querySelector(
(this.constructor as typeof C4DCardGroup).selectorItemTagGroup
)
);
this._childItemHeadings.push(
(e as HTMLElement).querySelector(
(this.constructor as typeof C4DCardGroup).selectorItemHeading
)
);
this._childItemFooters.push(
(e as HTMLElement).querySelector(
(this.constructor as typeof C4DCardGroup).selectorItemFooter
)
);
});

const { customPropertyCardsPerRow } = this
Expand All @@ -137,70 +59,9 @@ class C4DCardGroup extends StableSelectorMixin(LitElement) {
customPropertyCardsPerRow,
String(this.cardsPerRow)
);

if (this.gridMode !== GRID_MODE.NARROW) {
this._resizeHandler();
}
}
}

/**
* The observer for the resize of the viewport, calls sameHeight utility function
*/
private _resizeHandler = () => {
if (!this.pictograms) {
window.requestAnimationFrame(() => {
this._setSameHeight();
});
}
};

private _setSameHeight = () => {
// check if items are not null before using sameHeight

sameHeight(
this._childItemEyebrows.filter((item) => item !== null),
'md'
);
sameHeight(
this._childItemHeadings.filter((item) => item !== null),
'md'
);
sameHeight(
this._childItemParagraphs.filter((item) => item !== null),
'md'
);
sameHeight(
this._childItemFooters.filter((item) => item !== null),
'md'
);

let tagGroupHeight = 0;

// get tallest height of tag groups
this._childItemTagGroup.forEach((item) => {
if (item) {
const groupHeight = (item as HTMLElement).offsetHeight;
if (groupHeight > tagGroupHeight) {
tagGroupHeight = groupHeight;
}
}
});

this._childItemHeadings.forEach((e) => {
// add tag group height to heading to the cards lacking tag group
if (
e &&
!e.parentElement.hasAttribute('link') &&
!e.nextElementSibling?.matches(
(this.constructor as typeof C4DCardGroup).selectorItemTagGroup
)
) {
e.style.marginBottom = `${tagGroupHeight + headingBottomMargin}px`;
}
});
};

/**
* The number of columns per row. Min 2, max 4, default 3. Applies to >=`lg` breakpoint only.
*/
Expand Down Expand Up @@ -243,16 +104,6 @@ class C4DCardGroup extends StableSelectorMixin(LitElement) {
@property({ type: Boolean, reflect: true })
pictograms = false;

connectedCallback() {
super.connectedCallback();
this._cleanAndCreateObserverResize({ create: true });
}

disconnectedCallback() {
this._cleanAndCreateObserverResize();
super.disconnectedCallback();
}

firstUpdated() {
super.connectedCallback();

Expand All @@ -263,11 +114,14 @@ class C4DCardGroup extends StableSelectorMixin(LitElement) {
) {
this.setAttribute('with-card-in-card', '');
}
this._cleanAndCreateObserverResize({ create: true });
}

updated() {
this._resizeHandler();
updated(changedProperties) {
super.updated(changedProperties);

if (changedProperties.has('gridMode')) {
this._childItems.forEach((e) => (e.gridMode = this.gridMode));
}
}

render() {
Expand Down
Loading

0 comments on commit 86e3290

Please sign in to comment.