feat(card): scaffold shared CardBase, template#6491
Conversation
|
|
|
||
| | # | Item | Status | | ||
| |---|---|---| | ||
| | **Q1** | `selectable`: exact dispatched event name (`swc-card-click` proposed) | Open — naming only; `tabindex` management is implemented | |
There was a problem hiding this comment.
Please leave feedback on the name of this event, keeping in mind that if/when we implement a CardView-like component to enable checkbox selection that it may pick up on this event to check the checkbox (React offers a combined click, and also keeping the card click distinct from the checkbox click).
📚 Branch Preview Links🔍 Gen1 Visual Regression Test ResultsWhen a visual regression test fails (or has previously failed while working on this branch), its results can be found in the following URLs:
Deployed to Azure Blob Storage: If the changes are expected, update the |
| - **Elevate nested interactive targets** — actions, in-content links, etc. need `position: relative` plus a higher stacking order than the stretched pseudo-element/click-catching surface, in `card-template.css`, so native hit-testing routes their own clicks to them rather than the card surface. This is a CSS-only concern, independent of the JS filtering below. | ||
| - **Filter clicks on nested interactive targets** — implemented in `CardBase`'s click handler via `event.composedPath()`, checking each node's `tabIndex` IDL property (not the `tabindex` attribute or a tag-name list): natively-interactive elements (`button`, `input`, `select`, `textarea`, `a[href]`) report `tabIndex >= 0` with no explicit attribute needed, `tabindex="-1"` and disabled controls correctly report as non-interactive, and — because `composedPath()` already traverses into other custom elements' shadow roots for composed events like `click` — an internal `<button>` inside e.g. `<swc-button>` slotted into `actions` is inspected directly, regardless of which shadow tree it belongs to. No tag-name enumeration, and no `stopPropagation()` wiring on wrapper elements in `renderCardTemplate()`, is needed. The `actions` slot is additionally excluded unconditionally (checking whether its `<slot>` element appears in the composed path) as defense in depth, since it's contractually for interactive content regardless of whether a given control correctly reflects focusability — mirroring 1st-gen's own belt-and-suspenders approach (a hard `stopPropagationOnHref` boundary for actions, plus a softer anchor-detection heuristic for everything else). | ||
|
|
||
| <details> |
There was a problem hiding this comment.
View the rich diff to see this Mermaid flowchart
Coverage Report for CI Build 29048505172Coverage remained the same at 96.257%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats💛 - Coveralls |
| TestCardWithMediaExtras, | ||
| } from './test-card-base.js'; | ||
|
|
||
| // No concrete card component (swc-card, swc-user-card, etc.) exists yet, so |
There was a problem hiding this comment.
Yes, this is a little strange, but in an effort to validate the proposed functionality I wanted to go ahead and run some tests, even though this PR is just the scaffold and split from from dev of the swc components. As noted, this will shift to the first available "real" component.
|
|
||
| Three concrete SWC components, all extending the already-built `CardBase`: | ||
|
|
||
| - **`swc-card`** — regular, collection, and gallery layouts, all driven by slot presence (no explicit layout attribute). Phase 1 handles basic `<img>` content and "cover" fit behavior directly. Once the 2nd-gen `Asset` component ships, documentation updates to recommend it in place of plain `<img>`; no dedicated `swc-asset-card` is planned. |
There was a problem hiding this comment.
Could you help me understand how would the "collection"/"gallery" layouts be triggered?
There was a problem hiding this comment.
I'll update the plan to be explicit but here's the TL;DR:
Collection - populating that slot will display it accordingly, otherwise it will be hidden
Gallery - populated preview slot and absence of all of title, description, action, default, and footer slots, therefore indicating the image/asset is the main content and will therefore fill the space.
| * family plan, A11y-3 / Q8. | ||
| */ | ||
| @property({ type: Boolean, reflect: true }) | ||
| public selectable = false; |
There was a problem hiding this comment.
Am I understanding correctly that this property will eventually become private/internal? Or is our plan to support selectable cards without CardView?
| * @todo No `role` is set when `selectable` is true — deferred rather than | ||
| * defaulting to `role="button"`, since the eventual `CardView` selection | ||
| * model may call for a different role (e.g. `option`/`gridcell`) that | ||
| * `role="button"` would be wrong to have committed to today. See the card | ||
| * family plan, A11y-3 / Q8. | ||
| */ | ||
| @property({ type: Boolean, reflect: true }) | ||
| public selectable = false; |
There was a problem hiding this comment.
We've been keeping to the "component has one role rule" this far along, so I like deferring this to see how we want to do this.
| | **Q2** | Gallery badge/avatar via `actions`-slot reuse | Carried over from the scaffold ticket, still TBD | | ||
| | **Q3** | `swc-product-card` "side" title position | Carried over from the scaffold ticket, still deferred | | ||
| | **Q4** | A `selected` property to complement `selectable` — independently useful (visual/state only), not necessarily tied to a future `CardView` | Open — non-blocking, exploratory; may still end up deferred to `CardView` | | ||
| | **Q5** | ARIA `role` for `selectable` (e.g. `button` vs. a future `CardView`-driven `option`/`gridcell`) | Open — deferred; not set today so an eventual role choice isn't foreclosed by committing to `role="button"` now | |
There was a problem hiding this comment.
I agree with deferring this until we have cardview.
Description
Plans and scaffolds the shared foundation for the
swc-cardfamily. See also the related Slack thread and Miro board for visuals and additional discussion.Important
Review the planning doc first —
CONTRIBUTOR-DOCS/03_project-planning/03_components/card/migration-plan.md, covering the React/1st-gen reference comparison, API decisions, styling approach, accessibility decisions, and 8 open items.Implemented features:
CardBase(2nd-gen/packages/core/components/card/) — behavior-only base class:size(viaSizedMixin),variant,density, and their dev-mode validation, plustitleAsLink/selectablefor whole-card-clickable behavior (click-proxy to a consumer-supplied link, keyboard activation, and filtering that excludes clicks on nested interactive targets — including targets inside another custom element's own shadow root).renderCardTemplate()(2nd-gen/packages/swc/components/card/card-template.ts) — the shared anatomy render function every concrete card will call from its ownrender(), mirroring the existingrenderPendingSpinner()shared-function pattern.card-template.css(swc/stylesheets/_lit-styles/) — placeholder for the shared structural rules; not yet populated.swc/components/card/test/, since no concrete card component exists yet. This is new territory for the codebase (no prior precedent for testing an abstract base via a throwaway concrete subclass) and is documented as such in the plan.No concrete card component (
swc-card,swc-user-card,swc-product-card) is implemented in this PR — that's explicitly out of scope, left to three follow-up tickets.Motivation and context
Three planned card components share layout and interactive behavior (sizing, variant, density, whole-card-clickable handling). Scaffolding that shared foundation first — base class, shared render function, shared styles placeholder — avoids duplicating it across three upcoming per-component tickets and lets them be built in parallel against a single, already-tested contract.
Related issue(s)
Manual review test cases
Review the plan for completeness and open items
CONTRIBUTOR-DOCS/03_project-planning/03_components/card/migration-plan.mdRun the CardBase test suite
2nd-gen/packages/swc, runyarn vitest --run --project storybook card-base