Component Library Refactor & New Components (#3510)

* adding showcase page

* adding CardStatsList

* clean up, tighter code

* code review and code clean up

* update import, clean up env for error message

* tweak some css code

* less css, rebuilt

* re-adding bem, modifier for bds variants
This commit is contained in:
Calvin
2026-02-23 15:00:18 -08:00
committed by Calvin Jhunjhuwala
parent fe1aa0ecb1
commit 176fb3cbc7
120 changed files with 2394 additions and 793 deletions

View File

@@ -0,0 +1,50 @@
// BDS SectionHeader Pattern Styles
// Brand Design System - Consolidated section header (heading + description)
//
// Naming Convention: BEM with 'bds' namespace
// .bds-section-header - Header wrapper for heading and description
// .bds-section-header__heading - Section heading (uses .h-md)
// .bds-section-header__description - Section description (uses .body-l)
//
// Design tokens from _spacing.scss:
// - Gap between heading and description: $bds-gap-header-*
// - Light/Dark mode colors: $black / $white
// =============================================================================
// Header Section
// =============================================================================
.bds-section-header {
display: flex;
flex-direction: column;
gap: $bds-gap-header-sm;
margin-bottom: $bds-gap-section-sm;
@include media-breakpoint-up(md) {
gap: $bds-gap-header-md;
margin-bottom: $bds-gap-section-md;
}
@include media-breakpoint-up(lg) {
gap: $bds-gap-header-lg;
margin-bottom: $bds-gap-section-lg;
}
@include bds-theme-mode(light) {
color: $black;
}
@include bds-theme-mode(dark) {
color: $white;
}
}
.bds-section-header__heading {
margin: 0;
// Typography handled by .h-md class from _font.scss
}
.bds-section-header__description {
margin: 0;
// Typography handled by .body-l class from _font.scss
}

View File

@@ -0,0 +1,111 @@
import React from 'react';
import clsx from 'clsx';
import { PageGrid } from '../../components/PageGrid/page-grid';
import type { ResponsiveValue, PageGridSpanValue } from '../../components/PageGrid/page-grid';
import { isEnvironment } from '../../utils/helpers';
const DEFAULT_SPAN = {
base: 'fill' as const,
md: 6,
lg: 8,
};
export interface SectionHeaderProps {
/** Section heading text */
heading?: React.ReactNode;
/** Section description text */
description?: React.ReactNode;
/** Polymorphic heading element - h1 through h6 */
as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
/** PageGrid.Col span - defaults to { base: 'fill', md: 6, lg: 8 } */
span?: ResponsiveValue<PageGridSpanValue>;
/** Optional slot for trailing content (e.g. ButtonGroup) */
children?: React.ReactNode;
/** Additional CSS classes for the header wrapper */
className?: string;
}
/**
* SectionHeader - Consolidated section header pattern
*
* Renders a PageGrid.Row + Col with heading (polymorphic h1-h6) and optional description.
* Used across CardsFeatured, StandardCardGroupSection, CardsIconGrid, and other sections.
*
* **Behavior:**
* - Returns `null` if no content is provided (no heading, description, or children)
* - Logs a development warning when returning null to help catch missing props
* - At least one of `heading`, `description`, or `children` should be provided
*
* @example
* // Typical usage with heading and description
* <SectionHeader
* heading="Our Features"
* description="Explore what we offer"
* />
*
* @example
* // With custom heading level
* <SectionHeader
* heading="Main Title"
* as="h1"
* description="Subtitle text"
* />
*
* @example
* // With children (e.g., ButtonGroup)
* <SectionHeader heading="Products">
* <ButtonGroup buttons={[...]} />
* </SectionHeader>
*/
export const SectionHeader = React.forwardRef<HTMLDivElement, SectionHeaderProps>(
(props, ref) => {
const {
heading,
description,
as = 'h2',
span = DEFAULT_SPAN,
children,
className,
} = props;
const hasContent = heading || description || children;
if (!hasContent) {
if (isEnvironment(["development", "test"])) {
console.warn(
'SectionHeader: No content provided. Component requires at least one of: heading, description, or children. ' +
'Returning null - this may indicate a missing prop or data issue.'
);
}
return null;
}
const HeadingTag = as;
return (
<PageGrid.Row>
<PageGrid.Col span={span}>
<div
ref={ref}
className={clsx('bds-section-header', className)}
>
{heading != null && heading !== '' && (
<HeadingTag className="bds-section-header__heading h-md">
{heading}
</HeadingTag>
)}
{description != null && description !== '' && (
<p className="bds-section-header__description body-l">
{description}
</p>
)}
{children}
</div>
</PageGrid.Col>
</PageGrid.Row>
);
}
);
SectionHeader.displayName = 'SectionHeader';
export default SectionHeader;

View File

@@ -0,0 +1 @@
export { SectionHeader, type SectionHeaderProps } from './SectionHeader';