Skip to content

Commit 8cac067

Browse files
fix: workspace toolbar and header responsiveness (#955)
1 parent ef69fe1 commit 8cac067

File tree

14 files changed

+587
-94
lines changed

14 files changed

+587
-94
lines changed

demo/src/react/WorkspaceWriteableElementExample.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,12 @@ function WorkspaceWriteableElementExample({
136136

137137
return (
138138
<WorkspaceShell>
139-
<Toolbar slot="toolbar" actions={toolbarActions} overflow>
140-
<div slot="title">Optimizing excess inventory</div>
139+
<Toolbar
140+
slot="toolbar"
141+
actions={toolbarActions}
142+
overflow
143+
titleText="Optimizing excess inventory"
144+
>
141145
<div slot="decorator">
142146
<AILabel size="2xs" autoAlign>
143147
<AILabelContent>

demo/src/web-components/workspace-writeable-element-example.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,8 @@ class WorkspaceWriteableElementExample extends LitElement {
138138
slot="toolbar"
139139
overflow
140140
.actions=${this.toolbarActions}
141+
titleText="Optimizing excess inventory"
141142
>
142-
<div slot="title">Optimizing excess inventory</div>
143143
<cds-ai-label autoalign="" slot="decorator" size="2xs">
144144
<div slot="body-text">
145145
<p class="secondary">

packages/ai-chat-components/src/components/toolbar/src/toolbar.scss

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ $block-class: #{$prefix}-toolbar;
2525

2626
.#{$block-class} {
2727
display: flex;
28-
align-items: flex-start;
2928
block-size: 100%;
3029
inline-size: 100%;
3130
max-inline-size: 100%;
@@ -65,6 +64,16 @@ $block-class: #{$prefix}-toolbar;
6564
margin-block: auto;
6665
}
6766

67+
.#{$block-class}__left,
68+
.#{$block-class}__right {
69+
display: flex;
70+
flex: 1;
71+
}
72+
73+
.#{$block-class}__right {
74+
justify-content: end;
75+
}
76+
6877
::slotted([slot="decorator"]) {
6978
display: flex;
7079
align-items: center;

packages/ai-chat-components/src/components/toolbar/src/toolbar.ts

Lines changed: 71 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
import { LitElement, html, nothing } from "lit";
1111
import { property, state, query } from "lit/decorators.js";
12-
import { classMap } from "lit/directives/class-map.js";
1312
import { repeat } from "lit/directives/repeat.js";
1413
import "@carbon/web-components/es/components/button/index.js";
1514
import "@carbon/web-components/es/components/overflow-menu/index.js";
@@ -21,6 +20,9 @@ import prefix from "../../../globals/settings.js";
2120
import styles from "./toolbar.scss?lit";
2221
import { CarbonIcon } from "@carbon/web-components/es/globals/internal/icon-loader-utils.js";
2322
import { carbonElement } from "../../../globals/decorators/index.js";
23+
import "../../truncated-text/index.js";
24+
25+
const blockClass = `${prefix}-toolbar`;
2426

2527
export interface Action {
2628
text: string;
@@ -40,7 +42,7 @@ export interface Action {
4042
* @slot toolbar-ai-label - Defines the area for displaying the AI label in the toolbar.
4143
*
4244
*/
43-
@carbonElement(`${prefix}-toolbar`)
45+
@carbonElement(blockClass)
4446
class CDSAIChatToolbar extends LitElement {
4547
/** Hidden actions rendered in the overflow menu.
4648
* @internal
@@ -55,10 +57,13 @@ class CDSAIChatToolbar extends LitElement {
5557
@property({ type: Boolean, attribute: "overflow", reflect: true })
5658
overflow = false;
5759

60+
@property({ type: String })
61+
titleText?: string;
62+
5863
/** Container holding all action buttons and the overflow menu.
5964
* @internal
6065
*/
61-
@query(`.${prefix}-toolbar`) private container!: HTMLElement;
66+
@query(`.${blockClass}__right`) private container!: HTMLElement;
6267

6368
@state() private measuring = true;
6469

@@ -182,63 +187,74 @@ class CDSAIChatToolbar extends LitElement {
182187
const showOverflowMenu = this.measuring || this.hiddenItems.length > 0;
183188

184189
return html`
185-
<div
186-
data-rounded="top"
187-
class=${classMap({ [`${prefix}-toolbar`]: true })}
188-
>
189-
<div data-fixed class="cds-aichat-toolbar__navigation">
190-
<slot name="navigation"></slot>
191-
</div>
190+
<div data-rounded="top" class=${blockClass}>
191+
<div data-fixed class="${blockClass}__left">
192+
<div data-fixed class="${blockClass}__navigation">
193+
<slot name="navigation"></slot>
194+
</div>
192195
193-
<div data-fixed class="cds-aichat-toolbar__title">
194-
<slot name="title"></slot>
196+
<div data-fixed class="${blockClass}__title">
197+
<slot name="title">
198+
<cds-aichat-truncated-text
199+
value=${this.titleText}
200+
lines="1"
201+
type="tooltip"
202+
></cds-aichat-truncated-text>
203+
</slot>
204+
</div>
195205
</div>
196206
197-
<div data-fixed class="cds-aichat-toolbar__fixed-actions">
198-
<slot name="fixed-actions"></slot>
199-
</div>
207+
<div data-fixed class="${blockClass}__right">
208+
<div data-fixed class="${blockClass}__fixed-actions">
209+
<slot name="fixed-actions"></slot>
210+
</div>
211+
212+
<div data-fixed><slot name="decorator"></slot></div>
200213
201-
<div data-fixed><slot name="decorator"></slot></div>
202-
203-
${repeat(
204-
nonFixedActions,
205-
(action) => action.text,
206-
this.renderIconButton,
207-
)}
208-
${showOverflowMenu
209-
? html`
210-
<cds-overflow-menu
211-
size=${this.getOverflowMenuSize()}
212-
align="bottom-end"
213-
data-offset
214-
?data-hidden=${this.hiddenItems.length === 0}
215-
kind="ghost"
216-
close-on-activation
217-
enter-delay-ms="0"
218-
leave-delay-ms="0"
219-
>
220-
${iconLoader(OverflowMenuVertical16, {
221-
class: `${prefix}-toolbar-overflow-icon`,
222-
slot: "icon",
223-
})}
224-
<span slot="tooltip-content"
225-
>${CDSAIChatToolbar.OVERFLOW_MENU_LABEL}</span
214+
${repeat(
215+
nonFixedActions,
216+
(action) => action.text,
217+
this.renderIconButton,
218+
)}
219+
${showOverflowMenu
220+
? html`
221+
<cds-overflow-menu
222+
size=${this.getOverflowMenuSize()}
223+
align="bottom-end"
224+
data-offset
225+
?data-hidden=${this.hiddenItems.length === 0}
226+
kind="ghost"
227+
close-on-activation
228+
enter-delay-ms="0"
229+
leave-delay-ms="0"
226230
>
227-
<cds-overflow-menu-body flipped>
228-
${repeat(
229-
this.hiddenItems,
230-
(item) => item.text,
231-
(item) => html`
232-
<cds-overflow-menu-item @click=${item.onClick}>
233-
${item.text}
234-
</cds-overflow-menu-item>
235-
`,
236-
)}
237-
</cds-overflow-menu-body>
238-
</cds-overflow-menu>
239-
`
240-
: nothing}
241-
${repeat(fixedActions, (action) => action.text, this.renderIconButton)}
231+
${iconLoader(OverflowMenuVertical16, {
232+
class: `${blockClass}-overflow-icon`,
233+
slot: "icon",
234+
})}
235+
<span slot="tooltip-content"
236+
>${CDSAIChatToolbar.OVERFLOW_MENU_LABEL}</span
237+
>
238+
<cds-overflow-menu-body flipped>
239+
${repeat(
240+
this.hiddenItems,
241+
(item) => item.text,
242+
(item) => html`
243+
<cds-overflow-menu-item @click=${item.onClick}>
244+
${item.text}
245+
</cds-overflow-menu-item>
246+
`,
247+
)}
248+
</cds-overflow-menu-body>
249+
</cds-overflow-menu>
250+
`
251+
: nothing}
252+
${repeat(
253+
fixedActions,
254+
(action) => action.text,
255+
this.renderIconButton,
256+
)}
257+
</div>
242258
</div>
243259
`;
244260
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* @license
3+
*
4+
* Copyright IBM Corp. 2026
5+
*
6+
* This source code is licensed under the Apache-2.0 license found in the
7+
* LICENSE file in the root directory of this source tree.
8+
*/
9+
10+
// TODO: add this to core utils
11+
12+
import "./src/truncated-text";
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright IBM Corp. 2026
3+
*
4+
* This source code is licensed under the Apache-2.0 license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
// $css--plex: true !default;
9+
10+
@use "sass:map";
11+
@use "@carbon/styles/scss/utilities" as *;
12+
@use "@carbon/styles/scss/spacing" as *;
13+
@use "@carbon/styles/scss/theme";
14+
@use "@carbon/styles/scss/motion" as *;
15+
@use "@carbon/styles/scss/config" as carbon-config;
16+
17+
$prefix: "cds-aichat";
18+
$carbon-prefix: carbon-config.$prefix;
19+
$block-class: #{$prefix}--truncated-text;
20+
21+
// Common reset button style
22+
%reset-button {
23+
border: none;
24+
cursor: pointer;
25+
font: inherit;
26+
line-height: inherit;
27+
}
28+
29+
// Mixin for directional gradients
30+
@mixin gradient-bg($direction, $color) {
31+
background: linear-gradient($direction, rgba(255, 255, 255, 0) 0%, $color 0%);
32+
}
33+
34+
:host(#{$prefix}-truncated-text) {
35+
display: block;
36+
inline-size: 100%;
37+
38+
.#{$block-class}_transition {
39+
@media (prefers-reduced-motion: no-preference) {
40+
transition: max-height $duration-fast-02 motion(standard, productive);
41+
}
42+
}
43+
44+
.#{$block-class}_content {
45+
display: -webkit-box;
46+
overflow: hidden;
47+
-webkit-box-orient: vertical;
48+
-webkit-line-clamp: var(--line-clamp, 0);
49+
text-overflow: clip;
50+
white-space: normal;
51+
52+
&:focus {
53+
@include focus-outline("outline");
54+
}
55+
}
56+
57+
.#{$block-class}_content--closing {
58+
-webkit-line-clamp: none;
59+
}
60+
61+
#{$carbon-prefix}-tooltip {
62+
display: inline-flex;
63+
}
64+
65+
button:focus,
66+
.#{$block-class}_button-expand:focus,
67+
.#{$block-class}_button-collapse:focus {
68+
@include focus-outline("outline");
69+
}
70+
}
71+
72+
.#{$block-class}_button-expand,
73+
.#{$block-class}_button-collapse {
74+
@extend %reset-button;
75+
76+
padding: 0 $spacing-01;
77+
color: theme.$link-primary;
78+
79+
&.#{$block-class}_button-hide {
80+
display: none;
81+
}
82+
}
83+
84+
.#{$block-class}_button-expand {
85+
&.#{$block-class}_button-layered {
86+
background-color: theme.$layer;
87+
}
88+
89+
// Gradient LTR
90+
&:dir(ltr)::before {
91+
@include gradient-bg(90deg, theme.$background);
92+
}
93+
94+
&.#{$block-class}_button-layered:dir(ltr)::before {
95+
@include gradient-bg(90deg, theme.$layer);
96+
}
97+
98+
// Gradient RTL
99+
&:dir(rtl)::before {
100+
@include gradient-bg(270deg, theme.$background);
101+
}
102+
103+
&.#{$block-class}_button-layered:dir(rtl)::before {
104+
@include gradient-bg(270deg, theme.$layer);
105+
}
106+
}
107+
108+
.#{$block-class}_button-collapse {
109+
background-color: transparent;
110+
}

0 commit comments

Comments
 (0)