Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions design-system/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ For shared icon rendering or geometry changes, use the focused package checks:
pnpm --dir design-system run build:ui && node --test design-system/packages/ui/tests/icon.test.mjs design-system/packages/ui/tests/icon-slots.test.mjs
```

For composer geometry and queue anatomy, disclosure and status presentation:

```bash
pnpm --dir design-system run build:ui && node --test design-system/packages/ui/tests/chat-composer.test.mjs
```

These package contracts do not establish native rendering or live remote behavior.

Do not use browser automation or mock screenshots as visual proof. Design Lab is the manual authoring surface; source, build, HTTP, and package checks do not establish final visual fidelity.

For SplitView geometry, drag cancellation, and cached resize bounds:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,38 @@
min-inline-size: 0;
inline-size: 100%;
flex-direction: column;
gap: var(--openbitfun-space-2);
padding-block: var(--openbitfun-space-3);
padding-inline: var(--openbitfun-space-4);
border-radius: var(--openbitfun-radius-lg);
gap: var(--openbitfun-space-1);
padding: var(--openbitfun-space-1);
border: var(--openbitfun-border-width-default) solid var(--openbitfun-color-border-subtle);
border-radius: var(--openbitfun-control-composer-surface-radius);
container: composer-queue / inline-size;
color: var(--openbitfun-color-content-primary);
background: var(--openbitfun-color-surface-subtle);
font-family:var(--openbitfun-type-body-md-font-family);
}

/* A composer with a context bar already tints the tray around its input.
The queue joins that tray instead of stacking a second translucent card. */
:global([data-openbitfun-component="chat-composer"][data-has-context="true"]) .root {
margin-block-end: calc(-1 * var(--openbitfun-space-2));
padding-block-end: var(--openbitfun-space-3);
border-block-end: 0;
border-end-start-radius: 0;
border-end-end-radius: 0;
background: transparent;
}

.header {
display: flex;
min-inline-size: 0;
min-block-size: var(--openbitfun-control-chat-composer-control-height);
align-items: center;
gap: var(--openbitfun-space-1);
padding-inline: var(--openbitfun-space-2);
color: var(--openbitfun-color-content-secondary);
font-size: var(--openbitfun-type-body-sm-font-size);
font-weight: var(--openbitfun-type-body-md-font-weight);
line-height: var(--openbitfun-type-body-md-line-height);
line-height: var(--openbitfun-type-body-sm-line-height);
}

.header > :where(svg, img) {
Expand All @@ -32,6 +46,12 @@
color: var(--openbitfun-color-content-muted);
}

.toggle[data-openbitfun-component="button"][data-size] {
min-inline-size: 0;
padding-inline: 0;
color: inherit;
}

.title {
display: inline-flex;
min-inline-size: 0;
Expand All @@ -53,18 +73,15 @@
.list {
display: flex;
min-inline-size: 0;
/* Four standard message rows plus the three gaps between them. */
/* Four comfortable message rows before the tray scrolls. */
max-block-size: calc(
var(--openbitfun-control-chat-composer-control-height) +
var(--openbitfun-control-chat-composer-control-height) +
var(--openbitfun-control-chat-composer-control-height) +
var(--openbitfun-control-chat-composer-control-height) +
var(--openbitfun-space-1) +
var(--openbitfun-space-1) +
var(--openbitfun-space-1)
var(--openbitfun-control-height-sm) +
var(--openbitfun-control-height-sm) +
var(--openbitfun-control-height-sm) +
var(--openbitfun-control-height-sm)
);
flex-direction: column;
gap: var(--openbitfun-space-1);
gap: 0;
margin: 0;
overflow-x: hidden;
overflow-y: auto;
Expand All @@ -73,86 +90,138 @@
list-style: none;
}

.list[hidden] {
display: none;
}

.item {
box-sizing: border-box;
display: grid;
display: flex;
flex: 0 0 auto;
min-inline-size: 0;
min-block-size: var(--openbitfun-control-chat-composer-control-height);
grid-template-columns: minmax(0, 1fr) auto auto;
min-block-size: var(--openbitfun-control-height-sm);
align-items: center;
gap: var(--openbitfun-space-2);
padding-inline: var(--openbitfun-space-2) var(--openbitfun-space-1);
border-radius: var(--openbitfun-radius-md);
color: var(--openbitfun-color-content-primary);
}

.item[data-openbitfun-state="sending"] {
opacity: var(--openbitfun-opacity-disabled);
/* The row, not a floating button cluster, is the unit being acted on. */
.item:focus-within {
background: var(--openbitfun-color-surface-subtle);
}

.leadingIcon {
display: inline-flex;
flex: 0 0 var(--openbitfun-space-5);
align-items: center;
justify-content: center;
color: var(--openbitfun-color-content-muted);
}

.content {
display: flex;
flex: 1 1 0;
min-inline-size: 0;
flex-direction: column;
gap: var(--openbitfun-space-1);
color: var(--openbitfun-color-content-secondary);
flex-flow: row wrap;
align-items: baseline;
gap: 0 var(--openbitfun-space-2);
color: var(--openbitfun-color-content-primary);
font-size: var(--openbitfun-type-body-md-font-size);
font-weight: var(--openbitfun-type-body-md-font-weight);
line-height: var(--openbitfun-type-body-md-line-height);
transition: color var(--openbitfun-motion-duration-fast) var(--openbitfun-motion-easing-standard);
line-height: var(--openbitfun-type-body-sm-line-height);
}

.item:hover .content,
.item:focus-within .content {
color: var(--openbitfun-color-content-primary);
/* Message text takes the line; status facts follow it and wrap below only
when the row is too narrow to hold both. */
:where(.content) > * {
flex: 1 1 8em;
min-inline-size: 0;
}

/* A truncated preview may be a tab stop so keyboard users can read its
full-text tooltip; it stays display-only. */
:where(.content) > :focus-visible {
border-radius: var(--openbitfun-radius-xs);
outline: var(--openbitfun-focus-width) solid var(--openbitfun-color-focus-ring);
outline-offset: var(--openbitfun-focus-offset);
}

/* Muted ink instead of row opacity keeps the status text legible. */
.item[data-openbitfun-state="sending"] .content {
color: var(--openbitfun-color-content-muted);
}

.status {
flex: 0 1 auto;
min-inline-size: 0;
color: var(--openbitfun-color-content-muted);
font-size: var(--openbitfun-type-meta-font-size);
line-height: var(--openbitfun-type-body-sm-line-height);
overflow-wrap: anywhere;
}

.status[data-openbitfun-tone="warning"] {
color: var(--openbitfun-color-status-warning-content);
}

.status[data-openbitfun-tone="danger"] {
color: var(--openbitfun-color-status-danger-content);
}

.attachmentBadge {
box-sizing: border-box;
display: inline-flex;
min-inline-size: var(--openbitfun-control-chat-composer-control-height);
block-size: var(--openbitfun-control-chat-composer-control-height);
flex: 0 0 auto;
align-items: center;
justify-content: center;
padding-inline: var(--openbitfun-space-2);
border-radius: var(--openbitfun-radius-pill);
color: var(--openbitfun-color-content-secondary);
background: var(--openbitfun-color-surface-raised);
font-size: var(--openbitfun-type-body-sm-font-size);
font-weight: var(--openbitfun-type-label-lg-font-weight);
gap: var(--openbitfun-space-1);
color: var(--openbitfun-color-content-muted);
font-size: var(--openbitfun-type-meta-font-size);
font-variant-numeric: tabular-nums;
line-height: var(--openbitfun-type-modifier-leading-none-line-height);
}

.actions {
display: inline-flex;
flex: 0 0 auto;
min-inline-size: 0;
align-items: center;
gap: var(--openbitfun-space-1);
transition: opacity var(--openbitfun-motion-duration-fast) var(--openbitfun-motion-easing-standard);
}

/* The tray stays quiet without making its controls disappear. */
.actions [data-openbitfun-component="button"][data-openbitfun-variant="text"] {
color: var(--openbitfun-color-content-secondary);
padding-inline: var(--openbitfun-space-2);
}

@media (hover: hover) and (pointer: fine) {
.actions {
pointer-events: none;
opacity: 0;
.item:hover {
background: var(--openbitfun-color-surface-subtle);
}
}

.item:hover .actions,
.item:focus-within .actions {
pointer-events: auto;
opacity: 1;
@container composer-queue (max-width: 22rem) {
.actions [data-openbitfun-component="button"] [data-openbitfun-part="label"] {
display: none;
}
}

@media (prefers-reduced-motion: reduce) {
.content,
.actions {
transition: none;
@media (pointer: coarse) {
.actions [data-openbitfun-component="button"] {
min-block-size: var(--openbitfun-control-height-sm);
}

.actions [data-openbitfun-component="icon-button"] {
inline-size: var(--openbitfun-control-height-sm);
block-size: var(--openbitfun-control-height-sm);
min-inline-size: var(--openbitfun-control-height-sm);
min-block-size: var(--openbitfun-control-height-sm);
}
}

@media (forced-colors: active) {
.root,
.attachmentBadge {
.root {
border: var(--openbitfun-border-width-default) solid CanvasText;
}
}
Expand Down
Loading
Loading