You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CONTRIBUTOR-DOCS/03_project-planning/03_components/card/migration-plan.md
+33Lines changed: 33 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -207,6 +207,39 @@ Both modes need the same two supporting pieces, whichever (or both) are enabled:
207
207
-**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.
208
208
- **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).
(`handleSurfaceClick`/`handleSelectableKeydown` in `Card.base.ts`)
214
+
215
+
```mermaid
216
+
flowchart TD
217
+
A["Pointer click on card (bubbles to host)"] --> C
218
+
B["Enter / Space keydown (listener only attached when selectable)"] --> C
219
+
220
+
C{"titleAsLink or\nselectable set?"}
221
+
C -->|No| Z1["No-op"]
222
+
C -->|Yes| D{"Click path includes the actions slot?"}
223
+
224
+
D -->|Yes| Z2["No-op — actions slot is\nexcluded unconditionally"]
225
+
D -->|No| E{"Any node before the host has tabIndex >= 0?\n(checks across shadow-root boundaries too)"}
226
+
227
+
E -->|Yes| Z3["No-op — hit a nested interactive target"]
228
+
E -->|No| F{"titleAsLink set?"}
229
+
230
+
F -->|Yes| G["Find the title slot's linked anchor (direct or nested, requires href) and call .click()"]
231
+
F -->|No| H
232
+
G --> H{"selectable set?"}
233
+
234
+
H -->|Yes| I["Dispatch swc-card-click\n(bubbles, composed)"]
235
+
H -->|No| J["Done"]
236
+
I --> J
237
+
```
238
+
239
+
</details>
240
+
241
+
Both branches (`titleAsLink`'s proxy-click and `selectable`'s event dispatch) run independently once a click clears the filtering step — a card with both attributes set does both for the same click.
242
+
210
243
**Where this lives:** the `title-as-link`/`selectable` property declarations and the click-filtering/proxy logic are all behavior with no rendering — they belong in `CardBase`'s `SHARED API`/`IMPLEMENTATION` sections. Resolving the assigned title-link element needs **no** change to `renderCardTemplate()`: the existing `<slot name="title">` and `<slot name="actions">` markup is already directly queryable via `renderRoot.querySelector('slot[name="..."]')`, and `HTMLSlotElement.assignedElements()` returns the actual light-DOM element(s) assigned to it — that's the standard API for reading slotted content from script.
211
244
212
245
**Status:** implemented in `Card.base.ts` — `titleAsLink`/`selectable` properties, `tabindex` management, the click-vs-interactive-target filter, and the click-proxy/event dispatch. Only `selectable`'s dispatched event name remains open (see [Blockers Q1](#blockers-and-open-questions)).
0 commit comments