basalt-ui 1.12.0 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +21 -21
- package/CHANGELOG.md +24 -0
- package/README.md +38 -35
- package/agent/rules/basalt-agent.md +14 -0
- package/configs/oxlint-plugin.js +7 -3
- package/configs/oxlint-plugin.test.ts +34 -5
- package/configs/oxlint.json +4 -4
- package/dist/agent/adapter.d.ts +5 -1
- package/dist/agent/adapter.d.ts.map +1 -1
- package/dist/agent/adapter.js +22 -13
- package/dist/agent/ai-sdk-transport.d.ts.map +1 -1
- package/dist/agent/ai-sdk-transport.js +6 -2
- package/dist/agent/id.d.ts +67 -19
- package/dist/agent/id.d.ts.map +1 -1
- package/dist/agent/id.js +21 -7
- package/dist/agent/thread.d.ts +4 -0
- package/dist/agent/thread.d.ts.map +1 -1
- package/dist/agent/use-agent-stream.d.ts.map +1 -1
- package/dist/agent/use-agent-stream.js +2 -2
- package/dist/agent/use-agent-thread-runs.d.ts +24 -3
- package/dist/agent/use-agent-thread-runs.d.ts.map +1 -1
- package/dist/agent/use-agent-thread-runs.js +55 -15
- package/dist/agent-chat/index.d.ts +4 -0
- package/dist/agent-chat/index.d.ts.map +1 -1
- package/dist/agent-chat/index.js +2 -0
- package/dist/agent-chat/message-affordances.d.ts +59 -0
- package/dist/agent-chat/message-affordances.d.ts.map +1 -0
- package/dist/agent-chat/message-affordances.js +7 -0
- package/dist/agent-chat/relative-time.d.ts +27 -0
- package/dist/agent-chat/relative-time.d.ts.map +1 -0
- package/dist/agent-chat/relative-time.js +27 -0
- package/dist/agent-chat/relative-time.test.d.ts +2 -0
- package/dist/agent-chat/relative-time.test.d.ts.map +1 -0
- package/dist/agent-chat/thread-feed-row.d.ts +65 -0
- package/dist/agent-chat/thread-feed-row.d.ts.map +1 -0
- package/dist/agent-chat/thread-feed-row.js +156 -0
- package/dist/agent-chat/thread-feed-row.test.d.ts +2 -0
- package/dist/agent-chat/thread-feed-row.test.d.ts.map +1 -0
- package/dist/agent-chat/thread-feed.d.ts +34 -5
- package/dist/agent-chat/thread-feed.d.ts.map +1 -1
- package/dist/agent-chat/thread-feed.js +52 -19
- package/dist/agent-chat/thread-feed.test.d.ts +2 -0
- package/dist/agent-chat/thread-feed.test.d.ts.map +1 -0
- package/dist/agent-chat/thread-message.d.ts +183 -2
- package/dist/agent-chat/thread-message.d.ts.map +1 -1
- package/dist/agent-chat/thread-message.js +315 -34
- package/dist/agent-chat/thread-outcome-card.d.ts.map +1 -1
- package/dist/agent-chat/thread-outcome-card.js +1 -16
- package/dist/agent-chat/thread-workspace.d.ts +14 -2
- package/dist/agent-chat/thread-workspace.d.ts.map +1 -1
- package/dist/agent-chat/thread-workspace.js +29 -3
- package/dist/agent-chat/thread-workspace.test.d.ts +2 -0
- package/dist/agent-chat/thread-workspace.test.d.ts.map +1 -0
- package/dist/agent-chat/virtualize.d.ts +123 -0
- package/dist/agent-chat/virtualize.d.ts.map +1 -0
- package/dist/agent-chat/virtualize.js +9 -0
- package/dist/agent-chat/virtualize.type-guard.test.d.ts +2 -0
- package/dist/agent-chat/virtualize.type-guard.test.d.ts.map +1 -0
- package/dist/data/index.d.ts +5 -1
- package/dist/data/index.d.ts.map +1 -1
- package/dist/data/virtual-list.d.ts.map +1 -1
- package/dist/data/virtual.d.ts +2 -1
- package/dist/data/virtual.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/shell/app-sidebar.d.ts +19 -1
- package/dist/shell/app-sidebar.d.ts.map +1 -1
- package/dist/shell/app-sidebar.js +30 -26
- package/dist/shell/app-sidebar.module.css +11 -0
- package/dist/shell/app-sidebar.module.css.d.ts +1 -0
- package/dist/shell/app-sidebar.test.d.ts +2 -0
- package/dist/shell/app-sidebar.test.d.ts.map +1 -0
- package/dist/shell/index.d.ts +10 -1
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +2 -0
- package/dist/shell/index.test.d.ts +2 -0
- package/dist/shell/index.test.d.ts.map +1 -0
- package/dist/surfaces.d.ts +2 -2
- package/dist/surfaces.d.ts.map +1 -1
- package/dist/surfaces.js +3 -2
- package/dist/theme/shadow-surfaces.test.d.ts.map +1 -1
- package/llms.txt +6 -6
- package/package.json +2 -2
- package/src/agent/adapter.test.ts +237 -0
- package/src/agent/adapter.ts +72 -14
- package/src/agent/ai-sdk-transport.test.ts +64 -0
- package/src/agent/ai-sdk-transport.ts +8 -2
- package/src/agent/id.test.ts +95 -1
- package/src/agent/id.ts +98 -28
- package/src/agent/thread.ts +4 -0
- package/src/agent/use-agent-stream.test.tsx +22 -0
- package/src/agent/use-agent-stream.ts +6 -3
- package/src/agent/use-agent-thread-runs.test.tsx +326 -0
- package/src/agent/use-agent-thread-runs.ts +159 -23
- package/src/agent/use-agent-thread-runs.wedge.test.tsx +80 -0
- package/src/agent-chat/index.ts +12 -0
- package/src/agent-chat/message-affordances.ts +61 -0
- package/src/agent-chat/relative-time.test.ts +95 -0
- package/src/agent-chat/relative-time.ts +55 -0
- package/src/agent-chat/thread-feed-row.test.tsx +510 -0
- package/src/agent-chat/thread-feed-row.tsx +274 -0
- package/src/agent-chat/thread-feed.test.tsx +241 -0
- package/src/agent-chat/thread-feed.tsx +119 -18
- package/src/agent-chat/thread-message.test.tsx +937 -3
- package/src/agent-chat/thread-message.tsx +766 -38
- package/src/agent-chat/thread-outcome-card.tsx +1 -25
- package/src/agent-chat/thread-workspace.test.tsx +169 -0
- package/src/agent-chat/thread-workspace.tsx +69 -5
- package/src/agent-chat/virtualize.ts +132 -0
- package/src/agent-chat/virtualize.type-guard.test.ts +49 -0
- package/src/data/index.ts +5 -1
- package/src/data/virtual-list.tsx +2 -1
- package/src/data/virtual.ts +2 -1
- package/src/index.ts +5 -0
- package/src/shell/app-sidebar.module.css +11 -0
- package/src/shell/app-sidebar.module.css.d.ts +1 -0
- package/src/shell/app-sidebar.test.tsx +98 -0
- package/src/shell/app-sidebar.tsx +22 -0
- package/src/shell/index.test.tsx +35 -0
- package/src/shell/index.tsx +11 -0
- package/src/surfaces.ts +2 -1
- package/src/theme/shadow-surfaces.test.ts +9 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `navExtra` — the seam that lets a consumer put arbitrary content (a tree, a filter panel,
|
|
3
|
+
* a project list) inside the sidebar's nav scroll region instead of rendering a second column
|
|
4
|
+
* beside the shell. Four invariants:
|
|
5
|
+
*
|
|
6
|
+
* 1. It renders INSIDE the nav `ScrollArea`'s content (Mantine's own `.mantine-ScrollArea-content`
|
|
7
|
+
* class, stable across runs — CSS-module class hashes are not available under `bun test`, see
|
|
8
|
+
* `stat-card.test.tsx`/`use-basalt-spacing.test.tsx` for the same constraint elsewhere), as the
|
|
9
|
+
* LAST child, so a long tree scrolls with the nav instead of fighting it for height.
|
|
10
|
+
* 2. It STAYS MOUNTED when `collapsed` — `collapsed` is one value shared by the desktop rail AND
|
|
11
|
+
* the mobile drawer (`AppShell.Navbar`'s `collapsed: { mobile: !mobileOpened }` never touches
|
|
12
|
+
* the desktop side), and the rail-vs-drawer split lives entirely in a `min-width: sm` CSS media
|
|
13
|
+
* query, never in JS. A JS gate on `collapsed` would silently drop `navExtra` from the mobile
|
|
14
|
+
* drawer too, which opens at full width regardless of the persisted rail state. jsdom does not
|
|
15
|
+
* evaluate the media query, so this asserts presence in the DOM, not computed visibility — the
|
|
16
|
+
* CSS half (`.root[data-collapsed] .navExtra { display: none }`) is exercised by the guard rules
|
|
17
|
+
* it shares with `.childList`/`.sectionBand`, not by this test.
|
|
18
|
+
* 3. `sections={[]}` plus only `navExtra` renders cleanly: the nav Stack holds exactly the
|
|
19
|
+
* extra content, no orphan section wrapper.
|
|
20
|
+
* 4. Omitting the prop reproduces today's DOM exactly — the nav Stack's child count matches
|
|
21
|
+
* `sections.length`, with no stray wrapper appended for the (absent) slot. This is the
|
|
22
|
+
* regression guard for every existing consumer.
|
|
23
|
+
*/
|
|
24
|
+
import { MantineProvider } from '@mantine/core'
|
|
25
|
+
import { render, screen } from '@testing-library/react'
|
|
26
|
+
import { describe, expect, test } from 'bun:test'
|
|
27
|
+
import type { ReactNode } from 'react'
|
|
28
|
+
import { AppSidebar } from './app-sidebar'
|
|
29
|
+
import type { AppSidebarProps } from './app-sidebar'
|
|
30
|
+
|
|
31
|
+
const BRAND = { name: 'Argo' }
|
|
32
|
+
const ONE_SECTION: AppSidebarProps['sections'] = [
|
|
33
|
+
{ label: 'Main', items: [{ key: 'home', label: 'Home', icon: null }] },
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
function renderSidebar(props: Partial<AppSidebarProps> & { navExtra?: ReactNode }) {
|
|
37
|
+
return render(
|
|
38
|
+
<MantineProvider>
|
|
39
|
+
<AppSidebar
|
|
40
|
+
brand={BRAND}
|
|
41
|
+
sections={ONE_SECTION}
|
|
42
|
+
collapsed={false}
|
|
43
|
+
onToggleCollapse={() => {}}
|
|
44
|
+
onClose={() => {}}
|
|
45
|
+
{...props}
|
|
46
|
+
/>
|
|
47
|
+
</MantineProvider>,
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** The nav `ScrollArea`'s content Stack — the direct parent of `sections` and `navExtra`. */
|
|
52
|
+
function navStack(container: HTMLElement): Element {
|
|
53
|
+
const stack = container.querySelector('.mantine-ScrollArea-content > .mantine-Stack-root')
|
|
54
|
+
if (!stack) throw new Error('expected the nav ScrollArea content Stack to render')
|
|
55
|
+
return stack
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
describe('navExtra', () => {
|
|
59
|
+
test('renders inside the nav scroll region, as the last child, when expanded', () => {
|
|
60
|
+
const { container } = renderSidebar({
|
|
61
|
+
navExtra: <div data-testid="nav-extra">Extra</div>,
|
|
62
|
+
})
|
|
63
|
+
const extra = screen.getByTestId('nav-extra')
|
|
64
|
+
const stack = navStack(container)
|
|
65
|
+
expect(stack.contains(extra)).toBe(true)
|
|
66
|
+
expect(stack.lastElementChild?.contains(extra)).toBe(true)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
test('stays mounted in the DOM when collapsed — hiding it is CSS-only, not a JS gate', () => {
|
|
70
|
+
const { container } = renderSidebar({
|
|
71
|
+
collapsed: true,
|
|
72
|
+
navExtra: <div data-testid="nav-extra">Extra</div>,
|
|
73
|
+
})
|
|
74
|
+
const extra = screen.getByTestId('nav-extra')
|
|
75
|
+
const stack = navStack(container)
|
|
76
|
+
// Presence, not visibility — jsdom never evaluates the `min-width: sm` media query that hides
|
|
77
|
+
// this in the rail. A regression here (reintroducing `!collapsed &&` in app-sidebar.tsx) would
|
|
78
|
+
// fail this assertion instead of only breaking silently in a real mobile-drawer browser.
|
|
79
|
+
expect(stack.contains(extra)).toBe(true)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
test('sections={[]} plus only navExtra renders cleanly — no orphan section wrapper', () => {
|
|
83
|
+
const { container } = renderSidebar({
|
|
84
|
+
sections: [],
|
|
85
|
+
navExtra: <div data-testid="nav-extra">Extra</div>,
|
|
86
|
+
})
|
|
87
|
+
const stack = navStack(container)
|
|
88
|
+
expect(screen.getByTestId('nav-extra')).toBeTruthy()
|
|
89
|
+
expect(stack.children.length).toBe(1)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
test("omitting the prop reproduces today's DOM — no stray wrapper for the unused slot", () => {
|
|
93
|
+
const { container } = renderSidebar({})
|
|
94
|
+
expect(screen.queryByTestId('nav-extra')).toBeNull()
|
|
95
|
+
const stack = navStack(container)
|
|
96
|
+
expect(stack.children.length).toBe(ONE_SECTION.length)
|
|
97
|
+
})
|
|
98
|
+
})
|
|
@@ -92,6 +92,24 @@ export type AppSidebarProps = {
|
|
|
92
92
|
* fixed, non-scrolling row. Pair with basalt-ui/commands' openSpotlight.
|
|
93
93
|
*/
|
|
94
94
|
search?: SidebarSearchConfig
|
|
95
|
+
/**
|
|
96
|
+
* Arbitrary content appended after `sections` inside the nav `ScrollArea` — a tree, a filter
|
|
97
|
+
* panel, a project list, anything a set of `SidebarItem`s can't express. Renders as the last
|
|
98
|
+
* child of the scrolling nav column, so a long list scrolls with the rest of the nav instead of
|
|
99
|
+
* fighting it for height. Pass `sections={[]}` to use this slot exclusively; the section-spacing
|
|
100
|
+
* rule only fires between adjacent children, so an empty `sections` produces no orphan divider or
|
|
101
|
+
* dead padding above it.
|
|
102
|
+
*
|
|
103
|
+
* Hidden on the collapsed desktop rail; still present in the mobile drawer, which opens at full
|
|
104
|
+
* width. The rail is ~56px of icon buttons with no sensible representation for arbitrary
|
|
105
|
+
* consumer content, so the CSS media query that drives the rail hides this slot the same way it
|
|
106
|
+
* hides `.childList` — never a JS check on `collapsed`, since that one value is shared by the
|
|
107
|
+
* rail AND the drawer (only the media query tells them apart). `SidebarSearch` gets to adapt
|
|
108
|
+
* itself to the rail (it takes `collapsed` and renders its own icon-only form) because the shell
|
|
109
|
+
* owns that control; it cannot adapt content it knows nothing about, so this slot hides instead
|
|
110
|
+
* of squashing it.
|
|
111
|
+
*/
|
|
112
|
+
navExtra?: ReactNode
|
|
95
113
|
}
|
|
96
114
|
|
|
97
115
|
/** Inline collapse/expand chevrons — keeps the shell icon-dependency-free. */
|
|
@@ -457,6 +475,7 @@ export function AppSidebar({
|
|
|
457
475
|
footerExtra,
|
|
458
476
|
account,
|
|
459
477
|
search,
|
|
478
|
+
navExtra,
|
|
460
479
|
}: AppSidebarProps) {
|
|
461
480
|
// Density-tracking Menu dropdown width (`SPACE_STEP.sidebarSettingsMenuWidth`) — read the ACTIVE
|
|
462
481
|
// resolved level, not the frozen level-0 constant (see that constant's own doc in
|
|
@@ -622,6 +641,9 @@ export function AppSidebar({
|
|
|
622
641
|
</div>
|
|
623
642
|
)
|
|
624
643
|
})}
|
|
644
|
+
{navExtra !== undefined && navExtra !== null && (
|
|
645
|
+
<div className={classes.navExtra}>{navExtra}</div>
|
|
646
|
+
)}
|
|
625
647
|
</Stack>
|
|
626
648
|
</ScrollArea>
|
|
627
649
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `BasaltShell`'s `sidebarNavExtra` forwarding path — `AppSidebar` (exercised directly in
|
|
3
|
+
* `app-sidebar.test.tsx`) is not the only place this prop can break. `BasaltShell` destructures
|
|
4
|
+
* `sidebarNavExtra` and hands it to `AppSidebar` as `navExtra`; a typo'd destructure key, a dropped
|
|
5
|
+
* prop, or a `sidebarFooterExtra`/`sidebarNavExtra` mix-up in that hand-off would ship silently
|
|
6
|
+
* without a test that renders `BasaltShell` itself.
|
|
7
|
+
*/
|
|
8
|
+
import { MantineProvider } from '@mantine/core'
|
|
9
|
+
import { render, screen } from '@testing-library/react'
|
|
10
|
+
import { describe, expect, test } from 'bun:test'
|
|
11
|
+
import { BasaltShell } from './index'
|
|
12
|
+
import type { SidebarSection } from './index'
|
|
13
|
+
|
|
14
|
+
const BRAND = { name: 'Argo' }
|
|
15
|
+
const ONE_SECTION: SidebarSection[] = [
|
|
16
|
+
{ label: 'Main', items: [{ key: 'home', label: 'Home', icon: null }] },
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
describe('BasaltShell sidebarNavExtra', () => {
|
|
20
|
+
test("reaches AppSidebar's nav scroll region through the BasaltShell -> AppSidebar hand-off", () => {
|
|
21
|
+
const { container } = render(
|
|
22
|
+
<MantineProvider>
|
|
23
|
+
<BasaltShell
|
|
24
|
+
brand={BRAND}
|
|
25
|
+
sections={ONE_SECTION}
|
|
26
|
+
sidebarNavExtra={<div data-testid="nav-extra">Extra</div>}
|
|
27
|
+
/>
|
|
28
|
+
</MantineProvider>,
|
|
29
|
+
)
|
|
30
|
+
const extra = screen.getByTestId('nav-extra')
|
|
31
|
+
const stack = container.querySelector('.mantine-ScrollArea-content > .mantine-Stack-root')
|
|
32
|
+
expect(stack).not.toBeNull()
|
|
33
|
+
expect(stack?.contains(extra)).toBe(true)
|
|
34
|
+
})
|
|
35
|
+
})
|
package/src/shell/index.tsx
CHANGED
|
@@ -115,6 +115,15 @@ export type BasaltShellProps = {
|
|
|
115
115
|
globalActions?: ReactNode
|
|
116
116
|
/** Extra content appended to the sidebar footer, beside the settings menu (mobile close, etc.). */
|
|
117
117
|
sidebarFooterExtra?: ReactNode
|
|
118
|
+
/**
|
|
119
|
+
* Arbitrary content appended after `sections` inside the sidebar's nav scroll region (a tree, a
|
|
120
|
+
* filter panel, a project list, …). Hidden on the collapsed desktop rail; still present in the
|
|
121
|
+
* mobile drawer, which opens at full width — see `AppSidebarProps.navExtra`'s JSDoc for why.
|
|
122
|
+
* `AppSidebar` renders once and serves both the desktop rail and the mobile drawer (collapse
|
|
123
|
+
* styling is gated behind a `min-width: sm` media query, not a second render), so this slot
|
|
124
|
+
* reaches both.
|
|
125
|
+
*/
|
|
126
|
+
sidebarNavExtra?: ReactNode
|
|
118
127
|
/** Entries appended to the sidebar settings menu. */
|
|
119
128
|
settingsMenuItems?: SettingsMenuItem[]
|
|
120
129
|
/**
|
|
@@ -262,6 +271,7 @@ export function BasaltShell({
|
|
|
262
271
|
renderNavLink,
|
|
263
272
|
globalActions,
|
|
264
273
|
sidebarFooterExtra,
|
|
274
|
+
sidebarNavExtra,
|
|
265
275
|
settingsMenuItems,
|
|
266
276
|
storageKey = 'basalt-sidebar-collapsed',
|
|
267
277
|
collapsed: collapsedProp,
|
|
@@ -332,6 +342,7 @@ export function BasaltShell({
|
|
|
332
342
|
onToggleCollapse={toggleCollapse}
|
|
333
343
|
onClose={closeMobile}
|
|
334
344
|
footerExtra={sidebarFooterExtra}
|
|
345
|
+
navExtra={sidebarNavExtra}
|
|
335
346
|
{...(renderNavLink !== undefined && { renderNavLink })}
|
|
336
347
|
{...(settingsMenuItems !== undefined && { settingsMenuItems })}
|
|
337
348
|
{...(account !== undefined && { account })}
|
package/src/surfaces.ts
CHANGED
|
@@ -385,7 +385,7 @@ export const SURFACES = {
|
|
|
385
385
|
skill: ['basalt-app'],
|
|
386
386
|
guardKinds: [],
|
|
387
387
|
description:
|
|
388
|
-
'Mantine-styled thread-chat components over basalt-ui/agent: ThreadWorkspace, ThreadFeed, ThreadOutcomeCard, ThreadDetailPanel, Composer, ThreadTranscript (open part-renderer registry via its renderers/fallbackRenderer props), threadPartRenderers, ToolChip (Mantine-coupled). motion is required, not optional — ThreadFeed/ThreadDetailPanel import motion/react eagerly, so this subpath fails to resolve without it installed even though peerDependenciesMeta marks it optional (npm has no per-subpath optionality). remend is genuinely optional here — ThreadTranscript reaches it only through the lazy dynamic import() inside content/markdown.tsx.',
|
|
388
|
+
'Mantine-styled thread-chat components over basalt-ui/agent: ThreadWorkspace, ThreadFeed (variant/renderRow), ThreadFeedRow (inline-expanding Slack row, lazily mounted + kept mounted), ThreadOutcomeCard, ThreadDetailPanel, Composer, ThreadTranscript (open part-renderer registry via its renderers/fallbackRenderer props, per-message MessageAffordances, groupConsecutive, and an optional virtualize/height windowing mode whose VirtualizeOptions carry overscan/estimateSize/initialScroll — a virtualized transcript opens scrolled to the newest message unless initialScroll is "start"), threadPartRenderers, ToolChip (Mantine-coupled). motion is required, not optional — ThreadFeed/ThreadDetailPanel import motion/react eagerly, so this subpath fails to resolve without it installed even though peerDependenciesMeta marks it optional (npm has no per-subpath optionality). remend is genuinely optional here — ThreadTranscript reaches it only through the lazy dynamic import() inside content/markdown.tsx, and @tanstack/react-virtual the same way through the lazy import() behind ThreadTranscript virtualize (absent peer degrades to an unwindowed, height-bound pane).',
|
|
389
389
|
optionalPeers: [
|
|
390
390
|
'ai',
|
|
391
391
|
'motion',
|
|
@@ -397,6 +397,7 @@ export const SURFACES = {
|
|
|
397
397
|
'@shikijs/langs',
|
|
398
398
|
'@shikijs/themes',
|
|
399
399
|
'beautiful-mermaid',
|
|
400
|
+
'@tanstack/react-virtual',
|
|
400
401
|
],
|
|
401
402
|
forbiddenImports: [],
|
|
402
403
|
},
|
|
@@ -386,6 +386,15 @@ export const SHADOW_SURFACES: readonly ShadowSurfaceEntry[] = [
|
|
|
386
386
|
site: 'default',
|
|
387
387
|
roundedBy: 'borderRadius: VX.radiusCard (co-declared in the same inline style object).',
|
|
388
388
|
},
|
|
389
|
+
{
|
|
390
|
+
file: 'agent-chat/thread-feed-row.tsx',
|
|
391
|
+
site: 'default',
|
|
392
|
+
roundedBy:
|
|
393
|
+
'borderRadius: VX.radiusCard (co-declared in the same inline style object as the shadow). ' +
|
|
394
|
+
'This box also carries overflow: hidden, which is what lets the header button and the ' +
|
|
395
|
+
'expanded body square off against the row’s rounded corners; an element’s own overflow ' +
|
|
396
|
+
'never clips its own ring, so the shadow is unaffected.',
|
|
397
|
+
},
|
|
389
398
|
// ── agent ────────────────────────────────────────────────────────────────────────────────────
|
|
390
399
|
{
|
|
391
400
|
file: 'agent/stick-to-bottom.tsx',
|