diff --git a/playwright/cps-accessibility.spec.ts b/playwright/cps-accessibility.spec.ts index 0fb58f96..a91e14a5 100644 --- a/playwright/cps-accessibility.spec.ts +++ b/playwright/cps-accessibility.spec.ts @@ -148,15 +148,15 @@ const components: ComponentEntry[] = [ // }, { route: '/radio-group', name: 'Radio', selector: 'cps-radio-group' }, // { route: '/scheduler', name: 'Scheduler', selector: 'cps-scheduler' }, - // { - // route: '/select', - // name: 'Select', - // selector: ['cps-select', '.cps-select-options-menu'], - // setup: async (page) => { - // await page.waitForSelector('cps-select'); - // await page.locator('cps-select').first().click(); - // } - // }, + { + route: '/select', + name: 'Select', + selector: ['cps-select', '.cps-select-options-menu'], + setup: async (page) => { + await page.waitForSelector('cps-select'); + await page.locator('cps-select').first().click(); + } + }, { route: '/sidebar-menu', name: 'Sidebar menu', diff --git a/projects/composition/src/app/api-data/cps-select.json b/projects/composition/src/app/api-data/cps-select.json index 20555ccb..5640b67f 100644 --- a/projects/composition/src/app/api-data/cps-select.json +++ b/projects/composition/src/app/api-data/cps-select.json @@ -13,6 +13,14 @@ "default": "", "description": "Label of the select component." }, + { + "name": "ariaLabel", + "optional": false, + "readonly": false, + "type": "string", + "default": "", + "description": "Aria label for the select component, used for accessibility, it takes precedence over label." + }, { "name": "placeholder", "optional": false, @@ -186,7 +194,7 @@ "optional": false, "readonly": false, "type": "iconSizeType", - "default": "18px", + "default": "1.125rem", "description": "Size of icon before input value." }, { diff --git a/projects/composition/src/app/pages/autocomplete-page/autocomplete-page.component.html b/projects/composition/src/app/pages/autocomplete-page/autocomplete-page.component.html index 6bc8b53a..d367bc28 100644 --- a/projects/composition/src/app/pages/autocomplete-page/autocomplete-page.component.html +++ b/projects/composition/src/app/pages/autocomplete-page/autocomplete-page.component.html @@ -160,7 +160,7 @@ optionValue="val" optionInfo="ticker" placeholder="Enter a company" - hint="This autocomplete has a fixed width of 500px" + hint="This autocomplete has a fixed width of 31.25rem" [clearable]="true" [multiple]="true" [closableChips]="false" diff --git a/projects/composition/src/app/pages/autocomplete-page/autocomplete-page.examples.ts b/projects/composition/src/app/pages/autocomplete-page/autocomplete-page.examples.ts index 0803205e..96e6f66b 100644 --- a/projects/composition/src/app/pages/autocomplete-page/autocomplete-page.examples.ts +++ b/projects/composition/src/app/pages/autocomplete-page/autocomplete-page.examples.ts @@ -181,7 +181,7 @@ onMultiInputChanged(val: string): void { optionValue="val" optionInfo="ticker" placeholder="Enter a company" - hint="This autocomplete has a fixed width of 500px" + hint="This autocomplete has a fixed width of 31.25rem" [clearable]="true" [multiple]="true" [closableChips]="false" diff --git a/projects/composition/src/app/pages/radio-page/radio-page.component.html b/projects/composition/src/app/pages/radio-page/radio-page.component.html index 9f118feb..ad0b037c 100644 --- a/projects/composition/src/app/pages/radio-page/radio-page.component.html +++ b/projects/composition/src/app/pages/radio-page/radio-page.component.html @@ -52,6 +52,7 @@
On the of every month(s) at :
@if (prefixIcon) { } - @if ( - (!multiple && !isEmptyValue()) || (value?.length > 0 && multiple) - ) { + @if (hasSelectedValue()) {
@if (!multiple) { @@ -159,11 +158,12 @@ class="cps-autocomplete-box-clear-icon" [ngClass]="{ 'cps-autocomplete-box-clear-icon-hidden': - !persistentClear && - (!multiple || !value?.length) && - (multiple || isEmptyValue()) + !persistentClear && !hasSelectedValue() }"> - + } @if (showChevron && options.length) { @@ -178,6 +178,7 @@ " [tabindex]="disabled ? -1 : 0"> @@ -240,7 +241,9 @@ [attr.aria-posinset]="1" [attr.aria-selected]="value?.length === options.length" [class.allselected]="value?.length === options.length" - [class.highlighten]="optionHighlightedIndex === 0" + [class.highlighten]=" + isArrowNavigating && optionHighlightedIndex === 0 + " (mousedown)="$event.preventDefault()" (click)="toggleAll()"> @@ -331,11 +334,7 @@ [attr.aria-required]="isRequired || null" [ngClass]="inputClass" [ngStyle]="inputStyle" - [placeholder]=" - (!multiple && isEmptyValue()) || (value?.length < 1 && multiple) - ? placeholder - : '' - " + [placeholder]="!hasSelectedValue() ? placeholder : ''" (input)="filterOptions($event)" (keydown)="onInputKeyDown($event)" [(ngModel)]="inputText" @@ -355,6 +354,7 @@ (mousedown)="$event.preventDefault()" (click)="onOptionClick(item)" [class.highlighten]=" + isArrowNavigating && itemIndex === optionHighlightedIndex - (isSelectAllVisible ? 1 : 0) " [attr.aria-selected]=" diff --git a/projects/cps-ui-kit/src/lib/components/cps-autocomplete/cps-autocomplete.component.scss b/projects/cps-ui-kit/src/lib/components/cps-autocomplete/cps-autocomplete.component.scss index bd38ecd0..664aae00 100644 --- a/projects/cps-ui-kit/src/lib/components/cps-autocomplete/cps-autocomplete.component.scss +++ b/projects/cps-ui-kit/src/lib/components/cps-autocomplete/cps-autocomplete.component.scss @@ -141,6 +141,7 @@ $hover-transition-duration: 0.2s; outline: none; font-family: inherit; &::placeholder { + user-select: none; color: $autocomplete-placeholder-color; font-style: italic; opacity: 1; /* Firefox */ 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 cd88ebcf..af324b38 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 @@ -195,24 +195,24 @@ describe('CpsAutocompleteComponent', () => { it('should allow options menu to close with ESCAPE key when validating', () => { fixture.componentRef.setInput('validating', true); - const onBlurStub = jest.spyOn(component, 'onBlur'); + jest.spyOn(component, 'clearInput'); fixture.detectChanges(); const result = component.onBeforeOptionsHidden( CpsMenuHideReason.KEYDOWN_ESCAPE ); expect(result).toBe(undefined); - expect(onBlurStub).toHaveBeenCalledTimes(1); + expect(component.clearInput).toHaveBeenCalled(); }); it('should allow options menu to close with TAB key when validating', () => { fixture.componentRef.setInput('validating', true); - const onBlurStub = jest.spyOn(component, 'onBlur'); + jest.spyOn(component, 'clearInput'); fixture.detectChanges(); const result = component.onBeforeOptionsHidden( CpsMenuHideReason.KEYDOWN_TAB ); expect(result).toBe(undefined); - expect(onBlurStub).toHaveBeenCalledTimes(1); + expect(component.clearInput).toHaveBeenCalled(); }); it('should display loading indicator when validating', () => { 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 2a24debb..24b3ab7c 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 @@ -427,10 +427,11 @@ export class CpsAutocompleteComponent backspaceClickedOnce = false; activeSingle = false; optionHighlightedIndex = -1; + isArrowNavigating = false; readonly virtualScrollItemSizePx = computed( () => - (this._cpsRootFontSizeService?.fontSize() ?? 16) * + (this._cpsRootFontSizeService?.fontSize() || 16) * VIRTUAL_SCROLL_ITEM_SIZE_REM ); @@ -478,6 +479,7 @@ export class CpsAutocompleteComponent ngOnInit() { this.virtualListHeightRem = VIRTUAL_SCROLL_ITEM_SIZE_REM * VIRTUAL_SCROLL_MAX_VISIBLE_ITEMS; + this.cvtWidth = convertSize(this.width); if (this.multiple && !this._value) { this._value = []; } @@ -521,12 +523,10 @@ export class CpsAutocompleteComponent ) { this._toggleOptions(true); } - if (changes.label || changes.ariaLabel) { - if (!this.label?.trim() && !this.ariaLabel?.trim()) { - console.error( - 'CpsAutocompleteComponent: unlabeled autocomplete component must have an ariaLabel for accessibility.' - ); - } + if (!this.label?.trim() && !this.ariaLabel?.trim()) { + console.error( + 'CpsAutocompleteComponent: unlabeled autocomplete component must have an ariaLabel for accessibility.' + ); } } @@ -682,10 +682,9 @@ export class CpsAutocompleteComponent event?.stopPropagation(); event?.preventDefault(); - if ( - (!this.multiple && !this.isEmptyValue()) || - (this.multiple && this.value?.length > 0) - ) { + const hadValue = this.hasSelectedValue(); + + if (hadValue) { if (this.openOnClear) { this._toggleOptions(true); } @@ -694,9 +693,11 @@ export class CpsAutocompleteComponent } this.clearInput(); this._dehighlightOption(); - setTimeout(() => { - this.focusInput(); - }, 0); + if (hadValue) { + setTimeout(() => { + this.focusInput(); + }, 0); + } } // eslint-disable-next-line @typescript-eslint/no-empty-function @@ -743,18 +744,21 @@ export class CpsAutocompleteComponent } this._confirmInput(this.inputText || '', false); this._closeAndClear(); - this.onBlur(); } onBoxClick() { + const wasOpened = this.isOpened; if (!this.multiple) { this.activeSingle = true; if (!this.inputText) this.inputText = this._getValueLabel(); - if (!this.isOpened) this.filteredOptions = this.options; + if (!wasOpened) this.filteredOptions = this.options; } this._dehighlightOption(); setTimeout(() => { - this.focus(); + this.focusInput(); + if (!wasOpened) { + this._toggleOptions(true); + } }); } @@ -826,7 +830,7 @@ export class CpsAutocompleteComponent } focusInput() { - this.autocompleteContainer?.nativeElement?.querySelector('input')?.focus(); + this.autocompleteInput?.nativeElement?.focus(); } focus() { @@ -843,12 +847,14 @@ export class CpsAutocompleteComponent this.virtualList?.setSpacerSize(); } - isEmptyValue(): boolean { + hasSelectedValue(): boolean { + if (this.multiple) { + return this.value?.length > 0; + } return ( - this.value === null || - this.value === undefined || - (typeof this.value === 'string' && this.value.trim() === '') || - Number.isNaN(this.value) + this.value != null && + !(typeof this.value === 'string' && this.value.trim() === '') && + !Number.isNaN(this.value) ); } @@ -944,6 +950,7 @@ export class CpsAutocompleteComponent setTimeout(() => { if (this.isOpened && this.filteredOptions.length > 0) { this.recalcVirtualListHeight(); + this._syncHighlightToValue(); const selected = this.optionsList.nativeElement.querySelector('.selected'); @@ -953,15 +960,8 @@ export class CpsAutocompleteComponent block: 'nearest', inline: 'center' }); - } else if (this.virtualScroll && !this.isEmptyValue()) { - let v: any; - if (this.multiple) { - if (this.value.length > 0) { - v = this.value[0]; - } - } else v = this.value; - const idx = this.filteredOptions.findIndex((o) => isEqual(o, v)); - if (idx >= 0) this.virtualList.scrollToIndex(idx); + } else if (this.virtualScroll && this.optionHighlightedIndex >= 0) { + this._scrollVirtualListToIndex(this.optionHighlightedIndex); } } }); @@ -1008,7 +1008,7 @@ export class CpsAutocompleteComponent } private _getValueLabel() { - return !this.isEmptyValue() + return this.hasSelectedValue() ? this.returnObject ? this.value[this.optionLabel] : this._labelByValue.transform( @@ -1028,6 +1028,19 @@ export class CpsAutocompleteComponent private _dehighlightOption() { this.optionHighlightedIndex = -1; + this.isArrowNavigating = false; + } + + private _syncHighlightToValue(): void { + if (!this.hasSelectedValue()) return; + + const firstSelected = this.multiple ? this.value[0] : this.value; + const idx = this.filteredOptions.findIndex((o) => + isEqual(this.returnObject ? o : o[this.optionValue], firstSelected) + ); + if (idx < 0) return; + + this.optionHighlightedIndex = idx + (this.isSelectAllVisible ? 1 : 0); } private _getHighlightedOptionId(): string | null { @@ -1067,6 +1080,7 @@ export class CpsAutocompleteComponent if (this.optionsAriaSetSize < 1) return; + this.isArrowNavigating = true; this.optionHighlightedIndex = this._nextHighlightIndex( up, this.optionsAriaSetSize @@ -1090,6 +1104,7 @@ export class CpsAutocompleteComponent const len = this.filteredOptions.length; if (len < 1) return; + this.isArrowNavigating = true; this.optionHighlightedIndex = this._nextHighlightIndex(up, len); this._syncVirtualHighlightedOptionIntoView(); } @@ -1148,13 +1163,23 @@ export class CpsAutocompleteComponent searchVal = searchVal.toLowerCase(); if (!searchVal) { - if (this.multiple) return; - // Only reset the value if the inputText was changed by the user - if (this.inputText !== this._getValueLabel()) { - this.updateValue(this._getEmptyValue()); + if (this.multiple) { + this._closeAndClear(); + return; + } + const shouldUpdateValue = + this.activeSingle && this.inputText !== this._getValueLabel(); + this.clearInput(); + this._dehighlightOption(); + if (shouldUpdateValue) { + setTimeout(() => { + this.updateValue(this._getEmptyValue()); + if (needFocusInput) { + this.cdRef.detectChanges(); + this.focusInput(); + } + }, 0); } - this.cdRef.detectChanges(); - this._closeAndClear(); return; } 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 index 5abe137d..2c3858f1 100644 --- 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 @@ -35,6 +35,7 @@ describe('CpsButtonToggleComponent', () => { fixture = TestBed.createComponent(CpsButtonToggleComponent); component = fixture.componentInstance; + fixture.componentRef.setInput('ariaLabel', 'Toggle group'); fixture.componentRef.setInput('options', OPTIONS); fixture.detectChanges(); }); @@ -49,19 +50,22 @@ describe('CpsButtonToggleComponent', () => { 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(); + const defaultComponent = TestBed.createComponent( + CpsButtonToggleComponent + ).componentInstance; + expect(defaultComponent.label).toBe(''); + expect(defaultComponent.ariaLabel).toBe(''); + expect(defaultComponent.multiple).toBe(false); + expect(defaultComponent.disabled).toBe(false); + expect(defaultComponent.mandatory).toBe(true); + expect(defaultComponent.equalWidths).toBe(true); + expect(defaultComponent.optionTooltipPosition).toBe('bottom'); + expect(defaultComponent.infoTooltip).toBe(''); + expect(defaultComponent.infoTooltipClass).toBe('cps-tooltip-content'); + expect(defaultComponent.infoTooltipMaxWidth).toBe('100%'); + expect(defaultComponent.infoTooltipPersistent).toBe(false); + expect(defaultComponent.infoTooltipPosition).toBe('top'); + expect(defaultComponent.value).toBeUndefined(); }); }); @@ -106,6 +110,7 @@ describe('CpsButtonToggleComponent', () => { it('should fall back to label for role=group aria-label when ariaLabel is empty', () => { fixture.componentRef.setInput('label', 'My Label'); + fixture.componentRef.setInput('ariaLabel', ''); fixture.detectChanges(); const group = fixture.nativeElement.querySelector('[role="group"]'); expect(group.getAttribute('aria-label')).toBe('My Label'); @@ -245,6 +250,7 @@ describe('CpsButtonToggleComponent', () => { it('should initialize value to [] when multiple is true and no value is set', () => { const newFixture = TestBed.createComponent(CpsButtonToggleComponent); + newFixture.componentRef.setInput('ariaLabel', 'Toggle group'); newFixture.componentRef.setInput('multiple', true); newFixture.componentRef.setInput('options', OPTIONS); newFixture.detectChanges(); @@ -283,9 +289,10 @@ describe('CpsButtonToggleComponent', () => { const consoleSpy = jest .spyOn(console, 'error') .mockImplementation(() => {}); + component.ariaLabel = ''; component.ngOnChanges({ label: new SimpleChange('My Label', '', false), - ariaLabel: new SimpleChange('', '', false) + ariaLabel: new SimpleChange('Toggle group', '', false) }); expect(consoleSpy).toHaveBeenCalledWith( expect.stringContaining('ariaLabel') @@ -297,6 +304,7 @@ describe('CpsButtonToggleComponent', () => { const consoleSpy = jest .spyOn(console, 'error') .mockImplementation(() => {}); + component.ariaLabel = ''; fixture.componentRef.setInput('label', 'My Label'); fixture.detectChanges(); expect(consoleSpy).not.toHaveBeenCalled(); @@ -332,6 +340,7 @@ describe('CpsButtonToggleComponent', () => { const consoleSpy = jest .spyOn(console, 'error') .mockImplementation(() => {}); + component.label = 'Toggle'; const goodOptions = [{ value: 'x', label: 'X' }]; component.options = goodOptions; component.ngOnChanges({ @@ -345,6 +354,7 @@ describe('CpsButtonToggleComponent', () => { const consoleSpy = jest .spyOn(console, 'error') .mockImplementation(() => {}); + component.label = 'Toggle'; const ariaOptions = [{ value: 'x', ariaLabel: 'X' }]; component.options = ariaOptions; component.ngOnChanges({ 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 5e9e87d1..e103449e 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 @@ -190,12 +190,10 @@ export class CpsButtonToggleComponent } ngOnChanges(changes: SimpleChanges): void { - if (changes.label || changes.ariaLabel) { - if (!this.label?.trim() && !this.ariaLabel?.trim()) { - console.error( - 'CpsButtonToggleComponent: unlabeled button toggle component must have an ariaLabel for accessibility.' - ); - } + if (!this.label?.trim() && !this.ariaLabel?.trim()) { + console.error( + 'CpsButtonToggleComponent: unlabeled button toggle component must have an ariaLabel for accessibility.' + ); } if (changes.options) { const hasInaccessibleOption = this.options.some( diff --git a/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.ts b/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.ts index c7e6988c..fa35db68 100644 --- a/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.ts +++ b/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.ts @@ -6,8 +6,7 @@ import { Inject, Input, OnChanges, - Output, - type SimpleChanges + Output } from '@angular/core'; import { getCSSColor } from '../../utils/colors-utils'; import { CpsIconComponent, IconType } from '../cps-icon/cps-icon.component'; @@ -126,7 +125,7 @@ export class CpsButtonComponent implements OnChanges { // eslint-disable-next-line no-useless-constructor constructor(@Inject(DOCUMENT) private document: Document) {} - ngOnChanges(changes: SimpleChanges): void { + ngOnChanges(): void { this.buttonColor = getCSSColor(this.color, this.document); this.borderRadius = convertSize(this.borderRadius); this.textColor = @@ -136,12 +135,10 @@ export class CpsButtonComponent implements OnChanges { if (this.disabled || this.loading) { this.enterActive = false; } - if (changes.label || changes.ariaLabel) { - if (!this.label?.trim() && !this.ariaLabel?.trim()) { - console.error( - 'CpsButtonComponent: icon-only or unlabeled button must have an ariaLabel for accessibility.' - ); - } + if (!this.label?.trim() && !this.ariaLabel?.trim()) { + console.error( + 'CpsButtonComponent: icon-only or unlabeled button must have an ariaLabel for accessibility.' + ); } this.setClasses(); } diff --git a/projects/cps-ui-kit/src/lib/components/cps-checkbox/cps-checkbox.component.ts b/projects/cps-ui-kit/src/lib/components/cps-checkbox/cps-checkbox.component.ts index adef42a6..6003e73f 100644 --- a/projects/cps-ui-kit/src/lib/components/cps-checkbox/cps-checkbox.component.ts +++ b/projects/cps-ui-kit/src/lib/components/cps-checkbox/cps-checkbox.component.ts @@ -9,8 +9,7 @@ import { OnInit, Optional, Output, - Self, - type SimpleChanges + Self } from '@angular/core'; import { ControlValueAccessor, NgControl } from '@angular/forms'; import { CpsInfoCircleComponent } from '../cps-info-circle/cps-info-circle.component'; @@ -128,13 +127,11 @@ export class CpsCheckboxComponent this.iconColor = getCSSColor(this.iconColor, this.document); } - ngOnChanges(changes: SimpleChanges): void { - if (changes.label || changes.ariaLabel) { - if (!this.label?.trim() && !this.ariaLabel?.trim()) { - console.error( - 'CpsCheckboxComponent: icon-only or unlabeled checkbox must have an ariaLabel for accessibility.' - ); - } + ngOnChanges(): void { + if (!this.label?.trim() && !this.ariaLabel?.trim()) { + console.error( + 'CpsCheckboxComponent: icon-only or unlabeled checkbox must have an ariaLabel for accessibility.' + ); } } diff --git a/projects/cps-ui-kit/src/lib/components/cps-chip/cps-chip.component.scss b/projects/cps-ui-kit/src/lib/components/cps-chip/cps-chip.component.scss index 3a427faf..63591f16 100644 --- a/projects/cps-ui-kit/src/lib/components/cps-chip/cps-chip.component.scss +++ b/projects/cps-ui-kit/src/lib/components/cps-chip/cps-chip.component.scss @@ -18,16 +18,17 @@ $color-text-mild: var(--cps-color-text-mild); background-color: $color-bg-dark; border-radius: 0.875rem; line-height: 1rem; - padding: 0.25rem 0.75rem; + padding-left: 0.75rem; + padding-right: 0.375rem; cursor: default; &-close-icon { - margin-left: 0.375rem; + padding: 0.375rem; cursor: pointer; &:focus { outline: none; } &:focus-visible { - @include focus-ring(0.125rem, 0.25rem, 50%); + @include focus-ring(-0.125rem, -0.25rem, 50%); } &:hover { ::ng-deep .cps-icon { @@ -36,11 +37,16 @@ $color-text-mild: var(--cps-color-text-mild); } } &-label { + margin-top: 0.25rem; + margin-bottom: 0.25rem; font-size: 0.875rem; color: $color-text-darkest; font-family: 'Source Sans Pro', sans-serif; font-style: normal; font-weight: 400; + &:not(:has(+ .cps-chip-close-icon)) { + margin-right: 0.375rem; + } } &.cps-chip-disabled { @@ -68,6 +74,16 @@ $color-text-mild: var(--cps-color-text-mild); .cps-chip-icon { margin-left: 0.375rem; order: 1; + + &:not(:has(~ .cps-chip-close-icon)) { + margin-right: 0.375rem; + } + } + .cps-chip-close-icon { + order: 2; + } + .cps-chip-label { + margin-right: 0; } } } diff --git a/projects/cps-ui-kit/src/lib/components/cps-paginator/cps-paginator.component.html b/projects/cps-ui-kit/src/lib/components/cps-paginator/cps-paginator.component.html index 287f5d79..c4246319 100644 --- a/projects/cps-ui-kit/src/lib/components/cps-paginator/cps-paginator.component.html +++ b/projects/cps-ui-kit/src/lib/components/cps-paginator/cps-paginator.component.html @@ -16,6 +16,7 @@
Items per page: Every Every hour(s) on minute Every On the of every On the Every On the + [ngClass]="{ disabled: disabled, error: error }"> @if (label) {
@@ -25,30 +20,43 @@ }
-
+ underlined: appearance === 'underlined', + active: isOpened, + focused: isActive + }" + #selectContainer + (keydown)="onContainerKeyDown($event)" + (focus)="onFocus()" + (blur)="onBlur()"> +
@if (prefixIcon) { } - @if ((!multiple && isEmptyValue()) || (value?.length < 1 && multiple)) { + @if (!hasSelectedValue()) {
{{ placeholder }}
- } - @if ( - (!multiple && !isEmptyValue()) || (value?.length > 0 && multiple) - ) { + } @else {
@if (!multiple) { @@ -61,8 +69,8 @@ > } @if (multiple && !chips) { -
- +
+ {{ value | combineLabels @@ -75,9 +83,14 @@
} @if (multiple && chips) { -
+
@for (val of value; track val) { @if (clearable && !disabled) { - + } @if (showChevron) { - + @@ -125,20 +148,36 @@
+ [style.width.px]="selectBoxWidthPx"> @if (!virtualScroll) { @if (multiple && selectAll && options.length > 1) {
@if (multiple) { @@ -148,12 +187,13 @@
} - @for (item of options; track item) { + @for (item of options; track item; let itemIdx = $index) { } @@ -161,17 +201,19 @@ @if (virtualScroll) { - + [itemSize]="virtualScrollItemSizePx()"> + @@ -194,14 +236,30 @@
{{ hint }}
} @if (error && !hideDetails) { -
{{ error }}
+ }
- +
@@ -222,6 +280,7 @@ {{ item[optionInfo] }} @if (item[optionIcon]) {