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 anisAgenticboolean like Button, IconButton and MenuButton. The combinations are explicit, but each new surface needs its ownagentic-*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-activeis a gradient, so it can't go inborder-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. isAnimatedshimmers the border and is on by default. It stays on until the screen passesisAnimated={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 anagentic-*variant. It is gated onprefers-reduced-motion: no-preferenceand 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.
- Classes on
- 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 Contentsample (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
divand 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:
- Variants vs
isAgentic. Threeagentic-*variants (this proposal) or anisAgenticboolean like the other agentic components. Each new surface needs its ownagentic-*value. - Animation default.
isAnimatedis on by default for agentic panels. Confirm, or flip it to off and have the screen opt in. - 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.
- 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.
- Dark mode. The gradient and fills need checking in dark.
Port notes
- Lives with the existing Panel:
src/components/panels/Panelinpds-toolkit-react(branchv2.x). No generator needed, since this edits an existing component. ApplyPanel.tsxandpanel.cssas a diff against it. - Local stand-ins to replace with the real ones:
mergeClasses(imported from../Button/utilshere) andPanelPadding(v2'sPaddingScale). - Restore
@media (--pds-bp-m)in the CSS. PanelPropsis a discriminated union soisAnimatedis only accepted onagentic-*. Storybook'sifconditions 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
isAnimatedto 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.