feat(apollo-wind): add DAP component patterns page - #1008
Conversation
…nder crossing lines Two bugs in CanvasEdge/SequenceEdge labels, plus a new Storybook reference page documenting label behavior across themes and edge cases. Bug 1 — line renders over the label: EdgeLabel rendered as a raw foreignObject inside its own edge's <g>, so it competed in the same per-edge z-index/DOM-order stack as every other edge's stroke. An unselected edge crossing near a label could paint its line over that label. Fixed by portaling the label through xyflow's EdgeLabelRenderer instead (the pattern StageEdge/EdgeToolbar already use), which always paints after every edge's own <svg>, regardless of z-index or array order. Bug 2 — label background can render fully transparent: `background: var(--canvas-background)` had no fallback value. That variable only resolves under a themed ancestor (body.light/.future-*/.vertex/.canvas per canvas/styles/variables.css); a host that mounts the canvas without one (e.g. a shadow-DOM host) got a transparent label with illegible text over the line. Added a `--color-background` fallback to both EdgeLabel.tsx and StageEdge.tsx's StageEdgeLabel. New: Components/Edges/EdgeLabels Storybook page Consolidates label documentation that was previously scattered (and, in one spot, stale — SequenceEdge.stories.tsx's old EdgeLabels story still claimed labels render via "SVG foreignObject") into one dedicated reference page: - Orientation, Diff States: baseline label behavior - Crossing Labeled Edges: regression coverage for Bug 1 - Themes: the same label across all 9 canvas themes side by side - Missing Theme Fallback: reproduces Bug 2's scenario directly (simulates an unthemed ancestor via CSS custom-property `initial`), and documents the one remaining gap the fallback doesn't cover (no themed ancestor at all, background still transparent) - Overflow: long label text and short-edge crowding (known, undocumented limitations, not fixed here) - Execution Status, Bent Path, Read Only: label composes correctly with execution-status coloring, multi-segment waypoint routing, and readonly mode Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…view Node labels support double-click-to-edit (BaseNode/NodeLabel's EditableLabel), but edge labels do not. EdgeLabel is pointer-events: none and CanvasEdgeData has no onLabelChange field, so there's no way to rename a label from the canvas. Clicking the label also passes straight through to the edge underneath and selects the whole edge, since the label isn't a hit target itself, the same root cause as the missing editing support: enabling pointer events on the label to support editing also changes what clicking it does today. Adds a story that surfaces both observations together and lays out two paths forward (keep labels pure-display vs. add inline editing, with the concrete changes each would require) as an open question for design/ product review, rather than a decision made here. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Apollo Coded App preview deployments finished with failures.
|
Dependency License Review
License distribution
Excluded packages
|
📊 Coverage + size by packagePer-package coverage and bundle size on this PR. New-line coverage = of the source lines this PR adds or changes, the % hit by tests.
"Coverage" is each package's own |
Storybook visual diff⏭️ Skipped: the apollo-design preview deployment did not succeed, so no comparison ran. Logs Updated (PT): Aug 05, 2026, 07:52:19 AM |
There was a problem hiding this comment.
Pull request overview
Adds a new Apollo Wind Storybook “Patterns/DAP components” page to review DAP layouts against Apollo Wind primitives, and updates apollo-react Canvas edge-label rendering so labels paint above crossing edges (plus hover/selection layering + fallback token support).
Changes:
- Adds a large, collapsible DAP component-layout gallery page in
apollo-wind, defaulting to the Light theme. - Ports Canvas edge labels to
EdgeLabelRenderer, adds z-index layering rules for hovered edges and the edge-label renderer, and forwards label interactions to edge selection. - Introduces/updates stories and tests around edge-label behavior (new
EdgeLabelsstory page, updated unit tests).
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/apollo-wind/src/components/ui/dap-components.stories.tsx | New DAP patterns page with interactive layout examples and gap callouts (Light theme). |
| packages/apollo-react/src/canvas/styles/reactflow-reset.css | Adds hover-edge elevation and lifts the edge-label renderer above edges. |
| packages/apollo-react/src/canvas/components/StageNode/StageEdge.tsx | Adds core-token fallbacks for Stage edge-label colors/borders. |
| packages/apollo-react/src/canvas/components/Edges/shared/primitives/EdgePath.test.tsx | Updates expected stroke token string to include fallback var() values. |
| packages/apollo-react/src/canvas/components/Edges/shared/primitives/EdgeLabel.tsx | Reworks EdgeLabel to portal via EdgeLabelRenderer, adds tooltip, styling, and interaction hooks. |
| packages/apollo-react/src/canvas/components/Edges/shared/primitives/EdgeLabel.test.tsx | Updates EdgeLabel tests for the portal-based implementation and new interactions. |
| packages/apollo-react/src/canvas/components/Edges/shared/constants.ts | Adds core-token fallback var()s for edge color constants. |
| packages/apollo-react/src/canvas/components/Edges/SequenceEdge.stories.tsx | Removes the old embedded Edge Labels story and points to the new dedicated page. |
| packages/apollo-react/src/canvas/components/Edges/EdgeLabel.stories.tsx | New dedicated story page covering label orientation, diff states, crossing-edge stacking, overflow, execution, waypoint routing, and readonly mode. |
| packages/apollo-react/src/canvas/components/Edges/CanvasEdge.tsx | Tracks hovered-edge state for CSS elevation and adds label-click edge selection using the xyflow store. |
| packages/apollo-react/src/canvas/components/Edges/CanvasEdge.test.tsx | New unit tests validating label-click selection behavior (including readonly and non-selectable cases). |
Suppressed comments (1)
packages/apollo-wind/src/components/ui/dap-components.stories.tsx:1047
GmailIconreferences/brand/google-gmail.svg, but there is nobrand/asset directory in the repo, so this will render a broken image in Storybook. Also, the connection list contains real-looking personal / corporate email addresses. Consider using the repo’s existing Gmail SVG asset vianew URL(..., import.meta.url)and swap the sample data to placeholders.
const gmailConnections = [
{ id: 'merohit', label: 'merohitsharma6@gmail.com', group: 'Defined resources' },
{
id: 'workspace',
label: "rohit.sharma@uipath.com's workspace",
group: 'Platform resources',
workspace: true,
},
{ id: 'platform-gmail', label: 'merohitsharma6@gmail.com', group: 'Platform resources' },
];
function GmailIcon() {
return <img alt="" aria-hidden="true" className="size-5" src="/brand/google-gmail.svg" />;
}
| const users = [ | ||
| { | ||
| value: 'anurag-krishna', | ||
| label: 'Anurag Krishna - anurag.krishna@uipath.com - U058Z4EL2C', | ||
| }, | ||
| { | ||
| value: 'alexandru-statie', | ||
| label: 'Alexandru Statie - alexandru.statie@uipath.com - WLX92FTCL', | ||
| }, | ||
| { value: 'andra-buica', label: 'Andra Buica - andra.buica@uipath.com - WLXP4TP9N' }, | ||
| { value: 'andrei-bacanu', label: 'Andrei Băcanu - andrei.bacanu@uipath.com - WLZT84AQN' }, | ||
| { value: 'ashim-gupta', label: 'Ashim Gupta - ashim.gupta@uipath.com - WLZTATYS2' }, | ||
| { value: 'brandon-deer', label: 'Brandon Deer - brandon.deer@uipath.com - WHAP68X44' }, | ||
| { value: 'cosmin-sandu', label: 'Cosmin Sandu - cosmin.sandu@uipath.com - WLX9F6A8L' }, | ||
| ]; | ||
|
|
||
| function UserComboboxExample() { | ||
| const [user, setUser] = useState('anurag-krishna'); | ||
|
|
| <div | ||
| className={EDGE_LABEL_BASE_CLASS} | ||
| style={{ transform, borderColor }} | ||
| onClick={onClick} | ||
| onMouseEnter={onMouseEnter} | ||
| onMouseLeave={onMouseLeave} | ||
| > | ||
| {text} | ||
| </div> |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.
Suppressed comments (4)
packages/apollo-wind/src/components/ui/dap-components.stories.tsx:582
- The story hard-codes real-looking employee names, email addresses, and IDs in the
usersdataset. Since this repo is public/open-source, these should be replaced with clearly fictitious placeholder data (e.g., example.com) to avoid leaking or normalizing PII in docs/examples.
const users = [
{
value: 'anurag-krishna',
label: 'Anurag Krishna - anurag.krishna@uipath.com - U058Z4EL2C',
},
packages/apollo-wind/src/components/ui/dap-components.stories.tsx:1052
- The
gmailConnectionsexamples use real-looking Gmail and UiPath email addresses. Please swap these for non-identifying placeholder values (e.g., example.com) so Storybook examples don't ship with PII-like data.
const gmailConnections = [
{ id: 'merohit', label: 'merohitsharma6@gmail.com', group: 'Defined resources' },
{
id: 'workspace',
label: "rohit.sharma@uipath.com's workspace",
packages/apollo-react/src/canvas/components/Edges/shared/primitives/EdgeLabel.tsx:56
EdgeLabelattaches anonClickhandler to a<div>without adding keyboard semantics. Since labels are now clickable (for selection) in non-readonly mode, addrole,tabIndex, and an Enter/Space key handler (and a pointer cursor) so the interaction is accessible.
<div
className={EDGE_LABEL_BASE_CLASS}
style={{ transform, borderColor }}
onClick={onClick}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
{text}
</div>
packages/apollo-wind/src/components/ui/dap-components.stories.tsx:1646
- PR description says this page should default to the Apollo Light theme, but Storybook's global default is
future-dark(see apps/storybook/.storybook/preview.tsx initialGlobals). This story currently doesn't override the theme, so it will render dark by default unless the user switches it. Consider setting a per-story global theme override.
const meta = {
title: 'Patterns/DAP components',
component: DapComponentsPage,
tags: ['!autodocs'],
parameters: {
layout: 'fullscreen',
},
} satisfies Meta<typeof DapComponentsPage>;
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.
Suppressed comments (8)
packages/apollo-wind/src/components/ui/dap-components.stories.tsx:583
- The story uses real-looking employee names/emails (and what appear to be internal IDs) in the sample directory data. Since this is an OSS design system, it’s safer to use clearly fictional placeholders (e.g. example.com) to avoid accidental PII exposure.
const users = [
{
value: 'anurag-krishna',
label: 'Anurag Krishna - anurag.krishna@uipath.com - U058Z4EL2C',
},
packages/apollo-wind/src/components/ui/dap-components.stories.tsx:1048
- GmailIcon references
/brand/google-gmail.svg, but that asset doesn’t exist in the repo (so the icon will be broken in Storybook). Use an explicit bundled asset URL (e.g. via import.meta.url) or an existing Apollo icon export instead of a hard-coded absolute path.
function GmailIcon() {
return <img alt="" aria-hidden="true" className="size-5" src="/brand/google-gmail.svg" />;
}
packages/apollo-react/src/canvas/components/Edges/shared/primitives/EdgeLabel.tsx:56
- The edge label is clickable (used to select the owning edge) but is rendered as a plain , which is not keyboard-accessible and has no default button semantics. Use a so the label can be focused and activated via keyboard without extra ARIA plumbing.
<div
className={EDGE_LABEL_BASE_CLASS}
style={{ transform, borderColor }}
onClick={onClick}
onMouseEnter={onMouseEnter}
packages/apollo-react/src/canvas/components/Edges/shared/primitives/EdgeLabel.tsx:13
- After switching the label element to a , the onClick handler type should target HTMLButtonElement (not HTMLDivElement) so consumers get correct event typing.
borderColor?: string;
onClick?: MouseEventHandler<HTMLDivElement>;
onMouseEnter?: () => void;
onMouseLeave?: () => void;
packages/apollo-react/src/canvas/components/Edges/shared/primitives/EdgeLabel.test.tsx:16
- This test casts the rendered label to HTMLDivElement, but the component is interactive and should be rendered as a . Update the cast so the test aligns with the semantic element.
function renderLabel(props: Partial<React.ComponentProps<typeof EdgeLabel>> = {}) {
const { container } = render(<EdgeLabel x={150} y={50} text="Run" {...props} />);
return {
label: container.querySelector('.react-flow__edge-label') as HTMLDivElement,
};
packages/apollo-react/src/canvas/components/Edges/CanvasEdge.tsx:62
- onLabelClick is typed as MouseEvent, but the label should be a . Updating the generic keeps event typing correct and avoids downstream TS mismatches once EdgeLabel becomes a button.
const onLabelClick = useCallback(
(event: MouseEvent<HTMLDivElement>) => {
event.stopPropagation();
packages/apollo-wind/src/components/ui/dap-components.stories.tsx:1044
- The Gmail connection picker examples include a real-looking platform email/identity (and a specific Gmail address). Prefer obviously fake placeholder addresses (example.com) for Storybook sample data to avoid accidental leakage of personal/internal identifiers.
This issue also appears on line 1046 of the same file.
const gmailConnections = [
{ id: 'merohit', label: 'merohitsharma6@gmail.com', group: 'Defined resources' },
{
id: 'workspace',
label: "rohit.sharma@uipath.com's workspace",
group: 'Platform resources',
workspace: true,
},
{ id: 'platform-gmail', label: 'merohitsharma6@gmail.com', group: 'Platform resources' },
packages/apollo-wind/src/components/ui/dap-components.stories.tsx:1667
- Storybook nav titles under
Patterns/appear to use Title Case (e.g.Patterns/Code Editors). For consistency in the sidebar, consider capitalizing "Components" here as well.
const meta = {
title: 'Patterns/DAP components',
component: DapComponentsPage,
tags: ['!autodocs'],
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.
Suppressed comments (3)
packages/apollo-wind/src/components/ui/dap-components.stories.tsx:583
- This story hard-codes real-looking employee names, UiPath email addresses, and internal IDs in the Combobox items. Since this repo is open-source, please replace these with anonymized sample data (e.g., Example User + example.com).
const users = [
{
value: 'anurag-krishna',
label: 'Anurag Krishna - anurag.krishna@uipath.com - U058Z4EL2C',
},
packages/apollo-wind/src/components/ui/dap-components.stories.tsx:184
- The “Select all properties” checkbox renders as indeterminate even when nothing is selected.
indeterminateshould only be used for the partial-selection case (0 < selected < total).
<Checkbox
aria-label="Select all properties"
checked={selectedCount === rows.length ? true : 'indeterminate'}
onCheckedChange={toggleAllRows}
/>
packages/apollo-wind/src/components/ui/dap-components.stories.tsx:1054
- This section hard-codes personal emails / workspace strings and references an image at
/brand/google-gmail.svg, but the repo doesn’t contain that public asset path. Consider switching to anonymized sample addresses and load the Gmail SVG from apollo-core via Vite’s asset handling so the icon reliably renders in Storybook.
function GmailIcon() {
return <img alt="" aria-hidden="true" className="size-5" src="/brand/google-gmail.svg" />;
}
function GmailConnectionPickerExample() {
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
Suppressed comments (6)
packages/apollo-wind/src/components/ui/dap-components.stories.tsx:592
- The mock
usersdataset includes real-looking @uipath.com email addresses and identifiers. Since this repo is public/open-source, story fixtures should avoid shipping potentially identifying personal data. Replace with clearly fake example.com data.
const users = [
{
value: 'anurag-krishna',
label: 'Anurag Krishna - anurag.krishna@uipath.com - U058Z4EL2C',
},
{
value: 'alexandru-statie',
label: 'Alexandru Statie - alexandru.statie@uipath.com - WLX92FTCL',
},
{ value: 'andra-buica', label: 'Andra Buica - andra.buica@uipath.com - WLXP4TP9N' },
{ value: 'andrei-bacanu', label: 'Andrei Băcanu - andrei.bacanu@uipath.com - WLZT84AQN' },
{ value: 'ashim-gupta', label: 'Ashim Gupta - ashim.gupta@uipath.com - WLZTATYS2' },
{ value: 'brandon-deer', label: 'Brandon Deer - brandon.deer@uipath.com - WHAP68X44' },
{ value: 'cosmin-sandu', label: 'Cosmin Sandu - cosmin.sandu@uipath.com - WLX9F6A8L' },
];
packages/apollo-wind/src/components/ui/dap-components.stories.tsx:1047
GmailIconreferences/brand/google-gmail.svg, but there is nobrand/asset directory in the repo, so the icon will render as a broken image in Storybook. Prefer an inline icon (lucide) or a local imported asset that exists in this package.
function GmailIcon() {
return <img alt="" aria-hidden="true" className="size-5" src="/brand/google-gmail.svg" />;
}
packages/apollo-wind/src/components/ui/dap-components.stories.tsx:1052
- After sanitizing the
gmailConnectionsfixture values, the defaultselectedConnectionstate should be updated too. Otherwise the picker will display an initial value that doesn't exist in the list.
const [selectedConnection, setSelectedConnection] = useState('merohitsharma6@gmail.com');
packages/apollo-wind/src/components/ui/dap-components.stories.tsx:1646
- PR description says this story defaults to the Apollo Light theme, but Storybook’s initial global theme for apollo-wind is
future-dark(see packages/apollo-wind/.storybook/preview.tsx). This story’s meta doesn’t override globals, so it will still render in the dark theme by default.
const meta = {
title: 'Patterns/DAP components',
component: DapComponentsPage,
tags: ['!autodocs'],
parameters: {
layout: 'fullscreen',
},
} satisfies Meta<typeof DapComponentsPage>;
packages/apollo-react/src/canvas/components/Edges/shared/primitives/EdgeLabel.tsx:54
EdgeLabelis clickable in design mode, but it always setscursor-defaultvia classes, so there’s no visual affordance that it’s interactive. Setting cursor inline based on whetheronClickis provided keeps readonly canvases looking non-interactive while still giving a pointer cursor when the label selects an edge.
<div
className={EDGE_LABEL_BASE_CLASS}
style={{ transform, borderColor }}
onClick={onClick}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
packages/apollo-react/src/canvas/components/Edges/CanvasEdge.tsx:80
- The PR title/description focus on adding an apollo-wind Storybook patterns page, but this PR also includes substantial apollo-react Canvas edge-label behavior changes (portaling, hover z-index, selection behavior) plus new stories/tests. Consider either updating the PR description to include this scope or splitting into a separate PR so reviewers can evaluate each change set independently.
const store = useStoreApi();
const onLabelClick = useCallback(
(event: MouseEvent<HTMLDivElement>) => {
event.stopPropagation();
const {
addSelectedEdges,
edgeLookup,
elementsSelectable,
multiSelectionActive,
unselectNodesAndEdges,
} = store.getState();
const edge = edgeLookup.get(id);
if (!edge || !(edge.selectable ?? elementsSelectable)) return;
store.setState({ nodesSelectionActive: false });
if (edge.selected && multiSelectionActive) {
unselectNodesAndEdges({ nodes: [], edges: [edge] });
} else {
addSelectedEdges([id]);
}
},
[id, store]
);
| const gmailConnections = [ | ||
| { id: 'merohit', label: 'merohitsharma6@gmail.com', group: 'Defined resources' }, | ||
| { | ||
| id: 'workspace', | ||
| label: "rohit.sharma@uipath.com's workspace", | ||
| group: 'Platform resources', | ||
| workspace: true, | ||
| }, | ||
| { id: 'platform-gmail', label: 'merohitsharma6@gmail.com', group: 'Platform resources' }, | ||
| ]; |
Overview
Adds a dedicated DAP components Storybook page under Apollo Wind Patterns for reviewing DAP layouts against Apollo Wind primitives.
Work completed
Why
This page provides a single review surface for comparing existing DAP patterns with Apollo Wind capabilities, identifying reusable compositions, and documenting component-library gaps before standardization.
Validation
Feedback requested