← 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/HANDOFF.md112 lines · View on GitHub

Handoff: Panel (agentic variants)

What and why

An agent sometimes produces a whole surface on the main screen, such as an investigation report with a proposed fix and the buttons to approve it. That surface needs to read as the agent's, the way the agentic Button, IconButton and MenuButton do. The PDS v2 Panel has no agentic option.

This proposal is the PDS v2 Panel plus three variants, agentic-default, agentic-raised and agentic-sunken. Each is the existing surface with the AI gradient as its border, and an optional shimmer (isAnimated) for while the agent is working. Everything else (variants, padding, heading rules) is unchanged, so the port is a diff against src/components/panels/Panel on v2.x.

  • Figma / Jira: none. Source was a designer screenshot of a full-width panel with an agentic border and a "Zappy" tab.
  • Context: context.md

Exploration and decisions

  • Variants, not a boolean. Agentic is three variants (agentic-<surface>) rather than an isAgentic boolean like Button, IconButton and MenuButton. The combinations are explicit, but each new surface needs its own agentic-* value, and this is inconsistent with the other agentic components. Flagged below.
  • Gradient border technique is the same as the agentic Button. --pds-gradient-ai-active is a gradient, so it can't go in border-color. The border is transparent, the gradient sits on the border-box, and the panel fill sits on the padding-box above it.
  • Fill and shadow are reused. agentic-<surface> renders the surface's own class plus --agentic, so no fill or shadow is redefined.
  • isAnimated shimmers the border and is on by default. It stays on until the screen passes isAnimated={false}, for example when the agent finishes. This differs from the other agentic components (static) and from the usual "defaults off" convention. It is typed so it is only accepted with an agentic-* variant. It is gated on prefers-reduced-motion: no-preference and uses --pds-animation-duration-ai-shimmer. The slide is one gradient tile that ends on its start color, so the loop is seamless.
  • Left out: the small "Zappy" label that sits on the border in the reference, and the report content itself.

API

Prop Type Default Purpose
children ReactNode required Panel content.
className string none Additional class names.
isAnimated boolean true on agentic-* Shimmer the agentic border while the agent is working. Only accepted with an agentic-* variant (never otherwise). Off for reduced motion.
padding 'condensed' | 'none' | 'spacious' | 'standard' 'standard' Padding for the panel.
variant PanelVariant 'default' Panel variant. New values: agentic-default, agentic-raised, agentic-sunken.

Variants and states:

  • agentic-default: default surface fill, AI gradient border.
  • agentic-raised: default fill with the raised shadow, AI gradient border.
  • agentic-sunken: sunken fill with the inset shadow, AI gradient border.
  • Each agentic variant is animated by default and static with isAnimated={false}.
  • The existing variants are unchanged.

Tokens used

  • --pds-animation-duration-ai-shimmer
  • --pds-border-radius-panel
  • --pds-border-width-default
  • --pds-color-border-default
  • --pds-color-foreground-default-secondary
  • --pds-color-panel-sunken-background
  • --pds-color-status-critical-border
  • --pds-color-status-discovery-border
  • --pds-color-status-info-border
  • --pds-color-status-success-border
  • --pds-color-status-success-foreground
  • --pds-color-status-warning-border
  • --pds-color-surface-default
  • --pds-elevation-overlay
  • --pds-elevation-panel-sunken
  • --pds-elevation-raised
  • --pds-gradient-ai-active
  • --pds-spacing-2xl
  • --pds-spacing-2xs
  • --pds-spacing-l
  • --pds-spacing-m
  • --pds-spacing-s
  • --pds-spacing-xl
  • --pds-spacing-xs
  • --pds-typography-ff-default
  • --pds-typography-fw-semibold
  • --pds-typography-lh-m
  • --pds-typography-size-l
  • --pds-typography-size-s
  • --pds-typography-size-xs

Reused vs net-new

  • Reused: the whole v2 Panel (variants, padding, heading rules). Fill, shadow and radius tokens for the agentic variants come from the existing surfaces.
  • Net-new:
    • Classes on .pds-panel: .pds-panel--agentic, .pds-panel--animated.
    • Variant values: agentic-default, agentic-raised, agentic-sunken.
    • Prop: isAnimated.
    • CSS variables, set on .pds-panel: --bg-color, --border-color.
  • Raw values kept: none. The @media (min-width: 768px) literal replaces (--pds-bp-m) only because this repo has no postcss custom-media plugin. The port restores the token form.
  • Story-only, not part of the Panel: the With Content sample (ApprovalReport.tsx, approval-report.css). It is built from the Panel (sunken), Code Diff, Button (agentic primary), Icon and Agent Avatar proposals. The content belongs to the screen.

See custom.md for the full list.

Accessibility

  • The Panel is a plain div and adds no role. Semantics come from the content, as with the v2 Panel.
  • The gradient border is decorative and carries no meaning of its own. Don't rely on it alone to say "agent content": label the content (as the sample does with a heading and the Zappy avatar).
  • The shimmer only runs under prefers-reduced-motion: no-preference.
  • Not yet done: the Storybook a11y panel has not been run on each story, in light or dark. Contrast of the fills in dark mode is also unchecked. Do both before merging.

Decisions and open questions

For the engineer or PDS team to decide:

  1. Variants vs isAgentic. Three agentic-* variants (this proposal) or an isAgentic boolean like the other agentic components. Each new surface needs its own agentic-* value.
  2. Animation default. isAnimated is on by default for agentic panels. Confirm, or flip it to off and have the screen opt in.
  3. Shimmer across the system. Button, IconButton and MenuButton are static. One shared mechanism or a prop on each is a system-level question for the PDS team.
  4. The "Zappy" tab label on the border is not built. If other agent surfaces need it, it belongs on the agentic container as an optional label.
  5. Dark mode. The gradient and fills need checking in dark.

Port notes

  • Lives with the existing Panel: src/components/panels/Panel in pds-toolkit-react (branch v2.x). No generator needed, since this edits an existing component. Apply Panel.tsx and panel.css as a diff against it.
  • Local stand-ins to replace with the real ones: mergeClasses (imported from ../Button/utils here) and PanelPadding (v2's PaddingScale).
  • Restore @media (--pds-bp-m) in the CSS.
  • PanelProps is a discriminated union so isAnimated is only accepted on agentic-*. Storybook's if conditions can't match a set of values, so the stories use a flat args type and the control shows on every variant.
  • Add stories for the three variants and isAnimated to the real Panel stories.

Preview

npm run storybook (port 6007), then Proposals/Panel. The With Content and All Agentic Variants stories show it in use. Use the Theme toggle to check dark.