mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-23 20:25:56 +00:00
Fill the table's visible width with phone drawers
Inline table drawers below the lg breakpoint capped their sticky content at calc(100vw - 3.5rem), a guess at the page chrome. Pages with less chrome than that left an empty strip beside every drawer (27px at 390px on the Availability checks, Proxmox, Docker, Kubernetes and Machines tables), and a table wider than its shell at tablet widths got a drawer wider than the visible area. The table scroll shell is already a size container, so the content now caps at 100cqi: exactly the table's visible width at every width, measured live at 320, 390, 768 and 1000px. Desktop keeps the static uncapped layout.
This commit is contained in:
@@ -5791,7 +5791,15 @@ the surface-alt detail row shell locally. The content shell must clip
|
||||
horizontal paint below the large breakpoint without becoming a scroll
|
||||
container, reset the parent table's `whitespace-nowrap` inheritance, and allow
|
||||
its descendants to shrink, then restore visible overflow for the static
|
||||
desktop layout. Long operator-state copy must wrap inside the shared row border
|
||||
desktop layout. Below that breakpoint the default content shell is capped at
|
||||
the table scroll shell's content-box inline size (`max-w-[100cqi]`; the shell
|
||||
is a size container), never a viewport estimate of the page chrome, so a phone
|
||||
drawer does not leave an empty strip beside its content (the retired
|
||||
`100vw-3.5rem` cap left 27px at 390px) and is never wider than the table's
|
||||
visible area. Callers that pass their own `contentClass` own their width.
|
||||
Fixed-layout cells clip overflow, so the sticky offset is inert and horizontal
|
||||
scrolling still moves the drawer with its cell.
|
||||
Long operator-state copy must wrap inside the shared row border
|
||||
instead of painting beneath adjacent controls or disappearing at the clip edge.
|
||||
When focused detail content is removed, `InlineDetailTableRow` restores focus
|
||||
to its current `aria-controls` disclosure with `preventScroll`; live refresh,
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"version": 1,
|
||||
"base_sha": "7eb32f318100fef045d63414fd63304c62acfdef",
|
||||
"verified_at": "2026-10-07T16:55:00Z",
|
||||
"result": "passed",
|
||||
"changed_paths": [
|
||||
"frontend-modern/src/components/shared/InlineDetailTableRow.tsx"
|
||||
],
|
||||
"content_sha256": {
|
||||
"frontend-modern/src/components/shared/InlineDetailTableRow.tsx": "e5b27178cb3268132595943058849b3f619da22fcbd7916dfc301d4e852ef244"
|
||||
},
|
||||
"routes": [
|
||||
"/standalone/availability",
|
||||
"/standalone/machines",
|
||||
"/proxmox",
|
||||
"/docker",
|
||||
"/kubernetes"
|
||||
],
|
||||
"viewports": [
|
||||
{
|
||||
"width": 1440,
|
||||
"height": 900
|
||||
},
|
||||
{
|
||||
"width": 1000,
|
||||
"height": 800
|
||||
},
|
||||
{
|
||||
"width": 768,
|
||||
"height": 1024
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"height": 844
|
||||
},
|
||||
{
|
||||
"width": 320,
|
||||
"height": 700
|
||||
}
|
||||
],
|
||||
"states": [
|
||||
"Private stacks served by Vite from this tree (Playwright 1.56.1 headless Chromium): a non-mock stack with one HTTP availability check, then a mock estate (3 Proxmox nodes, 2 Docker hosts, 1 Kubernetes cluster, 2 generic hosts).",
|
||||
"Before (origin/main class max-w-[calc(100vw-3.5rem)]): at 390px every opened drawer (availability check, Proxmox node, Proxmox guest, Docker host, Docker container, Kubernetes node, Machines agent) was 334px inside a 361px visible table, leaving a 27px empty strip; at 768px a table forced wider than its shell got a 712px drawer in a 695px visible area.",
|
||||
"After (max-w-[100cqi]): drawer content equals the scroll shell's visible width at 320 (291px), 390 (361px), 768 (695px) and 1000 (916px) with no right gap, including the forced-wider table; 1440px keeps the static lg layout (max-width none, 1320px). The availability drawer's hostname now shows in full instead of truncating.",
|
||||
"Long unwrapped identity chips (e.g. proxmox-lxc-docker:Production West:pve1:107) were already clipped at the content edge before (Kubernetes 20px, Docker 8px and 83px) and are clipped less after (7px, 70px); chip wrapping is a separate follow-up.",
|
||||
"Sticky positioning is inert in both versions because .table-fixed td sets overflow hidden; not changed here. This is not an installed-build, physical-phone or release acceptance."
|
||||
],
|
||||
"interactions": [
|
||||
"Opened each drawer by its disclosure button (row tap at phone width where the button is hidden), measured the scroll shell, detail cell, content shell and every descendant's right edge, and captured screenshots at 390px before and after.",
|
||||
"Forced a 900px table inside its shell at 390px and 768px and scrolled it 300px sideways to compare drawer width against the visible area for both classes."
|
||||
]
|
||||
}
|
||||
@@ -5,9 +5,12 @@ import { TableCell, TableRow, type TableRowProps } from './Table';
|
||||
export const INLINE_DETAIL_TABLE_CELL_CLASS = 'p-0 border-b border-border bg-surface-alt';
|
||||
// overflow-x-clip keeps over-wide content from painting outside the row's
|
||||
// border below the lg breakpoint (issue #1622) without creating a scroll
|
||||
// container the way overflow-hidden would.
|
||||
// container the way overflow-hidden would. Below lg the sticky content is as
|
||||
// wide as the table's visible area: 100cqi resolves against the table scroll
|
||||
// shell (a size container), so a guess at the page chrome cannot leave an
|
||||
// empty strip beside the drawer or push it past the visible edge.
|
||||
export const INLINE_DETAIL_TABLE_CONTENT_CLASS =
|
||||
'sticky left-0 min-w-0 max-w-[calc(100vw-3.5rem)] whitespace-normal overflow-x-clip px-2 py-3 sm:px-4 sm:py-4 lg:static lg:max-w-none lg:overflow-x-visible';
|
||||
'sticky left-0 min-w-0 max-w-[100cqi] whitespace-normal overflow-x-clip px-2 py-3 sm:px-4 sm:py-4 lg:static lg:max-w-none lg:overflow-x-visible';
|
||||
|
||||
export interface InlineDetailTableRowProps extends TableRowProps {
|
||||
cellId?: string;
|
||||
|
||||
@@ -8761,7 +8761,10 @@ describe('shared primitive guardrails', () => {
|
||||
expect(summaryRowActionButtonSource).toContain('h-9 w-9');
|
||||
expect(searchFieldSource).toContain('min-h-11');
|
||||
expect(filterToolbarSource).toContain('min-h-11');
|
||||
expect(inlineDetailTableRowSource).toContain('max-w-[calc(100vw-3.5rem)]');
|
||||
// Phone and tablet drawers fill the table's visible width (the scroll
|
||||
// shell is a size container), not a viewport guess at the page chrome.
|
||||
expect(inlineDetailTableRowSource).toContain('max-w-[100cqi]');
|
||||
expect(inlineDetailTableRowSource).not.toContain('100vw-3.5rem');
|
||||
});
|
||||
|
||||
it('keeps shared settings panels dense without forking their desktop framing', () => {
|
||||
|
||||
@@ -39,7 +39,7 @@ describe('InlineDetailTableRow', () => {
|
||||
expect(detail.parentElement).toHaveClass('left-0');
|
||||
expect(detail.parentElement).toHaveClass('min-w-0');
|
||||
expect(detail.parentElement).toHaveClass('whitespace-normal');
|
||||
expect(detail.parentElement).toHaveClass('max-w-[calc(100vw-3.5rem)]');
|
||||
expect(detail.parentElement).toHaveClass('max-w-[100cqi]');
|
||||
expect(detail.parentElement).toHaveClass('lg:static');
|
||||
expect(detail.parentElement).toHaveClass('lg:max-w-none');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user