Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ describe('IgxButtonGroup', () => {

expect(btnGroupInstance.selected.emit).not.toHaveBeenCalled();

btnGroupInstance.buttons[1].select();
btnGroupInstance.buttons[1].selected = true;
fixture.detectChanges();

expect(btnGroupInstance.selected.emit).not.toHaveBeenCalled();
Expand All @@ -126,16 +126,16 @@ describe('IgxButtonGroup', () => {
fixture.detectChanges();

const btnGroupInstance = fixture.componentInstance.buttonGroup;
btnGroupInstance.buttons[0].select();
btnGroupInstance.buttons[1].select();
btnGroupInstance.buttons[0].selected = true;
btnGroupInstance.buttons[1].selected = true;
spyOn(btnGroupInstance.deselected, 'emit');

btnGroupInstance.ngAfterViewInit();
fixture.detectChanges();

expect(btnGroupInstance.deselected.emit).not.toHaveBeenCalled();

btnGroupInstance.buttons[1].deselect();
btnGroupInstance.buttons[1].selected = false;
fixture.detectChanges();

expect(btnGroupInstance.deselected.emit).not.toHaveBeenCalled();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,8 @@ export class IgxButtonGroupComponent implements AfterViewInit, OnDestroy {
return;
}

const button = this.buttons[index];
button.select();
this.buttons[index].selected = true;
this.updateSelected(index);
}

/**
Expand Down Expand Up @@ -398,8 +398,8 @@ export class IgxButtonGroupComponent implements AfterViewInit, OnDestroy {
return;
}

const button = this.buttons[index];
button.deselect();
this.buttons[index].selected = false;
this.updateDeselected(index);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
import {
Directive,
ElementRef,
EventEmitter,
HostBinding,
HostListener,
Input,
Output,
booleanAttribute,
inject,
AfterViewInit,
OnDestroy
} from '@angular/core';
import { PlatformUtil } from 'igniteui-angular/core';
import { animationFrameScheduler, Subscription } from 'rxjs';
import { Directive, ElementRef, Input, booleanAttribute, inject, AfterViewInit, signal, EventEmitter, Output} from '@angular/core';
import { IgxFocusRingDirective } from '../focus-ring/focus-ring.directive';


export const IgxBaseButtonType = {
Flat: 'flat',
Expand All @@ -21,126 +9,53 @@ export const IgxBaseButtonType = {
} as const;


@Directive()
export abstract class IgxButtonBaseDirective implements AfterViewInit, OnDestroy {
private _platformUtil = inject(PlatformUtil);
public element = inject(ElementRef);
private _viewInit = false;
private _animationScheduler: Subscription;
@Directive({
host: {
'role': 'button',
'[attr.disabled]': '_disabled() || null',
'[class.igx-button--focused]': '_hasKeyboardFocus()',
'[class.igx-button--disabled]': '_disabled()',
'[style.--_init-transition]': '_hasRendered() ? null : "0s"',
'[style.transition]': '_hasRendered() ? "var(--_button-transition)" : "none"',
'(click)': 'buttonClick.emit($event)',
},
hostDirectives: [IgxFocusRingDirective]
})
export abstract class IgxButtonBaseDirective implements AfterViewInit {
protected readonly _element = inject<ElementRef<HTMLElement>>(ElementRef);
protected readonly _hasKeyboardFocus = inject(IgxFocusRingDirective).hasKeyboardFocus;

/**
* Emitted when the button is clicked.
*/
@Output()
public buttonClick = new EventEmitter<any>();
protected readonly _hasRendered = signal(false);
protected readonly _disabled = signal(false);

/**
* Sets/gets the `role` attribute.
* Gets or sets whether the button is disabled.
*
* @example
* ```typescript
* this.button.role = 'navbutton';
* let buttonRole = this.button.role;
* ```
*/
@HostBinding('attr.role')
public role = 'button';

/**
* @hidden
* @internal
*/
@HostListener('click', ['$event'])
public onClick(ev: MouseEvent) {
this.buttonClick.emit(ev);
this.focused = false;
}

/**
* @hidden
* @internal
*/
@HostListener('blur')
protected onBlur() {
this.focused = false;
}

/**
* Sets/gets whether the button component is on focus.
* Default value is `false`.
* ```typescript
* this.button.focus = true;
* ```
* ```typescript
* let isFocused = this.button.focused;
* ```html
* <button type="button" igxButton="flat" [disabled]="isDisabled"></button>
* ```
*/
@HostBinding('class.igx-button--focused')
protected focused = false;

/**
* Enables/disables the button.
*
* @example
* ```html
* <button igxButton="fab" disabled></button>
* ```
*/
@Input({ transform: booleanAttribute })
@HostBinding('class.igx-button--disabled')
public disabled = false;

/**
* @hidden
* @internal
*/
@HostBinding('attr.disabled')
public get disabledAttribute() {
return this.disabled || null;
}

protected constructor() {
// In browser, set via native API for immediate effect (no-op on server).
// In SSR there is no paint, so there’s no visual rendering or transitions to suppress.
// Fix style flickering https://github.com/IgniteUI/igniteui-angular/issues/14759
if (this._platformUtil.isBrowser) {
this.element.nativeElement.style.setProperty('--_init-transition', '0s');
this.element.nativeElement.style.setProperty('transition', 'none');
}
public set disabled(value: boolean) {
this._disabled.set(value);
}

public ngAfterViewInit(): void {
if (this._platformUtil.isBrowser && !this._viewInit) {
this._viewInit = true;

this._animationScheduler = animationFrameScheduler.schedule(() => {
this.element.nativeElement.style.removeProperty('--_init-transition');
this.element.nativeElement.style.setProperty('transition', 'var(--_button-transition)');
});
}
public get disabled(): boolean {
return this._disabled();
}

public ngOnDestroy(): void {
if (this._animationScheduler) {
this._animationScheduler.unsubscribe();
}
}
/** Emitted when the button is clicked. */
@Output()
public readonly buttonClick = new EventEmitter<MouseEvent>();

/**
* @hidden
* @internal
*/
@HostListener('keyup', ['$event'])
protected updateOnKeyUp(event: KeyboardEvent) {
if (event.key === "Tab") {
this.focused = true;
}
/** Returns the underlying DOM element. */
public get nativeElement(): HTMLButtonElement {
return this._element.nativeElement as HTMLButtonElement;
}

/**
* Returns the underlying DOM element.
*/
public get nativeElement() {
return this.element.nativeElement;
public ngAfterViewInit(): void {
// FUOC workaround - ensures that the transition is only applied after the initial render
this._hasRendered.set(true);
}
}
Loading
Loading