Skip to content

Commit cfda98d

Browse files
authored
refactor(tooltip): Align API and behavior to Angular tooltip (#1740)
* refactor(tooltip): Align API and behavior to Angular tooltip docs: Updated CHANGELOG with release notes.
1 parent e48d8e5 commit cfda98d

File tree

3 files changed

+84
-70
lines changed

3 files changed

+84
-70
lines changed

CHANGELOG.md

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,29 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/)
55
and this project adheres to [Semantic Versioning](http://semver.org/).
66

7-
## [Unreleased]
7+
## [6.1.0] - 2025-06-11
8+
### Added
9+
- Date Range Picker
10+
11+
### Changed
12+
- #### Tooltip
13+
- **Behavioral change**: Tooltip default `placement` is 'bottom' now.
14+
- **Behavioral change**: Tooltip will not render an arrow indicator by default unless `with-arrow` is set.
15+
- **Breaking change**: Tooltip events will no longer return its `anchor` target in its `detail` property.
16+
17+
You can still access it at `event.target.anchor`.
18+
19+
### Deprecated
20+
- #### Tooltip
21+
- `disableArrow` is deprecated. Use `withArrow | with-arrow` to render an arrow indicator.
22+
823
### Fixed
9-
- #### Calendar & Date picker
10-
- Incorrect date rollover for in certain scenarios [#1710](https://github.com/IgniteUI/igniteui-webcomponents/issues/1710)
24+
- #### Calendar & Date Picker
25+
- Incorrect date rollover for in certain scenarios [#1710](https://github.com/IgniteUI/igniteui-webcomponents/issues/1710)
26+
- #### Combo
27+
- Case insensitive icon styles in themes [#1728](https://github.com/IgniteUI/igniteui-webcomponents/pull/1728)
28+
- #### Textarea
29+
- Label height and component height override [#1715](https://github.com/IgniteUI/igniteui-webcomponents/pull/1715)
1130

1231
## [6.0.1] - 2025-05-28
1332
### Added
@@ -898,6 +917,7 @@ Initial release of Ignite UI Web Components
898917
- Ripple component
899918
- Switch component
900919

920+
[6.1.0]: https://github.com/IgniteUI/igniteui-webcomponents/compare/6.0.1...6.1.0
901921
[6.0.1]: https://github.com/IgniteUI/igniteui-webcomponents/compare/6.0.0...6.0.1
902922
[6.0.0]: https://github.com/IgniteUI/igniteui-webcomponents/compare/5.4.1...6.0.0
903923
[5.4.1]: https://github.com/IgniteUI/igniteui-webcomponents/compare/5.4.0...5.4.1

src/components/tooltip/tooltip.spec.ts

Lines changed: 20 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,10 @@ describe('Tooltip', () => {
7575
it('is correctly initialized with its default component state', () => {
7676
expect(tooltip.dir).to.be.empty;
7777
expect(tooltip.open).to.be.false;
78-
expect(tooltip.disableArrow).to.be.false;
78+
expect(tooltip.disableArrow).to.be.true;
79+
expect(tooltip.withArrow).to.be.false;
7980
expect(tooltip.offset).to.equal(6);
80-
expect(tooltip.placement).to.equal('top');
81+
expect(tooltip.placement).to.equal('bottom');
8182
expect(tooltip.anchor).to.be.undefined;
8283
expect(tooltip.showTriggers).to.equal('pointerenter');
8384
expect(tooltip.hideTriggers).to.equal('pointerleave,click');
@@ -86,11 +87,6 @@ describe('Tooltip', () => {
8687
expect(tooltip.message).to.equal('');
8788
});
8889

89-
it('should render a default arrow', () => {
90-
const arrow = tooltip.shadowRoot!.querySelector('#arrow');
91-
expect(arrow).not.to.be.null;
92-
});
93-
9490
it('is correctly rendered both in shown/hidden states', async () => {
9591
expect(tooltip.open).to.be.false;
9692

@@ -103,7 +99,6 @@ describe('Tooltip', () => {
10399
>
104100
<div part="base">
105101
<slot></slot>
106-
<div id="arrow"></div>
107102
</div>
108103
</igc-popover>`
109104
);
@@ -120,7 +115,6 @@ describe('Tooltip', () => {
120115
>
121116
<div part="base">
122117
<slot></slot>
123-
<div id="arrow"></div>
124118
</div>
125119
</igc-popover>`
126120
);
@@ -212,29 +206,29 @@ describe('Tooltip', () => {
212206
expect(tooltip.open).to.be.true;
213207
});
214208

215-
it('should show/hide the arrow via the `disableArrow` property', async () => {
216-
expect(tooltip.disableArrow).to.be.false;
217-
expect(tooltip.shadowRoot!.querySelector('#arrow')).to.exist;
209+
it('should show/hide the arrow via the `withArrow` property', async () => {
210+
expect(tooltip.withArrow).to.be.false;
211+
expect(tooltip.renderRoot.querySelector('#arrow')).to.be.null;
218212

219-
tooltip.disableArrow = true;
213+
tooltip.withArrow = true;
220214
await elementUpdated(tooltip);
221215

222-
expect(tooltip.disableArrow).to.be.true;
223-
expect(tooltip.shadowRoot!.querySelector('#arrow')).to.be.null;
216+
expect(tooltip.withArrow).to.be.true;
217+
expect(tooltip.renderRoot.querySelector('#arrow')).not.to.be.null;
224218
});
225219

226-
it('should show/hide the arrow via the `disable-arrow` attribute', async () => {
220+
it('should show/hide the arrow via the `with-arrow` attribute', async () => {
227221
const template = html`
228222
<div>
229223
<button>Hover</button>
230-
<igc-tooltip disable-arrow>I am a tooltip</igc-tooltip>
224+
<igc-tooltip with-arrow>I am a tooltip</igc-tooltip>
231225
</div>
232226
`;
233227
const container = await fixture(template);
234228
tooltip = container.querySelector(IgcTooltipComponent.tagName)!;
235229

236-
expect(tooltip.disableArrow).to.be.true;
237-
expect(tooltip.shadowRoot!.querySelector('#arrow')).to.be.null;
230+
expect(tooltip.withArrow).to.be.true;
231+
expect(tooltip.renderRoot.querySelector('#arrow')).not.to.be.null;
238232
});
239233

240234
it('should provide content via the `message` property', async () => {
@@ -305,7 +299,6 @@ describe('Tooltip', () => {
305299
name="input_clear"
306300
></igc-icon>
307301
</slot>
308-
<div id="arrow"></div>
309302
</div>
310303
</igc-popover>`
311304
);
@@ -534,15 +527,8 @@ describe('Tooltip', () => {
534527
await showComplete();
535528
expect(tooltip.open).to.be.true;
536529

537-
expect(eventSpy).calledWith('igcOpening', {
538-
cancelable: true,
539-
detail: defaultAnchor,
540-
});
541-
542-
expect(eventSpy).calledWith('igcOpened', {
543-
cancelable: false,
544-
detail: defaultAnchor,
545-
});
530+
expect(eventSpy).calledWith('igcOpening', { cancelable: true });
531+
expect(eventSpy).calledWith('igcOpened', { cancelable: false });
546532
});
547533
});
548534

@@ -698,11 +684,11 @@ describe('Tooltip', () => {
698684
expect(eventSpy.callCount).to.equal(2);
699685
expect(eventSpy.firstCall).calledWith(
700686
state.open ? 'igcOpening' : 'igcClosing',
701-
{ cancelable: true, detail: anchor }
687+
{ cancelable: true }
702688
);
703689
expect(eventSpy.secondCall).calledWith(
704690
state.open ? 'igcOpened' : 'igcClosed',
705-
{ cancelable: false, detail: anchor }
691+
{ cancelable: false }
706692
);
707693
};
708694

@@ -730,10 +716,7 @@ describe('Tooltip', () => {
730716
await showComplete(tooltip);
731717

732718
expect(tooltip.open).to.be.false;
733-
expect(eventSpy).calledOnceWith('igcOpening', {
734-
cancelable: true,
735-
detail: anchor,
736-
});
719+
expect(eventSpy).calledOnceWith('igcOpening', { cancelable: true });
737720

738721
eventSpy.resetHistory();
739722

@@ -749,10 +732,7 @@ describe('Tooltip', () => {
749732
await hideComplete(tooltip);
750733

751734
expect(tooltip.open).to.be.true;
752-
expect(eventSpy).calledOnceWith('igcClosing', {
753-
cancelable: true,
754-
detail: anchor,
755-
});
735+
expect(eventSpy).calledOnceWith('igcClosing', { cancelable: true });
756736
});
757737

758738
it('fires `igcClosed` when tooltip is hidden via Escape key', async () => {
@@ -775,10 +755,7 @@ describe('Tooltip', () => {
775755

776756
expect(tooltip.open).to.be.false;
777757
expect(eventSpy.callCount).to.equal(1);
778-
expect(eventSpy.firstCall).calledWith('igcClosed', {
779-
cancelable: false,
780-
detail: anchor,
781-
});
758+
expect(eventSpy.firstCall).calledWith('igcClosed', { cancelable: false });
782759
});
783760
});
784761

src/components/tooltip/tooltip.ts

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import { LitElement, html, nothing } from 'lit';
1+
import { LitElement, type PropertyValues, html, nothing } from 'lit';
22
import { property, query } from 'lit/decorators.js';
33
import { createRef, ref } from 'lit/directives/ref.js';
44
import { EaseOut } from '../../animations/easings.js';
55
import { addAnimationController } from '../../animations/player.js';
66
import { fadeOut } from '../../animations/presets/fade/index.js';
77
import { scaleInCenter } from '../../animations/presets/scale/index.js';
88
import { themes } from '../../theming/theming-decorator.js';
9-
import { watch } from '../common/decorators/watch.js';
109
import { registerComponent } from '../common/definitions/register.js';
1110
import type { Constructor } from '../common/mixins/constructor.js';
1211
import { EventEmitterMixin } from '../common/mixins/event-emitter.js';
@@ -21,14 +20,10 @@ import { all } from './themes/themes.js';
2120
import { styles } from './themes/tooltip.base.css.js';
2221

2322
export interface IgcTooltipComponentEventMap {
24-
/* blazorAlternateType: CustomEvent<void> */
25-
igcOpening: CustomEvent<Element | null>;
26-
/* blazorAlternateType: CustomEvent<void> */
27-
igcOpened: CustomEvent<Element | null>;
28-
/* blazorAlternateType: CustomEvent<void> */
29-
igcClosing: CustomEvent<Element | null>;
30-
/* blazorAlternateType: CustomEvent<void> */
31-
igcClosed: CustomEvent<Element | null>;
23+
igcOpening: CustomEvent<void>;
24+
igcOpened: CustomEvent<void>;
25+
igcClosing: CustomEvent<void>;
26+
igcClosed: CustomEvent<void>;
3227
}
3328

3429
type TooltipStateOptions = {
@@ -143,11 +138,30 @@ export default class IgcTooltipComponent extends EventEmitterMixin<
143138
/**
144139
* Whether to disable the rendering of the arrow indicator for the tooltip.
145140
*
141+
* @deprecated since 6.1.0. Use `with-arrow` to control the behavior of the tooltip arrow.
146142
* @attr disable-arrow
147143
* @default false
148144
*/
149-
@property({ attribute: 'disable-arrow', type: Boolean, reflect: true })
150-
public disableArrow = false;
145+
@property({ type: Boolean, attribute: 'disable-arrow' })
146+
public set disableArrow(value: boolean) {
147+
this.withArrow = !value;
148+
}
149+
150+
/**
151+
* @deprecated since 6.1.0. Use `with-arrow` to control the behavior of the tooltip arrow.
152+
*/
153+
public get disableArrow(): boolean {
154+
return !this.withArrow;
155+
}
156+
157+
/**
158+
* Whether to render an arrow indicator for the tooltip.
159+
*
160+
* @attr with-arrow
161+
* @default false
162+
*/
163+
@property({ type: Boolean, reflect: true, attribute: 'with-arrow' })
164+
public withArrow = false;
151165

152166
/**
153167
* The offset of the tooltip from the anchor in pixels.
@@ -162,14 +176,18 @@ export default class IgcTooltipComponent extends EventEmitterMixin<
162176
* Where to place the floating element relative to the parent anchor element.
163177
*
164178
* @attr placement
165-
* @default top
179+
* @default bottom
166180
*/
167181
@property()
168-
public placement: PopoverPlacement = 'top';
182+
public placement: PopoverPlacement = 'bottom';
169183

170184
/**
171185
* An element instance or an IDREF to use as the anchor for the tooltip.
172186
*
187+
* @remarks
188+
* Trying to bind to an IDREF that does not exist in the current DOM root at will not work.
189+
* In such scenarios, it is better to get a DOM reference and pass it to the tooltip instance.
190+
*
173191
* @attr anchor
174192
*/
175193
@property()
@@ -272,20 +290,19 @@ export default class IgcTooltipComponent extends EventEmitterMixin<
272290
}
273291
}
274292

275-
@watch('anchor')
276-
protected _onAnchorChange(): void {
277-
this._controller.resolveAnchor(this.anchor);
278-
}
293+
protected override willUpdate(changedProperties: PropertyValues<this>): void {
294+
if (changedProperties.has('anchor')) {
295+
this._controller.resolveAnchor(this.anchor);
296+
}
279297

280-
@watch('sticky')
281-
protected _onStickyChange(): void {
282-
this._internals.role = this.sticky ? 'status' : 'tooltip';
298+
if (changedProperties.has('sticky')) {
299+
this._internals.role = this.sticky ? 'status' : 'tooltip';
300+
}
283301
}
284302

285303
private _emitEvent(name: keyof IgcTooltipComponentEventMap): boolean {
286304
return this.emitEvent(name, {
287305
cancelable: name === 'igcOpening' || name === 'igcClosing',
288-
detail: this._controller.anchor,
289306
});
290307
}
291308

@@ -416,7 +433,7 @@ export default class IgcTooltipComponent extends EventEmitterMixin<
416433
.placement=${this.placement}
417434
.offset=${this.offset}
418435
.anchor=${this._controller.anchor ?? undefined}
419-
.arrow=${this.disableArrow ? null : this._arrowElement}
436+
.arrow=${this.withArrow ? this._arrowElement : null}
420437
.arrowOffset=${this._arrowOffset}
421438
.shiftPadding=${8}
422439
?open=${this.open}
@@ -436,7 +453,7 @@ export default class IgcTooltipComponent extends EventEmitterMixin<
436453
</slot>
437454
`
438455
: nothing}
439-
${this.disableArrow ? nothing : html`<div id="arrow"></div>`}
456+
${this.withArrow ? html`<div id="arrow"></div>` : nothing}
440457
</div>
441458
</igc-popover>
442459
`;

0 commit comments

Comments
 (0)