Skip to content

Commit 6ddeda7

Browse files
Copilotkdinevrkaraivanov
authored
Fix tooltip max-width constraint for custom content (#1936)
* Initial plan * Fix tooltip max-width constraint for custom content Co-authored-by: kdinev <[email protected]> * Address code review feedback - improve defensive coding Co-authored-by: kdinev <[email protected]> * Fix timing issue with slot content detection Move slot content check to updated() lifecycle to ensure slot element is available. The @query() decorated properties are only populated after firstUpdated() completes, so checking in firstUpdated() was too early. Now using updated() with a flag to check on first update and when message property changes. Co-authored-by: kdinev <[email protected]> * refactor: Use slot controller and part attribute for styling --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: kdinev <[email protected]> Co-authored-by: Konstantin Dinev <[email protected]> Co-authored-by: Radoslav Karaivanov <[email protected]>
1 parent 329e2f4 commit 6ddeda7

File tree

3 files changed

+49
-3
lines changed

3 files changed

+49
-3
lines changed

src/components/tooltip/themes/tooltip.base.scss

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,24 @@
88
text-align: center;
99
}
1010

11-
[part="base"] {
11+
[part~="base"] {
1212
@include type-style('body-2');
1313

1414
padding: pad-block(rem(4px)) pad-inline(rem(8px));
1515
font-size: rem(10px);
1616
font-weight: 600;
1717
line-height: rem(16px);
1818
text-align: start;
19-
max-width: 200px;
2019
display: flex;
2120
align-items: flex-start;
2221
gap: rem(8px);
2322
position: relative;
2423
}
2524

25+
[part~="simple-text"] {
26+
max-width: 200px;
27+
}
28+
2629
#arrow {
2730
position: absolute;
2831
width: 0;

src/components/tooltip/tooltip.spec.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,40 @@ describe('Tooltip', () => {
276276
expect(defaultSlot?.assignedElements()[0].matches('button')).to.be.true;
277277
});
278278

279+
it('should apply simple-text class when using message property only', async () => {
280+
const template = html`
281+
<div>
282+
<button>Hover</button>
283+
<igc-tooltip message="Simple text tooltip"></igc-tooltip>
284+
</div>
285+
`;
286+
const container = await fixture(template);
287+
tooltip = container.querySelector(IgcTooltipComponent.tagName)!;
288+
await elementUpdated(tooltip);
289+
290+
const baseElement = tooltip.renderRoot.querySelector('[part~="base"]');
291+
expect(baseElement).not.to.be.null;
292+
expect(baseElement?.part.contains('simple-text')).to.be.true;
293+
});
294+
295+
it('should not apply simple-text class when using custom content', async () => {
296+
const template = html`
297+
<div>
298+
<button>Hover</button>
299+
<igc-tooltip>
300+
<div>Custom content with complex structure</div>
301+
</igc-tooltip>
302+
</div>
303+
`;
304+
const container = await fixture(template);
305+
tooltip = container.querySelector(IgcTooltipComponent.tagName)!;
306+
await elementUpdated(tooltip);
307+
308+
const baseElement = tooltip.renderRoot.querySelector('[part~="base"]');
309+
expect(baseElement).not.to.be.null;
310+
expect(baseElement?.part.contains('simple-text')).to.be.false;
311+
});
312+
279313
it('should render a default close button when in `sticky` mode', async () => {
280314
tooltip.sticky = true;
281315
await elementUpdated(tooltip);

src/components/tooltip/tooltip.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ import { fadeOut } from '../../animations/presets/fade/index.js';
77
import { scaleInCenter } from '../../animations/presets/scale/index.js';
88
import { addThemingController } from '../../theming/theming-controller.js';
99
import { addInternalsController } from '../common/controllers/internals.js';
10+
import { addSlotController, setSlots } from '../common/controllers/slot.js';
1011
import { registerComponent } from '../common/definitions/register.js';
1112
import type { Constructor } from '../common/mixins/constructor.js';
1213
import { EventEmitterMixin } from '../common/mixins/event-emitter.js';
14+
import { partMap } from '../common/part-map.js';
1315
import { asNumber, isLTR } from '../common/util.js';
1416
import IgcIconComponent from '../icon/icon.js';
1517
import IgcPopoverComponent, {
@@ -43,6 +45,7 @@ type TooltipStateOptions = {
4345
* @slot close-button - Slot for custom sticky-mode close action (e.g., an icon/button).
4446
*
4547
* @csspart base - The wrapping container of the tooltip content.
48+
* @csspart simple-text - The container where the message property of the tooltip is rendered.
4649
*
4750
* @fires igcOpening - Emitted before the tooltip begins to open. Can be canceled to prevent opening.
4851
* @fires igcOpened - Emitted after the tooltip has successfully opened and is visible.
@@ -82,6 +85,7 @@ export default class IgcTooltipComponent extends EventEmitterMixin<
8285

8386
private readonly _containerRef = createRef<HTMLElement>();
8487
private readonly _player = addAnimationController(this, this._containerRef);
88+
private readonly _slots = addSlotController(this, { slots: setSlots() });
8589

8690
private readonly _showAnimation = scaleInCenter({
8791
duration: 150,
@@ -430,6 +434,11 @@ export default class IgcTooltipComponent extends EventEmitterMixin<
430434
}
431435

432436
protected override render() {
437+
const parts = {
438+
base: true,
439+
'simple-text': !this._slots.hasAssignedNodes('[default]', true),
440+
};
441+
433442
return html`
434443
<igc-popover
435444
.inert=${!this.open}
@@ -443,7 +452,7 @@ export default class IgcTooltipComponent extends EventEmitterMixin<
443452
flip
444453
shift
445454
>
446-
<div ${ref(this._containerRef)} part="base">
455+
<div ${ref(this._containerRef)} part=${partMap(parts)}>
447456
<slot>${this.message}</slot>
448457
${this.sticky
449458
? html`

0 commit comments

Comments
 (0)