fix(ui-trajectory): own composer overlay geometry
This commit is contained in:
@@ -138,6 +138,23 @@ describe('web e2e: navigation & panes over a rich seeded session', () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-navigation-trajectory'))
|
||||
await page.getByRole('tab', { name: 'Trajectory' }).click()
|
||||
await page.waitForTimeout(100)
|
||||
const overlayLayout = await page.getByRole('table').evaluate((table) => {
|
||||
const host = table.closest('[data-conversation-scroll]')
|
||||
const seat = host?.querySelector('[data-composer-seat]') ?? null
|
||||
const pane = table.parentElement
|
||||
return {
|
||||
hostPosition: host === null ? null : getComputedStyle(host).position,
|
||||
paneOverflowX: pane === null ? null : getComputedStyle(pane).overflowX,
|
||||
paneScrollableWidth: pane === null ? null : pane.scrollWidth - pane.clientWidth,
|
||||
seatPosition: seat === null ? null : getComputedStyle(seat).position,
|
||||
}
|
||||
})
|
||||
expect(overlayLayout).toEqual({
|
||||
hostPosition: 'relative',
|
||||
paneOverflowX: 'hidden',
|
||||
paneScrollableWidth: 0,
|
||||
seatPosition: 'absolute',
|
||||
})
|
||||
expect({
|
||||
pageErrors: tripwire.pageErrors,
|
||||
slotErrors,
|
||||
@@ -153,6 +170,8 @@ describe('web e2e: navigation & panes over a rich seeded session', () => {
|
||||
await page.locator('tr[data-kind="tool"]').first().click()
|
||||
const details = page.getByRole('complementary', { name: 'Event details' })
|
||||
await expect.poll(() => details.count(), { timeout: 10_000 }).toBe(1)
|
||||
expect(await details.getByRole('tabpanel').evaluate(panel => getComputedStyle(panel).overflowX))
|
||||
.toBe('hidden')
|
||||
await page.evaluate(() => { document.body.setAttribute('data-ds-dark-theme', '') })
|
||||
const darkSummarySurfaces = await details.getByRole('heading', { name: 'Payload' }).evaluate(heading => ({
|
||||
heading: getComputedStyle(heading).backgroundColor,
|
||||
|
||||
@@ -208,6 +208,26 @@
|
||||
);
|
||||
}
|
||||
|
||||
/* Views may opt into a composer overlay while ConversationRoot retains
|
||||
ownership of the seat geometry and its active-phase precedence. */
|
||||
.scrollBody:has([data-conversation-composer-overlay]) {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.scrollBody:has([data-conversation-composer-overlay]) > .viewArea {
|
||||
flex: 1 1 0;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.scrollBody:has([data-conversation-composer-overlay]) > .composerSeat {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
/* Hero phase: the composer stack (hero chrome + workspace row + card) is
|
||||
flex-centered in the column; composer phase docks it at the bottom. Flex,
|
||||
NOT absolute+transform: a transform would make this box the containing
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
.tablePane {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding-bottom: var(--dsh-trajectory-bottom-clearance, 0px);
|
||||
container: trajectory-table / inline-size;
|
||||
}
|
||||
@@ -28,7 +29,7 @@
|
||||
);
|
||||
|
||||
width: 100%;
|
||||
min-width: 480px;
|
||||
min-width: 0;
|
||||
border-spacing: 0;
|
||||
table-layout: fixed;
|
||||
color: var(--dsw-alias-label-primary);
|
||||
@@ -905,7 +906,8 @@
|
||||
.detailBody {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding-bottom: var(--dsh-trajectory-bottom-clearance, 0px);
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
|
||||
@@ -459,7 +459,7 @@ export function TrajectoryView({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={css.root}>
|
||||
<div className={css.root} data-conversation-composer-overlay="">
|
||||
<TrajectoryToolbar
|
||||
actualDuration={actualDuration}
|
||||
onActualDurationChange={(nextActualDuration) => {
|
||||
|
||||
@@ -13,30 +13,6 @@
|
||||
background: var(--dsw-alias-bg-layer-1);
|
||||
}
|
||||
|
||||
/* Trajectory keeps the ledger and details panel inside the remaining
|
||||
* conversation height; only the internal panes scroll. The composer floats
|
||||
* over the ledger like chat's sticky seat — absolute, not sticky, because
|
||||
* this host does not scroll. */
|
||||
:global([data-conversation-scroll]):has(.root) {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:global([data-conversation-scroll]):has(.root) > :first-child {
|
||||
flex: 1 1 0;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* div qualifier outranks ConversationRoot's active-phase sticky rule (equal
|
||||
* specificity otherwise, and cross-module source order is bundler-defined). */
|
||||
:global([data-conversation-scroll]):has(.root) > :global(div[data-composer-seat]) {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.ledger {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
@@ -47,8 +23,6 @@
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
|
||||
/* Internal panes reserve the floating composer's live height plus a 16px
|
||||
* breathing gap so end rows and detail bodies can scroll clear of the
|
||||
* overlay. */
|
||||
/* ConversationRoot publishes the floating composer's live height. */
|
||||
--dsh-trajectory-bottom-clearance: calc(var(--dsh-composer-height, 152px) + 16px);
|
||||
}
|
||||
|
||||
@@ -288,6 +288,7 @@ describe('tab switching in ConversationRoot', () => {
|
||||
expect(screen.queryByRole('columnheader')).toBeNull()
|
||||
expect(screen.getByRole('toolbar', { name: 'Trajectory toolbar' })).toBeTruthy()
|
||||
expect(screen.getByRole('region', { name: 'Trajectory timeline' })).toBeTruthy()
|
||||
expect(view.container.querySelector('[data-conversation-composer-overlay]')).toBeTruthy()
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Collapse turns' }))
|
||||
expect(view.container.querySelector('[data-collapsed-summary="turn"]')).toBeTruthy()
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Expand turns' }))
|
||||
|
||||
Reference in New Issue
Block a user