Rewrite list and list-item without Tailwind
Plan step 36 (containment group, last of its four components): moves into resources/css/components/list.css (the container: display, the 2px segmented gap) and list-item.css (everything else — anatomy, states, the segmented item's own background/corner, and the row interaction pattern list.css used to carry). One commit for both: list-item.css keys heavily on list's own data-md-list="segmented" attribute and the two files are designed together. Kept, now on data-md-* hooks: selectable/selection listbox semantics (role="listbox"/"option", aria-selected, a trailing check as the second cue, C-03), a disabled item's link dropped entirely rather than left focusable (C-02), the segmented row's own state layer no longer racing its background through an unlayered escape hatch (C-08 doesn't recur — nothing here is unlayered), leading video/icon/avatar slots, three-line top alignment and 12px vertical padding (C-15), 16px leading/trailing gap (C-14), dividers inset 16px (C-16), the segmented list's surface fill (C-21) and its hover/focus/pressed/selected corner morph (C-22). The segmented icon size (20px) is now the `size` prop `<x-icon>` already takes from the parent's @aware(['segmented']), replacing the CSS override C-26's fix suggested. data-md-lines="1|2|3" replaces the old line-count classes; data-md-list-item-* hooks replace every other class list. Hooks renamed data-list -> data-md-list, data-list-item -> data-md-list-item, data-dividers -> data-md-dividers, data-selected -> data-md-selected, the generic data-list-row/-open row pattern's last consumer (list-item) moved, so list-rows.js drops the transitional dual-hook fallback the card commit added. table.css now @imports list-item.css, completing what its own comment already claimed (a row answers a pointer as a list row does) under the new per-component-import architecture. Imported from the Containment block of components.css; leaves tailwind.css, which now carries only dialog.css for this group. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
5cb11cd127
commit
9ff5a7a809
+14
-24
@@ -1,37 +1,27 @@
|
||||
/**
|
||||
* A row opens from anywhere on it.
|
||||
*
|
||||
* A row is `data-md-list-row` (or the older, unprefixed `data-list-row`, while a component that
|
||||
* has not yet moved off it still renders it) — an `<x-list-item>`, an `<x-card>`, a table row —
|
||||
* and exactly one control inside it is its opener, `data-md-list-open` (or `data-list-open`): the
|
||||
* title button that opens a sheet, or the link that goes to the item's page. A click anywhere else
|
||||
* on the row is handed to the opener, so the whole row is the target while the opener stays a real
|
||||
* control — the tab stop, the name a screen reader reads, and the owner of the `wire:click` or the
|
||||
* `href`. The row's other controls keep their own clicks. How a row looks while that happens is
|
||||
* resources/css/components/card.css and list.css.
|
||||
* A row is `data-md-list-row` — an `<x-list-item>`, an `<x-card>`, a table row — and exactly one
|
||||
* control inside it is its opener, `data-md-list-open`: the title button that opens a sheet, or
|
||||
* the link that goes to the item's page. A click anywhere else on the row is handed to the opener,
|
||||
* so the whole row is the target while the opener stays a real control — the tab stop, the name a
|
||||
* screen reader reads, and the owner of the `wire:click` or the `href`. The row's other controls
|
||||
* keep their own clicks. How a row looks while that happens is
|
||||
* resources/css/components/card.css and list-item.css.
|
||||
*
|
||||
* Not a stretched link (`::after { inset: 0 }`): Safari makes no containing block of a <tr>, so in
|
||||
* a table every overlay would cover the whole table; and not one <button> around the row, which
|
||||
* could hold no other buttons. The listeners sit on `document` and are added once.
|
||||
*
|
||||
* A row that is also `data-md-list-actionable` (or `data-list-actionable`) is M3's **directly
|
||||
* actionable card** (`<x-card actionable>`): the card is the one tab stop, so Enter and Space on
|
||||
* the card reach the opener, and the card's other actions follow it in the tab order with their
|
||||
* own keys. The opener itself carries `tabindex="-1"`, which the card's caller writes.
|
||||
* A row that is also `data-md-list-actionable` is M3's **directly actionable card** (`<x-card
|
||||
* actionable>`): the card is the one tab stop, so Enter and Space on the card reach the opener,
|
||||
* and the card's other actions follow it in the tab order with their own keys. The opener itself
|
||||
* carries `tabindex="-1"`, which the card's caller writes.
|
||||
*/
|
||||
|
||||
/** Anything that answers a click itself — the row's own controls, and the opener. */
|
||||
const CONTROLS = 'a, button, input, select, textarea, label, summary, [contenteditable]'
|
||||
|
||||
/** A row, under either its current or its older hook. */
|
||||
const ROW = '[data-md-list-row], [data-list-row]'
|
||||
|
||||
/** A row's opener, under either its current or its older hook. */
|
||||
const OPENER = '[data-md-list-open], [data-list-open]'
|
||||
|
||||
/** A directly actionable row, under either its current or its older hook. */
|
||||
const ACTIONABLE = '[data-md-list-actionable], [data-list-actionable]'
|
||||
|
||||
/** How far a pointer may travel between press and release and still be a click. */
|
||||
const DRAG_PX = 6
|
||||
|
||||
@@ -56,7 +46,7 @@ const openerFor = (event) => {
|
||||
return null
|
||||
}
|
||||
|
||||
const opener = event.target.closest(ROW)?.querySelector(OPENER)
|
||||
const opener = event.target.closest('[data-md-list-row]')?.querySelector('[data-md-list-open]')
|
||||
|
||||
if (!opener) {
|
||||
return null
|
||||
@@ -122,11 +112,11 @@ document.addEventListener('keydown', (event) => {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.defaultPrevented || !(event.target instanceof Element) || !event.target.matches(ACTIONABLE)) {
|
||||
if (event.defaultPrevented || !(event.target instanceof Element) || !event.target.matches('[data-md-list-actionable]')) {
|
||||
return
|
||||
}
|
||||
|
||||
const opener = event.target.querySelector(OPENER)
|
||||
const opener = event.target.querySelector('[data-md-list-open]')
|
||||
|
||||
if (!opener) {
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user