From 8a530700fe9dbb53d035015bbd7cada42d0d4312 Mon Sep 17 00:00:00 2001 From: Kamil Emeleev Date: Mon, 17 Aug 2026 21:18:23 +0300 Subject: [PATCH] fix(tree): prevent tooltip for non-truncated option text --- .../components/tree/tree-option.component.ts | 2 + .../tree/tree-selection.component.spec.ts | 55 +++++++++++++++++++ tools/public_api_guard/components/tree.api.md | 1 + 3 files changed, 58 insertions(+) diff --git a/packages/components/tree/tree-option.component.ts b/packages/components/tree/tree-option.component.ts index 5970ea031..f414b759a 100644 --- a/packages/components/tree/tree-option.component.ts +++ b/packages/components/tree/tree-option.component.ts @@ -108,6 +108,8 @@ export class KbqTreeOption extends KbqTreeNode implements AfterCo preventBlur: boolean = false; @ViewChild('kbqTitleContainer') parentTextElement: ElementRef; + /** Same element as `parentTextElement` — `.kbq-option-text` clips the text, so it is measured against itself. */ + @ViewChild('kbqTitleContainer') textElement: ElementRef; readonly toggleElementDirective = contentChild(KbqTreeNodeToggleDirective); readonly toggleElementComponent = contentChild(KbqTreeNodeToggleComponent); readonly pseudoCheckbox = contentChild(KbqPseudoCheckbox); diff --git a/packages/components/tree/tree-selection.component.spec.ts b/packages/components/tree/tree-selection.component.spec.ts index fbed1a991..4830b811b 100644 --- a/packages/components/tree/tree-selection.component.spec.ts +++ b/packages/components/tree/tree-selection.component.spec.ts @@ -20,6 +20,7 @@ import { TAB } from '@koobiq/components/core'; import { KbqDropdownModule } from '@koobiq/components/dropdown'; +import { KbqTitleDirective, KbqTitleModule } from '@koobiq/components/title'; import { AsyncScheduler } from 'rxjs/internal/scheduler/AsyncScheduler'; import { TestScheduler } from 'rxjs/testing'; import { @@ -1579,6 +1580,47 @@ describe('KbqTreeSelection', () => { }); }); }); + + describe('kbq-title', () => { + let fixture: ComponentFixture; + let titleDirective: KbqTitleDirective; + let optionElement: HTMLElement; + let containerElement: HTMLElement; + + beforeEach(() => { + configureKbqTreeTestingModule(); + fixture = TestBed.createComponent(KbqTreeAppWithTitle); + fixture.detectChanges(); + + const optionDebugElement = fixture.debugElement.query(By.directive(KbqTitleDirective)); + + titleDirective = optionDebugElement.injector.get(KbqTitleDirective); + optionElement = optionDebugElement.nativeElement; + containerElement = optionElement.querySelector('.kbq-option-text')!; + }); + + it('should measure the clipping container, not the option host', () => { + // The host is always wider and taller than the container it wraps (padding, border, checkbox), + // so measuring the container against the host reported every option as truncated. + jest.spyOn(optionElement, 'scrollWidth', 'get').mockReturnValue(296); + jest.spyOn(optionElement, 'scrollHeight', 'get').mockReturnValue(28); + jest.spyOn(containerElement, 'offsetWidth', 'get').mockReturnValue(232); + jest.spyOn(containerElement, 'scrollWidth', 'get').mockReturnValue(232); + jest.spyOn(containerElement, 'offsetHeight', 'get').mockReturnValue(20); + jest.spyOn(containerElement, 'scrollHeight', 'get').mockReturnValue(20); + + expect(titleDirective.isOverflown).toBe(false); + }); + + it('should report overflow when the container is clipped', () => { + jest.spyOn(containerElement, 'offsetWidth', 'get').mockReturnValue(28); + jest.spyOn(containerElement, 'scrollWidth', 'get').mockReturnValue(70); + jest.spyOn(containerElement, 'offsetHeight', 'get').mockReturnValue(20); + jest.spyOn(containerElement, 'scrollHeight', 'get').mockReturnValue(20); + + expect(titleDirective.isOverflown).toBe(true); + }); + }); }); export const DATA_OBJECT = { @@ -1797,6 +1839,19 @@ abstract class TreeParams { }; } +@Component({ + imports: [ + KbqTreeModule, + KbqTitleModule + ], + template: ` + + {{ node.name }} + + ` +}) +class KbqTreeAppWithTitle extends TreeParams {} + @Component({ imports: [KbqTreeModule, FormsModule], template: ` diff --git a/tools/public_api_guard/components/tree.api.md b/tools/public_api_guard/components/tree.api.md index 6de1ca228..3b7e98000 100644 --- a/tools/public_api_guard/components/tree.api.md +++ b/tools/public_api_guard/components/tree.api.md @@ -482,6 +482,7 @@ export class KbqTreeOption extends KbqTreeNode implements AfterCo // (undocumented) get showCheckbox(): any; set showCheckbox(value: any); + textElement: ElementRef; // (undocumented) toggle(): void; // (undocumented)