← All proposals

Panel

The PDS v2 Panel (src/components/panels/Panel, branch v2.x) with one addition: the agentic-default, agentic-raised and agentic-sunken variants: each existing surface with the AI gradient as the border.

Extends a PDS componentOpen in Storybook

proposals/Panel/panel.css160 lines · View on GitHub
.pds-panel {
	--border-color: var(--pds-color-border-default);
	--bg-color: var(--pds-color-surface-default);

	background-color: var(--bg-color);
	border: var(--pds-border-width-default) solid var(--border-color);
	border-radius: var(--pds-border-radius-panel);
	display: flex;
}

.pds-panel__content > *:last-child {
	margin-block-end: 0;
}

/* Panel heading (h1-h6) sized like `pds-heading-l`, as a direct child of
   the content wrapper or one level deep (e.g. an icon + heading header
   row). Headings nested deeper need `pds-heading-l` applied directly. */
.pds-panel__content > :is(h1, h2, h3, h4, h5, h6):first-child,
.pds-panel__content > *:first-child > :is(h1, h2, h3, h4, h5, h6):first-child {
	font-size: var(--pds-typography-size-l);
}

/* Space below any heading that has content following it (adjacent-sibling,
   not margin-plus-cancel-on-last-child, so a trailing heading never gets a
   phantom gap). Excludes .visually-hidden headings (Pagination et al. use
   one purely for aria-labelledby, immediately followed by real content).
   Matches an allow-list of body-content tags rather than excluding known
   decorative companions (Tooltip, Badge, etc.), so div/span-based
   components can never slip through and falsely trigger this. */
.pds-panel__content
	:is(h1, h2, h3, h4, h5, h6):not(.visually-hidden)
	+ :is(p, ul, ol, dl, blockquote, table, pre, form, h1, h2, h3, h4, h5, h6) {
	margin-block-start: var(--pds-spacing-s);
}

.pds-panel__content {
	display: block;
	padding: var(--pds-spacing-l);
	width: 100%;
}

.pds-panel__content--pad-condensed {
	padding: var(--pds-spacing-m);
}

.pds-panel__content--pad-none {
	padding: 0;
}

.pds-panel__content--pad-spacious {
	padding: var(--pds-spacing-xl);
}

/* v2 uses `@media (--pds-bp-m)`. This repo has no postcss custom-media plugin,
   so the literal value is used; the port restores the token form. */
@media (min-width: 768px) {
	.pds-panel__content {
		padding: var(--pds-spacing-xl);
	}

	.pds-panel__content--pad-condensed {
		padding: var(--pds-spacing-l);
	}

	.pds-panel__content--pad-none {
		padding: 0;
	}

	.pds-panel__content--pad-spacious {
		padding: var(--pds-spacing-2xl);
	}
}

/* Variants */

.pds-panel--sunken {
	--bg-color: var(--pds-color-panel-sunken-background);

	box-shadow: var(--pds-elevation-panel-sunken);
}

.pds-panel--raised {
	--border-color: transparent;

	box-shadow: var(--pds-elevation-raised);
}

.pds-panel--overlay {
	--border-color: transparent;

	box-shadow: var(--pds-elevation-overlay);
}

.pds-panel--critical {
	--border-color: var(--pds-color-status-critical-border);
}

.pds-panel--discovery {
	--border-color: var(--pds-color-status-discovery-border);
}

.pds-panel--info {
	--border-color: var(--pds-color-status-info-border);
}

.pds-panel--success {
	--border-color: var(--pds-color-status-success-border);
}

.pds-panel--warning {
	--border-color: var(--pds-color-status-warning-border);
}

/* Agentic variants (agentic-default, -raised, -sunken): the surface's own
   fill and shadow with the AI gradient as the border. The component adds this
   class beside the surface class (e.g. --raised), and this rule comes after
   them.
   --pds-gradient-ai-active is a gradient, not a color, so it cannot go in
   border-color. The border is transparent and the gradient is painted on the
   border-box underneath; the surface fill sits on the padding-box above it.
   Same technique as the agentic Button. */
.pds-panel--agentic {
	--border-color: transparent;

	background-clip: padding-box, border-box;
	background-color: transparent;
	background-image:
		linear-gradient(var(--bg-color), var(--bg-color)),
		var(--pds-gradient-ai-active);
	background-origin: border-box;
}

/* Animated (agentic only): the gradient layer is twice the panel width and
   repeats, and slides by one tile so the loop is seamless (the gradient ends
   on its start color). The fill layer stays put. Off for reduced motion. */
@media (prefers-reduced-motion: no-preference) {
	.pds-panel--agentic.pds-panel--animated {
		animation: panel-shimmer var(--pds-animation-duration-ai-shimmer) linear
			infinite;
		background-repeat: no-repeat, repeat-x;
		background-size:
			100% 100%,
			200% 100%;
	}
}

@keyframes panel-shimmer {
	from {
		background-position:
			0 0,
			0 0;
	}

	to {
		background-position:
			0 0,
			-200% 0;
	}
}