Add the supporting-pane canonical layout

Plan step 35: <x-supporting-pane>, following the reference's placement
table - below the focus pane below expanded, beside it from 840px at a
fixed 360px (412px from large) or the two-thirds split. Below expanded
compact="sheet" docks the supporting pane as a bottom sheet whose drag
handle opens it; always on the trailing side, so focus order matches the
panes on screen, and mirrored in RTL.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
Andreas Reinhold / reini
2026-09-14 14:51:22 +02:00
co-authored by Claude Opus 5
parent b5c5be1fd7
commit 9eb06323aa
7 changed files with 386 additions and 0 deletions
+131
View File
@@ -0,0 +1,131 @@
/*
* <x-supporting-pane>: M3's supporting-pane canonical layout — a focus pane, and a pane of what is
* only meaningful beside it.
*
* Its placement table, row by row (docs/reference/m3/foundations-supplement.md § Canonical layouts
* → Supporting pane):
*
* Below the focus pane flexible width compact or medium (below 840px)
* Leading or trailing side of the focus fixed, 360dp expanded (from 840px)
*
* From 840px the supporting pane is on the trailing side, 360px (`data-md-width="fixed"`, the
* default) and 412px from 1200px, where M3's fixed pane "defaults to 412dp" (§ Breakpoints, large
* and extra-large); or `data-md-width="split"`, the overview's split, the focus pane "about
* two-thirds" and the supporting pane the remaining third. The two are 24px apart, M3's spacer from
* medium on. Only the trailing side: on the leading side the pane would come first on screen and
* second in focus order, and M3 asks co-planar panes for a focus order that matches what is on
* screen (docs/reference/m3/foundations.md § Layout → Scaffold, Panes → Accessibility). Grid columns
* run in the inline direction, so a right-to-left document mirrors it, as M3 requires.
*
* Below 840px it is under the focus pane, 16px apart on a compact window and 24px from medium
* (`data-md-compact="below"`, the default), or a docked bottom sheet (`data-md-compact="sheet"`), the
* compact row's "a bottom sheet is a good way to keep focus on the primary pane": sticky to the
* bottom of the window, clear of the navigation bar (`--material-bottom-bar`), surface-container-low
* with extra-large top corners at elevation 1 and 640dp at most (M3's bottom sheet, SheetBottomTokens,
* androidx Compose Material 3), with a 32×4dp drag handle in on-surface-variant that is the button
* opening and closing it, 48dp to press (SheetDefaults.kt `DragHandleVerticalPadding = 22.dp`). Open,
* its content scrolls inside half the window, the height M3 caps a sheet's opening at. Sticky, not
* fixed, so it takes its own room at the end of the layout and never covers the last of the focus
* pane.
*
* The layout keeps M3's margin unless it is inside something that already does (pane.css). In
* `material.layout`; the sheet's state is Alpine in the view.
*/
@layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility;
@import './visibility.css';
@layer material.layout {
[data-md-supporting-pane] {
display: grid;
grid-template-columns: minmax(0, 1fr);
align-items: start;
gap: var(--md-sys-measurement-space200);
padding-inline: var(--md-layout-margin, var(--md-sys-measurement-space200));
@media (width >= 600px) {
gap: var(--md-sys-measurement-space300);
padding-inline: var(--md-layout-margin, var(--md-sys-measurement-space300));
}
@media (width >= 840px) {
grid-template-columns: minmax(0, 1fr) 360px;
}
@media (width >= 1200px) {
grid-template-columns: minmax(0, 1fr) 412px;
}
}
@media (width >= 840px) {
[data-md-supporting-pane][data-md-width='split'] {
grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
}
}
[data-md-supporting-pane] > * {
--md-layout-margin: 0px;
}
[data-md-supporting-pane-main],
[data-md-supporting-pane-supporting] {
min-inline-size: 0;
}
[data-md-supporting-pane-handle] {
display: none;
}
@media (width < 840px) {
[data-md-compact='sheet'] > [data-md-supporting-pane-supporting] {
position: sticky;
inset-block-end: max(var(--material-bottom-bar, 0px), var(--material-safe-bottom, env(safe-area-inset-bottom)));
z-index: 20;
inline-size: 100%;
max-inline-size: 640px;
margin-inline: auto;
border-start-start-radius: var(--md-sys-shape-corner-xl);
border-start-end-radius: var(--md-sys-shape-corner-xl);
background-color: var(--md-sys-color-surface-container-low);
color: var(--md-sys-color-on-surface);
box-shadow: var(--md-sys-elevation-1);
}
[data-md-compact='sheet'] [data-md-supporting-pane-handle] {
display: flex;
flex-direction: column;
align-items: center;
inline-size: 100%;
min-block-size: var(--md-sys-measurement-space600);
border-start-start-radius: inherit;
border-start-end-radius: inherit;
color: var(--md-sys-color-on-surface-variant);
cursor: pointer;
}
[data-md-supporting-pane-grip] {
inline-size: var(--md-sys-measurement-space400);
block-size: var(--md-sys-measurement-space50);
margin-block: 22px;
border-radius: var(--md-sys-shape-corner-full);
background-color: currentColor;
}
[data-md-supporting-pane-label] {
margin-block-start: calc(-1 * var(--md-sys-measurement-space100));
padding-block-end: var(--md-sys-measurement-space200);
color: var(--md-sys-color-on-surface);
}
[data-md-compact='sheet'] [data-md-supporting-pane-body] {
max-block-size: 50dvh;
overflow-y: auto;
overscroll-behavior: contain;
}
[data-md-compact='sheet'] > [data-md-supporting-pane-supporting]:not([data-md-open]) [data-md-supporting-pane-body] {
display: none;
}
}
}