diff --git a/projects/igniteui-angular/src/lib/checkbox/checkbox.component.ts b/projects/igniteui-angular/src/lib/checkbox/checkbox.component.ts index 299a765a7f2..8e5fc3c53c0 100644 --- a/projects/igniteui-angular/src/lib/checkbox/checkbox.component.ts +++ b/projects/igniteui-angular/src/lib/checkbox/checkbox.component.ts @@ -12,13 +12,15 @@ import { Renderer2, Optional, Self, - booleanAttribute + booleanAttribute, + inject, + DestroyRef } from '@angular/core'; import { ControlValueAccessor, NgControl, Validators } from '@angular/forms'; import { IgxRippleDirective } from '../directives/ripple/ripple.directive'; import { IBaseEventArgs, mkenum } from '../core/utils'; import { EditorProvider, EDITOR_PROVIDER } from '../core/edit-provider'; -import { noop, Subject } from 'rxjs'; +import { noop, Subject, Subscription } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { IgxTheme, ThemeService } from '../services/theme/theme.service'; @@ -287,6 +289,58 @@ export class IgxCheckboxComponent implements EditorProvider, AfterViewInit, Cont @HostBinding('class.igx-checkbox') public cssClass = 'igx-checkbox'; + /** + * Returns if the component is of type `material`. + * + * @example + * ```typescript + * let checkbox = this.checkbox.material; + * ``` + */ + @HostBinding('class.igx-checkbox--material') + protected get material() { + return this.theme === 'material'; + } + + /** + * Returns if the component is of type `indigo`. + * + * @example + * ```typescript + * let checkbox = this.checkbox.indigo; + * ``` + */ + @HostBinding('class.igx-checkbox--indigo') + protected get indigo() { + return this.theme === 'indigo'; + } + + /** + * Returns if the component is of type `bootstrap`. + * + * @example + * ```typescript + * let checkbox = this.checkbox.bootstrap; + * ``` + */ + @HostBinding('class.igx-checkbox--bootstrap') + protected get bootstrap() { + return this.theme === 'bootstrap'; + } + + /** + * Returns if the component is of type `fluent`. + * + * @example + * ```typescript + * let checkbox = this.checkbox.fluent; + * ``` + */ + @HostBinding('class.igx-checkbox--fluent') + protected get fluent() { + return this.theme === 'fluent'; + } + /** * Sets/gets whether the checkbox component is on focus. * Default value is `false`. @@ -410,30 +464,38 @@ export class IgxCheckboxComponent implements EditorProvider, AfterViewInit, Cont * @internal */ public inputId = `${this.id}-input`; + /** * @hidden */ protected _onChangeCallback: (_: any) => void = noop; + /** * @hidden */ private _onTouchedCallback: () => void = noop; + /** * @hidden * @internal */ protected _checked = false; + /** * @hidden * @internal */ - private _required = false; + protected theme: IgxTheme; /** * @hidden * @internal */ - protected theme: IgxTheme = 'material'; + private _required = false; + private elRef = inject(ElementRef); + private _theme$ = new Subject(); + private _subscription: Subscription; + private destroyRef = inject(DestroyRef); constructor( protected cdr: ChangeDetectorRef, @@ -441,11 +503,18 @@ export class IgxCheckboxComponent implements EditorProvider, AfterViewInit, Cont protected themeService: ThemeService, @Optional() @Self() public ngControl: NgControl, ) { - this.theme = this.themeService?.globalTheme; - if (this.ngControl !== null) { this.ngControl.valueAccessor = this; } + + this.theme = this.themeService.globalTheme; + + this._subscription = this._theme$.asObservable().subscribe(value => { + this.theme = value as IgxTheme; + this.cdr.detectChanges(); + }); + + this.destroyRef.onDestroy(() => this._subscription.unsubscribe()); } /** @@ -461,6 +530,13 @@ export class IgxCheckboxComponent implements EditorProvider, AfterViewInit, Cont this.cdr.detectChanges(); } } + + const theme = this.themeService.getComponentTheme(this.elRef); + + if (theme) { + this._theme$.next(theme); + this.cdr.markForCheck(); + } } /** @hidden @internal */ diff --git a/projects/igniteui-angular/src/lib/core/styles/components/checkbox/_checkbox-component.scss b/projects/igniteui-angular/src/lib/core/styles/components/checkbox/_checkbox-component.scss index 1704210eb47..2bea021daa0 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/checkbox/_checkbox-component.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/checkbox/_checkbox-component.scss @@ -18,17 +18,9 @@ @extend %cbx-ripple--hover !optional; } - @include e(composite) { - @extend %cbx-composite--hover !optional; - } - @include e(composite-mark) { @extend %cbx-composite-mark--fluent !optional; } - - @include e(label) { - @extend %cbx-label--hover !optional; - } } &:active { @@ -68,6 +60,32 @@ @extend %cbx-ripple !optional; } + @include m(bootstrap) { + @include e(composite) { + &:hover { + @extend %cbx-composite--hover !optional; + } + } + } + + @include m(indigo) { + @include e(composite) { + &:hover { + @extend %cbx-composite--hover !optional; + } + } + + @include e(composite-mark) { + @extend %cbx-composite-mark-indigo !optional; + } + + @include e(label) { + &:hover { + @extend %cbx-label--hover !optional; + } + } + } + @include m(invalid) { @include e(composite) { @extend %cbx-composite--invalid !optional; @@ -127,26 +145,54 @@ } &:hover { - @extend %igx-checkbox--focused-hovered !optional; - @include e(ripple) { @extend %cbx-ripple--focused !optional; } } } + @include mx(indigo, focused) { + @extend %igx-checkbox--focused-indigo !optional; + } + + @include mx(fluent, focused) { + @extend %igx-checkbox--focused-fluent !optional; + } + + @include mx(bootstrap, focused) { + @extend %igx-checkbox--focused-bootstrap !optional; + + &:hover { + @extend %igx-checkbox--focused-hovered !optional; + } + } + + @include mx(indigo, focused, checked) { + @extend %igx-checkbox--focused-checked-indigo !optional; + } + + @include mx(bootstrap, focused, checked) { + @extend %igx-checkbox--focused-checked-bootstrap !optional; + } + @include mx(focused, checked) { @extend %igx-checkbox--focused-checked !optional; } @include mx(focused, invalid) { - @extend %igx-checkbox--focused-invalid !optional; - @include e(ripple) { @extend %cbx-ripple--focused-invalid !optional; } } + @include mx(indigo, focused, invalid) { + @extend %igx-checkbox--focused-invalid-indigo !optional; + } + + @include mx(bootstrap, focused, invalid) { + @extend %igx-checkbox--focused-invalid-bootstrap !optional; + } + @include m(indeterminate) { @extend %igx-checkbox--indeterminate !optional; @@ -178,6 +224,18 @@ } } + @include mx(indigo, indeterminate) { + @extend %igx-checkbox--indeterminate-indigo !optional; + } + + @include mx(fluent, indeterminate) { + @extend %igx-checkbox--indeterminate-fluent !optional; + } + + @include mx(material, indeterminate) { + @extend %igx-checkbox--indeterminate-material !optional; + } + @include mx(invalid, indeterminate) { @extend %igx-checkbox--indeterminate--invalid !optional; @@ -188,8 +246,12 @@ } } - @include mx(focused, indeterminate) { - @extend %igx-checkbox--focused-checked !optional; + @include mx(indigo, focused, indeterminate) { + @extend %igx-checkbox--focused-checked-indigo !optional; + } + + @include mx(bootstrap, focused, indeterminate) { + @extend %igx-checkbox--focused-checked-bootstrap !optional; } @include m(checked) { diff --git a/projects/igniteui-angular/src/lib/core/styles/components/checkbox/_checkbox-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/checkbox/_checkbox-theme.scss index 657e87b9d33..ff07156f7f1 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/checkbox/_checkbox-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/checkbox/_checkbox-theme.scss @@ -152,9 +152,9 @@ ), $variant); $mark-offset: map.get(( - 'material': .5px, + 'material': 0, 'fluent': -1px, - 'bootstrap': .5px, + 'bootstrap': 1px, 'indigo': 1px, ), $variant); @@ -223,9 +223,7 @@ } %cbx-composite--hover { - @if $variant == 'indigo' or $variant == 'bootstrap' { - border-color: var-get($theme, 'empty-color-hover'); - } + border-color: var-get($theme, 'empty-color-hover'); } %cbx-composite--x { @@ -303,30 +301,30 @@ fill: none; opacity: 0; z-index: 1; + } - @if $variant == 'material' { - inset-inline-start: -.5px; - } + %cbx-composite-mark-material { + inset-inline-start: -.5px; + } - @if $variant == 'indigo' { - stroke: unset; - stroke-linecap: unset; - stroke-width: unset; - stroke-dasharray: unset; - stroke-dashoffset: unset; - fill: var-get($theme, 'tick-color'); - transition: none !important; + %cbx-composite-mark-indigo { + stroke: unset; + stroke-linecap: unset; + stroke-width: unset; + stroke-dasharray: unset; + stroke-dashoffset: unset; + fill: var-get($theme, 'tick-color'); + transition: none !important; - rect { - fill: none; - } + rect { + fill: none; } } %igx-checkbox--indeterminate { %cbx-composite-mark { top: $mark-offset; - inset-inline-start: $mark-offset; + margin-inline-start: $mark-offset; } &:hover { @@ -344,55 +342,55 @@ } } } + } - @if $variant == 'material' { - %cbx-composite--x--disabled { - border-color: var-get($theme, 'disabled-indeterminate-color'); - background: var-get($theme, 'disabled-indeterminate-color'); + %igx-checkbox--indeterminate-indigo { + %cbx-composite-mark { + fill: none; + stroke-dashoffset: unset !important; + transform: none !important; + + rect { + fill: var-get($theme, 'tick-color'); + opacity: 1; } } + } - @if $variant == 'fluent' { - %cbx-composite-mark { - stroke: transparent; - } + %igx-checkbox--indeterminate-fluent { + %cbx-composite-mark { + stroke: transparent; + } - %cbx-composite { - background: transparent; + %cbx-composite { + background: transparent; - &::before { - content: ''; - position: absolute; - top: calc($size / 2 - rem(6px)); - inset-inline-start: calc($size / 2 - rem(6px)); - width: rem(10px); - height: rem(10px); - border-radius: border-radius(rem(2px)); - background: var-get($theme, 'fill-color'); - z-index: 1; - } + &::before { + content: ''; + position: absolute; + top: calc($size / 2 - rem(6px)); + inset-inline-start: calc($size / 2 - rem(6px)); + width: rem(10px); + height: rem(10px); + border-radius: border-radius(rem(2px)); + background: var-get($theme, 'fill-color'); + z-index: 1; } + } - %cbx-composite--x--disabled { - background: transparent; + %cbx-composite--x--disabled { + background: transparent; - &::before { - background: var-get($theme, 'disabled-color'); - } + &::before { + background: var-get($theme, 'disabled-color'); } } + } - @if $variant == 'indigo' { - %cbx-composite-mark { - fill: none; - stroke-dashoffset: unset !important; - transform: none !important; - - rect { - fill: var-get($theme, 'tick-color'); - opacity: 1; - } - } + %igx-checkbox--indeterminate-material { + %cbx-composite--x--disabled { + border-color: var-get($theme, 'disabled-indeterminate-color'); + background: var-get($theme, 'disabled-indeterminate-color'); } } @@ -489,9 +487,7 @@ } %cbx-label--hover { - @if $variant == 'indigo' { - color: var-get($theme, 'label-color-hover'); - } + color: var-get($theme, 'label-color-hover'); } %cbx-label-pos--before, @@ -550,75 +546,67 @@ background: var-get($theme, 'error-color'); } - %igx-checkbox--focused { - @if $variant == 'fluent' { - position: relative; - $focus-outline-offset: rem(2px); - - &::after { - content: ''; - position: absolute; - inset: -$focus-outline-offset; - box-shadow: 0 0 0 rem(1px) var-get($theme, 'focus-outline-color'); - } + %igx-checkbox--focused-indigo { + %cbx-composite { + border-radius: var-get($theme, 'border-radius'); + box-shadow: 0 0 0 rem(3px) var-get($theme, 'focus-outline-color'); } + } - @if $variant == 'bootstrap' { - %cbx-composite { - border-radius: var-get($theme, 'border-radius'); - border-color: color($color: 'primary', $variant: 200); - box-shadow: 0 0 0 rem(4px) var-get($theme, 'focus-outline-color'); - } + %igx-checkbox--focused-fluent { + position: relative; + $focus-outline-offset: rem(2px); + + &::after { + content: ''; + position: absolute; + inset: -$focus-outline-offset; + box-shadow: 0 0 0 rem(1px) var-get($theme, 'focus-outline-color'); } + } - @if $variant == 'indigo' { - %cbx-composite { - border-radius: var-get($theme, 'border-radius'); - box-shadow: 0 0 0 rem(3px) var-get($theme, 'focus-outline-color'); - } + %igx-checkbox--focused-bootstrap { + %cbx-composite { + border-radius: var-get($theme, 'border-radius'); + border-color: color($color: 'primary', $variant: 200); + box-shadow: 0 0 0 rem(4px) var-get($theme, 'focus-outline-color'); } } %igx-checkbox--focused-hovered { - @if $variant == 'bootstrap' { - %cbx-composite { - border-color: color($color: 'primary', $variant: 300); - } + %cbx-composite { + border-color: color($color: 'primary', $variant: 300); } } - %igx-checkbox--focused-checked { - @if $variant == 'indigo' { - %cbx-composite { - border-radius: var-get($theme, 'border-radius'); - box-shadow: 0 0 0 rem(3px) var-get($theme, 'focus-outline-color-focused'); - } + %igx-checkbox--focused-checked-indigo { + %cbx-composite { + border-radius: var-get($theme, 'border-radius'); + box-shadow: 0 0 0 rem(3px) var-get($theme, 'focus-outline-color-focused'); } + } - @if $variant == 'bootstrap' { - %cbx-composite { - border-color: transparent; - } + %igx-checkbox--focused-checked-bootstrap { + %cbx-composite { + border-color: transparent; } } - %igx-checkbox--focused-invalid { - @if $variant == 'bootstrap' { - %cbx-composite { - border-color: var-get($theme, 'error-color'); - box-shadow: 0 0 0 rem(4px) var-get($theme, 'focus-outline-color-error'); - } + %igx-checkbox--focused-invalid-indigo { + %cbx-composite { + box-shadow: 0 0 0 rem(3px) var-get($theme, 'focus-outline-color-error'); + } + } - &:hover { - %cbx-composite { - border-color: var-get($theme, 'error-color-hover'); - } - } + %igx-checkbox--focused-invalid-bootstrap { + %cbx-composite { + border-color: var-get($theme, 'error-color'); + box-shadow: 0 0 0 rem(4px) var-get($theme, 'focus-outline-color-error'); } - @if $variant == 'indigo' { + &:hover { %cbx-composite { - box-shadow: 0 0 0 rem(3px) var-get($theme, 'focus-outline-color-error'); + border-color: var-get($theme, 'error-color-hover'); } } }