feat(evo-react): add evo-details component#640
Conversation
Migrates ebay-details from @ebay/ebayui-core-react to @evo-web/react using a compound sub-component API (EvoDetails, EvoDetailsSummary, EvoDetailsLeading, EvoDetailsLabel, EvoDetailsContent) backed by React context, avoiding React.Children. Also adds the missing `leading` attribute tag to evo-details in @evo-web/marko, and adds ADR 0005 documenting the child component composition pattern. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: aa694d7 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
Pull request overview
This PR introduces a new evo-details compound component to @evo-web/react (migrated from ebay-details) and updates @evo-web/marko’s evo-details tag to restore the missing leading attribute tag from the Marko 5 implementation.
Changes:
- Add
EvoDetails+ sub-components (Summary,Leading,Label,Content) to@evo-web/react, including stories and SSR/browser tests. - Add
leadingattribute tag support to@evo-web/marko’sevo-details, plus story/test/example updates. - Add ADR 0005 documenting the compound component composition approach, and update migration skill docs + changesets.
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/evo-react/src/index.ts | Exports new evo-details components/types from the package entry point |
| packages/evo-react/src/evo-details/types.ts | Defines evo-details public prop and type surface |
| packages/evo-react/src/evo-details/test/test.server.tsx | Adds SSR snapshot coverage for evo-details |
| packages/evo-react/src/evo-details/test/test.browser.tsx | Adds browser interaction coverage (toggle, classes, slots) |
| packages/evo-react/src/evo-details/test/snapshots/test.server.tsx.snap | Stores SSR snapshot expectations |
| packages/evo-react/src/evo-details/index.ts | Component folder barrel exports for evo-details |
| packages/evo-react/src/evo-details/details.tsx | Implements EvoDetails wrapper + context provider + Skin import |
| packages/evo-react/src/evo-details/details.stories.tsx | Adds Storybook docs/stories for evo-details |
| packages/evo-react/src/evo-details/details-summary.tsx | Implements summary sub-component (classes + chevron icon) |
| packages/evo-react/src/evo-details/details-leading.tsx | Implements leading slot sub-component |
| packages/evo-react/src/evo-details/details-label.tsx | Implements label slot sub-component |
| packages/evo-react/src/evo-details/details-content.tsx | Implements content wrapper sub-component with as support |
| packages/evo-react/src/evo-details/context.ts | Adds context + hook used by sub-components |
| packages/evo-react/src/evo-details/README.md | Adds minimal documentation pointing to Storybook |
| packages/evo-marko/src/tags/evo-details/test/test.server.ts | Extends server snapshot coverage to include leading variant |
| packages/evo-marko/src/tags/evo-details/index.marko | Adds leading attribute tag support and renders it in the summary |
| packages/evo-marko/src/tags/evo-details/examples/with-leading.marko | Adds Marko example demonstrating <@leading> usage |
| packages/evo-marko/src/tags/evo-details/details.stories.ts | Adds Storybook story + argTypes/docs for leading attribute tag |
| docs/adr/0005-evo-react-child-component-composition.md | Documents compound component pattern decision for evo-react |
| .claude/skills/evo-migrate-react/SKILL.md | Updates migration authoring guidance (context usage, icon/testing rules, etc.) |
| .claude/skills/evo-app-migrate-react/SKILL.md | Adds app-level migration guidance from ebay-details to compound evo-details API |
| .changeset/add-evo-details-react.md | Changeset for publishing the new evo-react component |
| .changeset/add-evo-details-leading.md | Changeset for publishing the Marko leading attr tag addition |
| <EvoDetailsSummary> | ||
| <EvoDetailsLeading> | ||
| <span>icon</span> | ||
| </EvoDetailsLeading> |
There was a problem hiding this comment.
This test uses a custom placeholder (<span>icon</span>) for the leading slot. The repo guidance explicitly says stories/tests should use an existing EvoIcon* component instead of placeholders (see .claude/skills/evo-migrate-react/SKILL.md around the “This applies to stories and tests as well” note). Using a real icon here will keep tests aligned with expected consumer usage and avoid drift in markup.
| <EvoDetailsLeading> | ||
| <span data-testid="icon">icon</span> | ||
| </EvoDetailsLeading> | ||
| <EvoDetailsLabel>Details</EvoDetailsLabel> |
There was a problem hiding this comment.
This test uses a custom placeholder (<span data-testid="icon">icon</span>) for the leading slot. Per .claude/skills/evo-migrate-react/SKILL.md (stories/tests should use an existing EvoIcon* component rather than placeholder icons), please switch this to a real Evo icon component and attach the test id to that element if needed.
| function Details(props: Partial<ComponentProps<typeof EvoDetails>> = {}) { | ||
| return ( | ||
| <EvoDetails {...props}> | ||
| <EvoDetailsSummary> | ||
| <EvoDetailsLabel>Show me the details!</EvoDetailsLabel> | ||
| </EvoDetailsSummary> | ||
| <EvoDetailsContent>Content</EvoDetailsContent> | ||
| </EvoDetails> | ||
| ); |
There was a problem hiding this comment.
These SSR snapshots render EvoDetails (which includes EvoIconChevronDown16) without an EvoIconProvider. On the server, EvoIcon logs a console.warn when rendered without the provider, so this test file will emit warnings during normal test runs. Consider wrapping the rendered tree in <EvoIconProvider> (or explicitly stubbing console.warn) to keep the test output clean and representative of recommended SSR usage.
…ve Alignment from public API Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
LuLaValva
left a comment
There was a problem hiding this comment.
Looks great! Just one change on the Marko side and some high-level thoughts on design decisions for React
|
|
||
| No prop changes. Global renames (Step 2) are sufficient. | ||
|
|
||
| ### `ebay-details` |
There was a problem hiding this comment.
This list is going to get really long once everything's in here... maybe we should have a separate markdown file for each component?
There was a problem hiding this comment.
Yeah probably we should start moving around.
| </EvoDetailsLeading> | ||
| <EvoDetailsLabel>How do I get started?</EvoDetailsLabel> | ||
| </EvoDetailsSummary> | ||
| <EvoDetailsContent>Content</EvoDetailsContent> |
There was a problem hiding this comment.
Are we planning on always having *Content tags? I'd hope that in many cases we can just keep the content inline
<EvoDetails size="small" onToggle={handler}>
<EvoDetailsSummary>
<EvoDetailsLeading>
<EvoIconLightbulb16 />
</EvoDetailsLeading>
How do I get started?
</EvoDetailsSummary>
Content
</EvoDetails>There was a problem hiding this comment.
Not always, it will depend on the component and how skin organizes it. Having the component allow the developer to add other properties like class names to the container, but it will depend for each component might be different.
| <@summary>Details</@summary> | ||
| <@leading><evo-icon-lightbulb-16/></@leading> |
There was a problem hiding this comment.
Can we nest <@leading> inside <@summary> instead? It'll require a <const/{ leading, ...rest }=summary/> on the consuming side but I think that's worth it
| <@summary>Details</@summary> | |
| <@leading><evo-icon-lightbulb-16/></@leading> | |
| <@summary> | |
| <@leading><evo-icon-lightbulb-16/></@leading> | |
| Details | |
| </@summary> |
There was a problem hiding this comment.
This will be wrong no? It will render the icon inside the summary text? But it is a sibling
There was a problem hiding this comment.
In the markup it is a child of <summary>, not a sibling...
There was a problem hiding this comment.
yes but @summary is actually the label not the details__summary https://github.com/eBay/evo-web/pull/640/changes#diff-341fd61a09aec307e916b291902025382ead9dd66813cb13883cc8004c6119deR32
There was a problem hiding this comment.
Hmm, I guess you're right but it does mess with my mental model a little bit. I've also never been a fan of @leading as a name, maybe that's part of it. How about leadingIcon?
| <EvoDetails size="small" onToggle={handler}> | ||
| <EvoDetailsSummary> | ||
| <EvoDetailsLeading> | ||
| <EvoIconLightbulb16 /> | ||
| </EvoDetailsLeading> | ||
| <EvoDetailsLabel>How do I get started?</EvoDetailsLabel> | ||
| </EvoDetailsSummary> | ||
| <EvoDetailsContent>Content</EvoDetailsContent> | ||
| </EvoDetails> |
There was a problem hiding this comment.
Thoughts on using an object instead of individual components, like Radix does? Might make more sense for grouping, but I'm not sure
<EvoDetails.Root size="small" onToggle={handler}>
<EvoDetails.Summary>
<EvoDetails.Leading>
<EvoIconLightbulb16 />
</EvoDetails.Leading>
<EvoDetails.Label>How do I get started?</EvoDetails.Label>
</EvoDetails.Summary>
<EvoDetails.Content>Content</EvoDetails.Content>
</EvoDetails.Root>There was a problem hiding this comment.
We can have both at some point like base-ui has.
| @@ -0,0 +1,13 @@ | |||
| import { createContext, useContext } from "react"; | |||
There was a problem hiding this comment.
If it was up to me I'd probably put all of the component parts in one file, you know better than I do though
There was a problem hiding this comment.
I think having in a separate file prevents the risk of circular dependencies since we have multiple components.
LuLaValva
left a comment
There was a problem hiding this comment.
Approving because evo-react is still in alpha, but some of the conversations here are maybe worth continuing as more components are migrated
Description
Migrates
ebay-detailsfrom@ebay/ebayui-core-reactto@evo-web/reactas a new compound component, and adds the missingleadingattribute tag toevo-detailsin@evo-web/marko.@evo-web/react— newevo-detailscomponentUses a compound sub-component API backed by React context instead of flat props or
React.Childrenscanning (see ADR 0005):Exported components:
EvoDetails,EvoDetailsSummary,EvoDetailsLeading,EvoDetailsLabel,EvoDetailsContent.@evo-web/marko—leadingattribute tag onevo-detailsAdds the
leadingattribute tag that was present in@ebay/ebayui-core(Marko 5) but was missed during the Marko 6 migration.Notes
React.Children/React.cloneElementwere ruled out.evo-migrate-reactandevo-app-migrate-reactskills updated with migration guidance for this component.<@summary>attribute tag pattern, which has no direct React equivalent.Screenshots
Checklist