From 2a15772bf37dd81914da2d8833415b8c18480c23 Mon Sep 17 00:00:00 2001 From: fateeand Date: Tue, 19 May 2026 14:31:37 +0200 Subject: [PATCH] Integrate CpsRootFontSizeService into components --- .../cps-autocomplete.component.spec.ts | 14 +- .../cps-autocomplete.component.ts | 18 +- .../cps-button-toggle.component.spec.ts | 390 ++++++++++++++++++ .../cps-button-toggle.component.ts | 16 +- .../cps-tooltip/cps-tooltip.directive.spec.ts | 12 +- .../cps-tooltip/cps-tooltip.directive.ts | 18 +- .../cps-dialog/cps-dialog.component.spec.ts | 9 + .../cps-dialog/cps-dialog.component.ts | 11 +- 8 files changed, 449 insertions(+), 39 deletions(-) create mode 100644 projects/cps-ui-kit/src/lib/components/cps-button-toggle/cps-button-toggle.component.spec.ts diff --git a/projects/cps-ui-kit/src/lib/components/cps-autocomplete/cps-autocomplete.component.spec.ts b/projects/cps-ui-kit/src/lib/components/cps-autocomplete/cps-autocomplete.component.spec.ts index 5aa23e3c..9074d24d 100644 --- a/projects/cps-ui-kit/src/lib/components/cps-autocomplete/cps-autocomplete.component.spec.ts +++ b/projects/cps-ui-kit/src/lib/components/cps-autocomplete/cps-autocomplete.component.spec.ts @@ -13,6 +13,11 @@ import { CheckOptionSelectedPipe } from '../../pipes/internal/check-option-selec import { LabelByValuePipe } from '../../pipes/internal/label-by-value.pipe'; import { CpsMenuHideReason } from '../cps-menu/cps-menu.component'; import { CpsAutocompleteComponent } from './cps-autocomplete.component'; +import { CPS_ROOT_FONT_SIZE_SERVICE } from '../../services/cps-root-font-size/cps-root-font-size.service'; + +const mockRootFontSizeService = { + fontSize: () => 16 +}; describe('CpsAutocompleteComponent', () => { let component: CpsAutocompleteComponent; @@ -26,7 +31,14 @@ describe('CpsAutocompleteComponent', () => { CpsAutocompleteComponent, NoopAnimationsModule ], - providers: [LabelByValuePipe, CheckOptionSelectedPipe], + providers: [ + LabelByValuePipe, + CheckOptionSelectedPipe, + { + provide: CPS_ROOT_FONT_SIZE_SERVICE, + useValue: mockRootFontSizeService + } + ], schemas: [NO_ERRORS_SCHEMA] // Ignore unknown elements and attributes }).compileComponents(); }); diff --git a/projects/cps-ui-kit/src/lib/components/cps-autocomplete/cps-autocomplete.component.ts b/projects/cps-ui-kit/src/lib/components/cps-autocomplete/cps-autocomplete.component.ts index 8e7414be..07abf78c 100644 --- a/projects/cps-ui-kit/src/lib/components/cps-autocomplete/cps-autocomplete.component.ts +++ b/projects/cps-ui-kit/src/lib/components/cps-autocomplete/cps-autocomplete.component.ts @@ -1,11 +1,11 @@ -import { CommonModule, DOCUMENT, isPlatformBrowser } from '@angular/common'; +import { CommonModule } from '@angular/common'; import { AfterViewInit, ChangeDetectorRef, Component, ElementRef, EventEmitter, - Inject, + inject, Input, OnChanges, OnDestroy, @@ -14,7 +14,6 @@ import { Output, Self, ViewChild, - PLATFORM_ID, type SimpleChanges } from '@angular/core'; import { @@ -25,6 +24,7 @@ import { } from '@angular/forms'; import { Subject, debounceTime, distinctUntilChanged, takeUntil } from 'rxjs'; import { convertSize } from '../../utils/internal/size-utils'; +import { CPS_ROOT_FONT_SIZE_SERVICE } from '../../services/cps-root-font-size/cps-root-font-size.service'; import { generateUniqueId, getComputedLabel @@ -446,7 +446,10 @@ export class CpsAutocompleteComponent 'cps-autocomplete-option' ); - private _rootFontSizePx = 16; + private readonly _cpsRootFontSizeService = inject(CPS_ROOT_FONT_SIZE_SERVICE); + private get _rootFontSizePx(): number { + return this._cpsRootFontSizeService?.fontSize() ?? 16; + } private _inputChangeSubject$ = new Subject(); private _destroy$ = new Subject(); @@ -456,8 +459,6 @@ export class CpsAutocompleteComponent constructor( @Self() @Optional() private _control: NgControl, - @Inject(DOCUMENT) private document: Document, - @Inject(PLATFORM_ID) private platformId: object, private cdRef: ChangeDetectorRef, private _labelByValue: LabelByValuePipe ) { @@ -475,11 +476,6 @@ export class CpsAutocompleteComponent } ngOnInit() { - if (isPlatformBrowser(this.platformId)) { - this._rootFontSizePx = parseFloat( - getComputedStyle(this.document.documentElement).fontSize || '16' - ); - } this.virtualScrollItemSizePx = this._rootFontSizePx * VIRTUAL_SCROLL_ITEM_SIZE_REM; this.virtualListHeightRem = diff --git a/projects/cps-ui-kit/src/lib/components/cps-button-toggle/cps-button-toggle.component.spec.ts b/projects/cps-ui-kit/src/lib/components/cps-button-toggle/cps-button-toggle.component.spec.ts new file mode 100644 index 00000000..b4ff43e1 --- /dev/null +++ b/projects/cps-ui-kit/src/lib/components/cps-button-toggle/cps-button-toggle.component.spec.ts @@ -0,0 +1,390 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { SimpleChange } from '@angular/core'; +import { + CpsButtonToggleComponent, + CpsButtonToggleOption +} from './cps-button-toggle.component'; +import { CPS_ROOT_FONT_SIZE_SERVICE } from '../../services/cps-root-font-size/cps-root-font-size.service'; + +const mockRootFontSizeService = { + fontSize: () => 16 +}; + +const OPTIONS: CpsButtonToggleOption[] = [ + { value: 'a', label: 'Alpha' }, + { value: 'b', label: 'Beta' }, + { value: 'c', label: 'Gamma' } +]; + +describe('CpsButtonToggleComponent', () => { + let component: CpsButtonToggleComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [CpsButtonToggleComponent], + providers: [ + { + provide: CPS_ROOT_FONT_SIZE_SERVICE, + useValue: mockRootFontSizeService + } + ] + }).compileComponents(); + + fixture = TestBed.createComponent(CpsButtonToggleComponent); + component = fixture.componentInstance; + fixture.componentRef.setInput('options', OPTIONS); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('default values', () => { + it('should have correct default input values', () => { + expect(component.label).toBe(''); + expect(component.ariaLabel).toBe(''); + expect(component.multiple).toBe(false); + expect(component.disabled).toBe(false); + expect(component.mandatory).toBe(true); + expect(component.equalWidths).toBe(true); + expect(component.optionTooltipPosition).toBe('bottom'); + expect(component.infoTooltip).toBe(''); + expect(component.infoTooltipClass).toBe('cps-tooltip-content'); + expect(component.infoTooltipMaxWidth).toBe('100%'); + expect(component.infoTooltipPersistent).toBe(false); + expect(component.infoTooltipPosition).toBe('top'); + expect(component.value).toBeUndefined(); + }); + }); + + describe('template', () => { + it('should render one button per option', () => { + const buttons = fixture.nativeElement.querySelectorAll( + 'button.cps-btn-toggle-content-option' + ); + expect(buttons.length).toBe(OPTIONS.length); + }); + + it('should show label element when label is set', () => { + fixture.componentRef.setInput('label', 'My Toggle'); + fixture.detectChanges(); + const label = fixture.nativeElement.querySelector( + '.cps-btn-toggle-label span' + ); + expect(label?.textContent?.trim()).toBe('My Toggle'); + }); + + it('should not show label element when label is empty', () => { + const label = fixture.nativeElement.querySelector( + '.cps-btn-toggle-label' + ); + expect(label).toBeNull(); + }); + + it('should set aria-label on role=group from ariaLabel', () => { + fixture.componentRef.setInput('ariaLabel', 'Toggle group'); + fixture.detectChanges(); + const group = fixture.nativeElement.querySelector('[role="group"]'); + expect(group.getAttribute('aria-label')).toBe('Toggle group'); + }); + + it('should prefer ariaLabel over label for role=group aria-label', () => { + fixture.componentRef.setInput('label', 'My Label'); + fixture.componentRef.setInput('ariaLabel', 'Aria Label'); + fixture.detectChanges(); + const group = fixture.nativeElement.querySelector('[role="group"]'); + expect(group.getAttribute('aria-label')).toBe('Aria Label'); + }); + + it('should fall back to label for role=group aria-label when ariaLabel is empty', () => { + fixture.componentRef.setInput('label', 'My Label'); + fixture.detectChanges(); + const group = fixture.nativeElement.querySelector('[role="group"]'); + expect(group.getAttribute('aria-label')).toBe('My Label'); + }); + + it('should mark selected option with aria-pressed="true"', () => { + fixture.componentRef.setInput('value', 'b'); + fixture.detectChanges(); + const buttons = fixture.nativeElement.querySelectorAll( + 'button.cps-btn-toggle-content-option' + ); + expect(buttons[0].getAttribute('aria-pressed')).toBe('false'); + expect(buttons[1].getAttribute('aria-pressed')).toBe('true'); + expect(buttons[2].getAttribute('aria-pressed')).toBe('false'); + }); + + it('should disable all buttons when component is disabled', () => { + fixture.componentRef.setInput('disabled', true); + fixture.detectChanges(); + const buttons = fixture.nativeElement.querySelectorAll( + 'button.cps-btn-toggle-content-option' + ); + buttons.forEach((btn: HTMLButtonElement) => { + expect(btn.disabled).toBe(true); + }); + }); + + it('should disable only the matching button when option.disabled is true', () => { + fixture.componentRef.setInput('options', [ + { value: 'a', label: 'Alpha', disabled: true }, + { value: 'b', label: 'Beta' } + ]); + fixture.detectChanges(); + const buttons = fixture.nativeElement.querySelectorAll( + 'button.cps-btn-toggle-content-option' + ); + expect(buttons[0].disabled).toBe(true); + expect(buttons[1].disabled).toBe(false); + }); + }); + + describe('updateValueOnClick - single select', () => { + it('should update value when clicking an option', () => { + const buttons = fixture.nativeElement.querySelectorAll( + 'button.cps-btn-toggle-content-option' + ); + buttons[1].click(); + expect(component.value).toBe('b'); + }); + + it('should emit valueChanged when clicking an option', () => { + jest.spyOn(component.valueChanged, 'emit'); + const buttons = fixture.nativeElement.querySelectorAll( + 'button.cps-btn-toggle-content-option' + ); + buttons[0].click(); + expect(component.valueChanged.emit).toHaveBeenCalledWith('a'); + }); + + it('should not change value when component is disabled', () => { + fixture.componentRef.setInput('value', 'a'); + fixture.componentRef.setInput('disabled', true); + fixture.detectChanges(); + component.updateValueOnClick('b'); + expect(component.value).toBe('a'); + }); + + it('should keep value when clicking same option and mandatory is true', () => { + fixture.componentRef.setInput('value', 'a'); + fixture.detectChanges(); + component.updateValueOnClick('a'); + expect(component.value).toBe('a'); + }); + + it('should deselect when clicking same option and mandatory is false', () => { + fixture.componentRef.setInput('mandatory', false); + fixture.componentRef.setInput('value', 'a'); + fixture.detectChanges(); + component.updateValueOnClick('a'); + expect(component.value).toBeUndefined(); + }); + + it('should select a different option when mandatory is false', () => { + fixture.componentRef.setInput('mandatory', false); + fixture.componentRef.setInput('value', 'a'); + fixture.detectChanges(); + component.updateValueOnClick('b'); + expect(component.value).toBe('b'); + }); + }); + + describe('updateValueOnClick - multiple select', () => { + beforeEach(() => { + fixture.componentRef.setInput('multiple', true); + fixture.detectChanges(); + }); + + it('should add values to selection', () => { + component.updateValueOnClick('a'); + component.updateValueOnClick('b'); + expect(component.value).toEqual(['a', 'b']); + }); + + it('should remove a value from selection', () => { + fixture.componentRef.setInput('value', ['a', 'b']); + fixture.detectChanges(); + component.updateValueOnClick('a'); + expect(component.value).toEqual(['b']); + }); + + it('should not remove last selected value when mandatory is true', () => { + fixture.componentRef.setInput('value', ['a']); + fixture.detectChanges(); + component.updateValueOnClick('a'); + expect(component.value).toEqual(['a']); + }); + + it('should remove last selected value when mandatory is false', () => { + fixture.componentRef.setInput('mandatory', false); + fixture.componentRef.setInput('value', ['a']); + fixture.detectChanges(); + component.updateValueOnClick('a'); + expect(component.value).toEqual([]); + }); + + it('should preserve options order in selection', () => { + component.updateValueOnClick('c'); + component.updateValueOnClick('a'); + expect(component.value).toEqual(['a', 'c']); + }); + + it('should emit valueChanged with array value', () => { + jest.spyOn(component.valueChanged, 'emit'); + component.updateValueOnClick('b'); + expect(component.valueChanged.emit).toHaveBeenCalledWith(['b']); + }); + + it('should initialize value to [] when multiple is true and no value is set', () => { + const newFixture = TestBed.createComponent(CpsButtonToggleComponent); + newFixture.componentRef.setInput('multiple', true); + newFixture.componentRef.setInput('options', OPTIONS); + newFixture.detectChanges(); + expect(newFixture.componentInstance.value).toEqual([]); + newFixture.destroy(); + }); + }); + + describe('ControlValueAccessor', () => { + it('should call registered onChange when value changes', () => { + const fn = jest.fn(); + component.registerOnChange(fn); + component.updateValueOnClick('b'); + expect(fn).toHaveBeenCalledWith('b'); + }); + + it('should call registered onTouched', () => { + const fn = jest.fn(); + component.registerOnTouched(fn); + component.onTouched(); + expect(fn).toHaveBeenCalled(); + }); + + it('should write value via writeValue', () => { + component.writeValue('c'); + expect(component.value).toBe('c'); + }); + + it('should not throw on setDisabledState', () => { + expect(() => component.setDisabledState(true)).not.toThrow(); + }); + }); + + describe('accessibility warnings', () => { + it('should log error when neither label nor ariaLabel is provided on the component', () => { + const consoleSpy = jest + .spyOn(console, 'error') + .mockImplementation(() => {}); + component.ngOnChanges({ + label: new SimpleChange('My Label', '', false), + ariaLabel: new SimpleChange('', '', false) + }); + expect(consoleSpy).toHaveBeenCalledWith( + expect.stringContaining('ariaLabel') + ); + consoleSpy.mockRestore(); + }); + + it('should not log error when label is set', () => { + const consoleSpy = jest + .spyOn(console, 'error') + .mockImplementation(() => {}); + fixture.componentRef.setInput('label', 'My Label'); + fixture.detectChanges(); + expect(consoleSpy).not.toHaveBeenCalled(); + consoleSpy.mockRestore(); + }); + + it('should not log error when ariaLabel is set', () => { + const consoleSpy = jest + .spyOn(console, 'error') + .mockImplementation(() => {}); + fixture.componentRef.setInput('ariaLabel', 'Accessible label'); + fixture.detectChanges(); + expect(consoleSpy).not.toHaveBeenCalled(); + consoleSpy.mockRestore(); + }); + + it('should log error when an option has no label and no ariaLabel', () => { + const consoleSpy = jest + .spyOn(console, 'error') + .mockImplementation(() => {}); + const badOptions = [{ value: 'x' }]; + component.options = badOptions; + component.ngOnChanges({ + options: new SimpleChange(OPTIONS, badOptions, false) + }); + expect(consoleSpy).toHaveBeenCalledWith( + expect.stringContaining('ariaLabel') + ); + consoleSpy.mockRestore(); + }); + + it('should not log error when all options have labels', () => { + const consoleSpy = jest + .spyOn(console, 'error') + .mockImplementation(() => {}); + const goodOptions = [{ value: 'x', label: 'X' }]; + component.options = goodOptions; + component.ngOnChanges({ + options: new SimpleChange(OPTIONS, goodOptions, false) + }); + expect(consoleSpy).not.toHaveBeenCalled(); + consoleSpy.mockRestore(); + }); + + it('should not log error when options use ariaLabel instead of label', () => { + const consoleSpy = jest + .spyOn(console, 'error') + .mockImplementation(() => {}); + const ariaOptions = [{ value: 'x', ariaLabel: 'X' }]; + component.options = ariaOptions; + component.ngOnChanges({ + options: new SimpleChange(OPTIONS, ariaOptions, false) + }); + expect(consoleSpy).not.toHaveBeenCalled(); + consoleSpy.mockRestore(); + }); + }); + + describe('equal widths', () => { + it('should not modify largestButtonWidthRem when equalWidths is false', () => { + component.largestButtonWidthRem = 5; + fixture.componentRef.setInput('equalWidths', false); + (component as any)._setEqualWidths(); + expect(component.largestButtonWidthRem).toBe(5); + }); + + it('should set largestButtonWidthRem to padding baseline when all option labels have offsetWidth=0', () => { + (component as any)._setEqualWidths(); + expect(component.largestButtonWidthRem).toBeCloseTo(1.625); + }); + + it('should add icon width and margin for options with both icon and label', () => { + fixture.componentRef.setInput('options', [ + { value: 'a', icon: 'home', label: 'Home' } + ]); + (component as any)._setEqualWidths(); + expect(component.largestButtonWidthRem).toBeCloseTo(3.125); + }); + + it('should add icon width without margin for icon-only options', () => { + fixture.componentRef.setInput('options', [ + { value: 'a', icon: 'home', ariaLabel: 'Home' } + ]); + (component as any)._setEqualWidths(); + expect(component.largestButtonWidthRem).toBeCloseTo(2.625); + }); + + it('should use the maximum width across all options', () => { + fixture.componentRef.setInput('options', [ + { value: 'a', label: 'Alpha' }, + { value: 'b', icon: 'home', label: 'Beta' } + ]); + (component as any)._setEqualWidths(); + expect(component.largestButtonWidthRem).toBeCloseTo(3.125); + }); + }); +}); diff --git a/projects/cps-ui-kit/src/lib/components/cps-button-toggle/cps-button-toggle.component.ts b/projects/cps-ui-kit/src/lib/components/cps-button-toggle/cps-button-toggle.component.ts index 1e967a46..80cccc11 100644 --- a/projects/cps-ui-kit/src/lib/components/cps-button-toggle/cps-button-toggle.component.ts +++ b/projects/cps-ui-kit/src/lib/components/cps-button-toggle/cps-button-toggle.component.ts @@ -1,8 +1,9 @@ -import { CommonModule, DOCUMENT, isPlatformBrowser } from '@angular/common'; +import { CommonModule, DOCUMENT } from '@angular/common'; import { ChangeDetectorRef, Component, EventEmitter, + inject, Inject, Input, OnChanges, @@ -11,11 +12,11 @@ import { Output, Renderer2, Self, - PLATFORM_ID, type SimpleChanges } from '@angular/core'; import { ControlValueAccessor, NgControl } from '@angular/forms'; import { isEqual } from 'lodash-es'; +import { CPS_ROOT_FONT_SIZE_SERVICE } from '../../services/cps-root-font-size/cps-root-font-size.service'; import { CheckOptionSelectedPipe } from '../../pipes/internal/check-option-selected.pipe'; import { CpsInfoCircleComponent } from '../cps-info-circle/cps-info-circle.component'; import { CpsIconComponent } from '../cps-icon/cps-icon.component'; @@ -159,12 +160,14 @@ export class CpsButtonToggleComponent largestButtonWidthRem = 0; - private _rootFontSizePx = 16; + private readonly _cpsRootFontSizeService = inject(CPS_ROOT_FONT_SIZE_SERVICE); + private get _rootFontSizePx(): number { + return this._cpsRootFontSizeService?.fontSize() ?? 16; + } constructor( @Self() @Optional() private _control: NgControl, @Inject(DOCUMENT) private document: Document, - @Inject(PLATFORM_ID) private platformId: object, private renderer: Renderer2, private cdr: ChangeDetectorRef ) { @@ -177,11 +180,6 @@ export class CpsButtonToggleComponent if (this.multiple && !this._value) { this._value = []; } - if (isPlatformBrowser(this.platformId)) { - this._rootFontSizePx = parseFloat( - getComputedStyle(this.document.documentElement).fontSize || '16' - ); - } if (this.document?.fonts?.ready) { this.document.fonts.ready.then(() => { this._setEqualWidths(); diff --git a/projects/cps-ui-kit/src/lib/directives/cps-tooltip/cps-tooltip.directive.spec.ts b/projects/cps-ui-kit/src/lib/directives/cps-tooltip/cps-tooltip.directive.spec.ts index 6dd2bb30..9b97d193 100644 --- a/projects/cps-ui-kit/src/lib/directives/cps-tooltip/cps-tooltip.directive.spec.ts +++ b/projects/cps-ui-kit/src/lib/directives/cps-tooltip/cps-tooltip.directive.spec.ts @@ -7,12 +7,16 @@ import { import { CpsTooltipDirective } from './cps-tooltip.directive'; import { Component } from '@angular/core'; import { By } from '@angular/platform-browser'; +import { CPS_ROOT_FONT_SIZE_SERVICE } from '../../services/cps-root-font-size/cps-root-font-size.service'; @Component({ template: `
`, imports: [CpsTooltipDirective] }) class MaliciousTooltipComponent {} +const mockRootFontSizeService = { + fontSize: () => 16 +}; @Component({ template: `
`, @@ -29,7 +33,13 @@ describe('CpsTooltipDirective', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [] + imports: [], + providers: [ + { + provide: CPS_ROOT_FONT_SIZE_SERVICE, + useValue: mockRootFontSizeService + } + ] }).compileComponents(); }); diff --git a/projects/cps-ui-kit/src/lib/directives/cps-tooltip/cps-tooltip.directive.ts b/projects/cps-ui-kit/src/lib/directives/cps-tooltip/cps-tooltip.directive.ts index 82b1e52b..ac3e3834 100644 --- a/projects/cps-ui-kit/src/lib/directives/cps-tooltip/cps-tooltip.directive.ts +++ b/projects/cps-ui-kit/src/lib/directives/cps-tooltip/cps-tooltip.directive.ts @@ -5,13 +5,13 @@ import { inject, input, OnDestroy, - OnInit, SecurityContext, PLATFORM_ID } from '@angular/core'; import { convertSize, parseSize } from '../../utils/internal/size-utils'; import { DOCUMENT, isPlatformBrowser } from '@angular/common'; import { DomSanitizer } from '@angular/platform-browser'; +import { CPS_ROOT_FONT_SIZE_SERVICE } from '../../services/cps-root-font-size/cps-root-font-size.service'; /** * CpsTooltipPosition is used to define the position of the tooltip. @@ -42,7 +42,7 @@ export type CpsTooltipOpenOn = 'hover' | 'click' | 'focus'; '(window:resize)': 'onPageResize()' } }) -export class CpsTooltipDirective implements OnInit, OnDestroy { +export class CpsTooltipDirective implements OnDestroy { /** * Tooltip text or html to show. * @group Props @@ -117,9 +117,13 @@ export class CpsTooltipDirective implements OnInit, OnDestroy { private _showTimeout?: ReturnType; private _hideTimeout?: ReturnType; private _ariaTarget?: HTMLElement; - private _rootFontSizePx = 16; private window: Window; + private readonly _cpsRootFontSizeService = inject(CPS_ROOT_FONT_SIZE_SERVICE); + private get _rootFontSizePx(): number { + return this._cpsRootFontSizeService?.fontSize() ?? 16; + } + private _elementRef = inject(ElementRef); private _document = inject(DOCUMENT); private _platformId = inject(PLATFORM_ID); @@ -129,14 +133,6 @@ export class CpsTooltipDirective implements OnInit, OnDestroy { this.window = this._document.defaultView as Window; } - ngOnInit(): void { - if (isPlatformBrowser(this._platformId)) { - this._rootFontSizePx = parseFloat( - getComputedStyle(this._document.documentElement).fontSize || '16' - ); - } - } - ngOnDestroy(): void { clearTimeout(this._showTimeout); clearTimeout(this._hideTimeout); diff --git a/projects/cps-ui-kit/src/lib/services/cps-dialog/internal/components/cps-dialog/cps-dialog.component.spec.ts b/projects/cps-ui-kit/src/lib/services/cps-dialog/internal/components/cps-dialog/cps-dialog.component.spec.ts index bce19d73..2f54500f 100644 --- a/projects/cps-ui-kit/src/lib/services/cps-dialog/internal/components/cps-dialog/cps-dialog.component.spec.ts +++ b/projects/cps-ui-kit/src/lib/services/cps-dialog/internal/components/cps-dialog/cps-dialog.component.spec.ts @@ -11,10 +11,15 @@ import { DomHandler } from 'primeng/dom'; import { CpsDialogComponent } from './cps-dialog.component'; import { CpsDialogConfig } from '../../../utils/cps-dialog-config'; import { CpsDialogRef } from '../../../utils/cps-dialog-ref'; +import { CPS_ROOT_FONT_SIZE_SERVICE } from '../../../../cps-root-font-size/cps-root-font-size.service'; @Component({ template: '' }) class TestChildComponent {} +const mockRootFontSizeService = { + fontSize: () => 16 +}; + describe('CpsDialogComponent', () => { let component: CpsDialogComponent; let fixture: ComponentFixture; @@ -41,6 +46,10 @@ describe('CpsDialogComponent', () => { providers: [ { provide: CpsDialogRef, useValue: mockDialogRef }, { provide: CpsDialogConfig, useValue: config }, + { + provide: CPS_ROOT_FONT_SIZE_SERVICE, + useValue: mockRootFontSizeService + }, PrimeNG ] }); diff --git a/projects/cps-ui-kit/src/lib/services/cps-dialog/internal/components/cps-dialog/cps-dialog.component.ts b/projects/cps-ui-kit/src/lib/services/cps-dialog/internal/components/cps-dialog/cps-dialog.component.ts index 9d52d6e0..21644770 100644 --- a/projects/cps-ui-kit/src/lib/services/cps-dialog/internal/components/cps-dialog/cps-dialog.component.ts +++ b/projects/cps-ui-kit/src/lib/services/cps-dialog/internal/components/cps-dialog/cps-dialog.component.ts @@ -43,6 +43,7 @@ import { CpsButtonComponent } from '../../../../../components/cps-button/cps-but import { CpsInfoCircleComponent } from '../../../../../components/cps-info-circle/cps-info-circle.component'; import { CpsIconComponent } from '../../../../../components/cps-icon/cps-icon.component'; import { CPS_FOCUS_SERVICE } from '../../../../cps-focus/cps-focus.service'; +import { CPS_ROOT_FONT_SIZE_SERVICE } from '../../../../cps-root-font-size/cps-root-font-size.service'; const showAnimation = animation([ style({ transform: '{{transform}}', opacity: 0 }), @@ -140,9 +141,12 @@ export class CpsDialogComponent implements OnInit, AfterViewInit, OnDestroy { _resizeEnded = new EventEmitter(); _maximizedStateChanged = new EventEmitter(); - private _rootFontSizePx = 16; private _openedByKeyboard = false; private readonly _cpsFocusService = inject(CPS_FOCUS_SERVICE); + private readonly _cpsRootFontSizeService = inject(CPS_ROOT_FONT_SIZE_SERVICE); + private get _rootFontSizePx(): number { + return this._cpsRootFontSizeService?.fontSize() ?? 16; + } get ariaLabel(): string | null { if (this.config.ariaLabelledBy) return null; @@ -232,11 +236,6 @@ export class CpsDialogComponent implements OnInit, AfterViewInit, OnDestroy { ) {} ngOnInit(): void { - if (isPlatformBrowser(this.platformId)) { - this._rootFontSizePx = parseFloat( - getComputedStyle(this.document.documentElement).fontSize || '16' - ); - } if ( !this.config.ariaLabel?.trim() && !this.config.ariaLabelledBy?.trim() &&