mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2026-09-27 23:47:59 +00:00
* BDS component polish: link visibility, static cards, uniform CTAs Component-level fixes and refinements across the 2026 brand components. Accessibility / contrast - StandardCard: pin description link colors. Every card variant has a light background in both themes, so theme-level link colors were wrong inside it — dark mode painted plain anchors white and BdsLink lilac-300, both of which wash out on a pale card. Links (including :visited) now use the card's own text color with an underline carrying the affordance; hover uses lilac-500, which clears 4.5:1 on all four card backgrounds. - Breadcrumbs: point the open dropdown menu at the breadcrumb color tokens so the trail, trigger, and menu read as one color in both themes, and give dark mode gray-6 (7.41:1, matching light mode's 7.23:1). Interaction - CardOffgrid: drop every hover affordance when a card has neither href nor onClick. Static cards no longer get a pointer cursor, the color-wipe overlay, or a pressed state — the tokenization and trading carousels pass link-less cards and were advertising a click target that did not exist. - CarouselFeatured: add a 'fade' transition alongside the default 'slide', for decks whose slides share a heading. Inactive slides are now inert, keeping focus and pointer events out of them in both styles. - Add a bds-reduced-motion mixin so components can collapse motion to an instant state change. Design consistency - ButtonGroup: add forceVariant and forceNoPadding overrides, letting a section opt out of the count-based variant defaults and render one uniform treatment. Existing consumers are unaffected. - FeatureTwoColumn: render every link as a tertiary button regardless of count, flush with the title and description. - CardImage: render an all-bullet subtitle as a real <ul> so wrapped text hangs under the first character and screen readers announce it as a list. - docs: give the node-installation card descriptions a paragraph break before their "Learn More" link. Dependencies - Bump @codemirror/state and view, add lang-javascript, lang-json, and lint, with overrides pinning state/view to one copy. Docs updated alongside each component. Built CSS regenerated with the production script to match the committed artifact's minified format. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * ButtonGroup: don't strip padding from forced filled variants `noPadding` was derived as `forceNoPadding || isMultiButton`, which was safe while the 3+ block layout was always tertiary. `forceVariant` also accepts `primary` and `secondary`, so a 3-button group forcing a filled variant had `padding: 0 !important` (Button.scss) applied with no way to opt out. Tie the implied no-padding to the resolved variant being tertiary. Behavior is unchanged for every caller that doesn't pass `forceVariant`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Stacked hero variant, fade-by-default carousel, component docs Layout - HeaderHeroPrimaryMedia: add a `stacked` prop that puts the headline, subtitle, and buttons in one column (full width at base, 7/8 at md, 9/12 at lg) instead of the default headline-left / CTA-right split. The headline and CTA block bottom-align against each other in the two-column layout, so the stacked variant undoes that. Both arrangements now share the same headline and CTA elements, so they can't drift apart. Used on the docs landing hero. Motion - CarouselFeatured: make `fade` the default transition. Slides that share a heading are the common case, and a horizontal wipe drags the identical heading across the screen only to set it back down. `slide` is now opt-in for decks whose panels are genuinely distinct. Nudge the crossfade to 260ms in / 200ms out. The home page carousel opts into fade explicitly; developer-funding now inherits it. Fixes - CardTextIconCard: pass `headingAs` through to `cardContent`, which was accepting the prop but never receiving it. Docs - Expand the Button, CardImage, CardTextIcon, PageGrid, CalloutMediaBanner, LogoSquareGrid, and HeaderHeroPrimaryMedia references. Built CSS regenerated with the production script. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
132 lines
3.6 KiB
TypeScript
132 lines
3.6 KiB
TypeScript
import React from 'react';
|
|
import clsx from 'clsx';
|
|
import { PageGrid } from '../PageGrid/page-grid';
|
|
import type { ResponsiveValue, PageGridSpanValue } from '../PageGrid/page-grid';
|
|
|
|
export interface CardTextIconCardProps {
|
|
/** Icon image URL */
|
|
icon?: string;
|
|
/** Alt text for the icon image */
|
|
iconAlt?: string;
|
|
/** Card heading */
|
|
heading: string;
|
|
/** Semantic heading element. Defaults to `'h3'` so cards enter the document outline.
|
|
* Use a heading level that fits the page hierarchy (typically one below the section heading). */
|
|
headingAs?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
|
|
/** Card description; accepts rich content (e.g., text with inline links) */
|
|
description: React.ReactNode | string;
|
|
/** Optional aspect ratio for future use; applied via CSS variable */
|
|
aspectRatio?: number;
|
|
/** When provided, renders as PageGrid.Col as="li" with this span—card becomes the grid column */
|
|
gridColSpan?: ResponsiveValue<PageGridSpanValue>;
|
|
/** Additional CSS classes */
|
|
className?: string;
|
|
/** Optional height and width for the icon image */
|
|
height?: number;
|
|
width?: number;
|
|
}
|
|
|
|
/**
|
|
* CardTextIconCard Component
|
|
*
|
|
* A card component featuring an icon, heading, and description.
|
|
* Built from Section Cards - Icon and Section Cards - Text Grid Figma designs.
|
|
*
|
|
* The description accepts ReactNode so it can include hyperlinks and other rich content.
|
|
*
|
|
* @example
|
|
* // Basic usage
|
|
* <CardTextIconCard
|
|
* icon="/icons/docs.svg"
|
|
* iconAlt="Documentation"
|
|
* heading="Documentation"
|
|
* description="Access everything you need to get started with the XRPL."
|
|
* />
|
|
*
|
|
* @example
|
|
* // With inline link in description
|
|
* <CardTextIconCard
|
|
* icon="/icons/docs.svg"
|
|
* heading="Documentation"
|
|
* description={
|
|
* <>
|
|
* Learn more in our{' '}
|
|
* <a href="/docs">documentation</a>.
|
|
* </>
|
|
* }
|
|
* />
|
|
*/
|
|
const cardContent = (
|
|
heading: string,
|
|
headingAs: NonNullable<CardTextIconCardProps['headingAs']>,
|
|
description: React.ReactNode | string,
|
|
icon?: string,
|
|
iconAlt?: string,
|
|
iconHeight?: number,
|
|
iconWidth?: number
|
|
) => {
|
|
const HeadingElement = headingAs;
|
|
return (
|
|
<>
|
|
<div className="bds-card-text-icon-card__icon">
|
|
{icon && (
|
|
<img
|
|
src={icon}
|
|
alt={iconAlt}
|
|
{...(iconHeight != null && { height: iconHeight })}
|
|
{...(iconWidth != null && { width: iconWidth })}
|
|
className="bds-card-text-icon-card__icon-img"
|
|
loading="lazy"
|
|
decoding="async"
|
|
/>
|
|
)}
|
|
<HeadingElement className="bds-card-text-icon-card__heading sh-md-r">{heading}</HeadingElement>
|
|
</div>
|
|
<p className="bds-card-text-icon-card__description body-l">
|
|
{description}
|
|
</p>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export const CardTextIconCard: React.FC<CardTextIconCardProps> = ({
|
|
icon,
|
|
iconAlt = '',
|
|
heading,
|
|
headingAs = 'h3',
|
|
description,
|
|
aspectRatio,
|
|
gridColSpan,
|
|
className,
|
|
height,
|
|
width
|
|
}) => {
|
|
const style = aspectRatio
|
|
? ({ '--bds-card-text-icon-aspect-ratio': aspectRatio } as React.CSSProperties)
|
|
: undefined;
|
|
|
|
if (gridColSpan) {
|
|
return (
|
|
<PageGrid.Col
|
|
as="li"
|
|
span={gridColSpan}
|
|
className={clsx('bds-card-text-icon-card', 'bds-card-text-icon-card--grid-col', className)}
|
|
style={style}
|
|
>
|
|
{cardContent(heading, headingAs, description, icon, iconAlt, height, width)}
|
|
</PageGrid.Col>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div
|
|
className={clsx('bds-card-text-icon-card', className)}
|
|
style={style}
|
|
>
|
|
{cardContent(heading, headingAs, description, icon, iconAlt, height, width)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default CardTextIconCard;
|