Files
xrpl-dev-portal/shared/patterns/SectionHeader/SectionHeader.tsx
Calvin 32e89c1299 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
2026-02-23 15:00:18 -08:00

112 lines
3.2 KiB
TypeScript

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;