mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-06-30 18:15:11 +00:00
[ADF-5213] Metadata - select list filter (#5961)
* select filter input component * include theme * add filter input * show input conditionally * convert value to string for d:int type values * filter list options pipe * add components to module * convert int value to string * i18n * update tests * tests * update config * remove unneeded decorator * fix lint * update schema * remove filter pipe * provide a filtered list
This commit is contained in:
parent
7b7c996fab
commit
9b0db0a82e
@ -1012,7 +1012,8 @@
|
||||
},
|
||||
"multi-value-pipe-separator": ", ",
|
||||
"multi-value-chips": true,
|
||||
"copy-to-clipboard-action": true
|
||||
"copy-to-clipboard-action": true,
|
||||
"selectFilterLimit": 5
|
||||
},
|
||||
"sideNav": {
|
||||
"expandedSidenav": true,
|
||||
|
@ -1036,6 +1036,14 @@
|
||||
"multi-value-chips": {
|
||||
"description": "Use chips for multi value properties",
|
||||
"type": "boolean"
|
||||
},
|
||||
"copy-to-clipboard-action": {
|
||||
"description": "Copy property to the clipboard on double click",
|
||||
"type": "boolean"
|
||||
},
|
||||
"selectFilterLimit": {
|
||||
"description": "Shows a filter if list options exceed a specified number. Default value 5",
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -3,6 +3,7 @@
|
||||
@import './components/card-view-textitem/card-view-textitem.component';
|
||||
@import './components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component';
|
||||
@import './components/card-view/card-view.component';
|
||||
@import './components/card-view-selectitem/select-filter-input/select-filter-input.component';
|
||||
@import '~@mat-datetimepicker/core/datetimepicker/datetimepicker-theme.scss';
|
||||
|
||||
@mixin adf-card-view-module-theme($theme) {
|
||||
@ -12,4 +13,5 @@
|
||||
@include adf-card-view-theme($theme);
|
||||
@include mat-datetimepicker-theme($theme);
|
||||
@include adf-card-view-array-item-theme($theme);
|
||||
@include adf-select-filter-input-theme($theme);
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ import { CardViewTextItemComponent } from './components/card-view-textitem/card-
|
||||
import { CardViewKeyValuePairsItemComponent } from './components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component';
|
||||
import { CardViewSelectItemComponent } from './components/card-view-selectitem/card-view-selectitem.component';
|
||||
import { CardViewArrayItemComponent } from './components/card-view-arrayitem/card-view-arrayitem.component';
|
||||
import { SelectFilterInputComponent } from './components/card-view-selectitem/select-filter-input/select-filter-input.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@ -78,7 +79,8 @@ import { CardViewArrayItemComponent } from './components/card-view-arrayitem/car
|
||||
CardViewSelectItemComponent,
|
||||
CardViewItemDispatcherComponent,
|
||||
CardViewContentProxyDirective,
|
||||
CardViewArrayItemComponent
|
||||
CardViewArrayItemComponent,
|
||||
SelectFilterInputComponent
|
||||
],
|
||||
exports: [
|
||||
CardViewComponent,
|
||||
@ -88,7 +90,8 @@ import { CardViewArrayItemComponent } from './components/card-view-arrayitem/car
|
||||
CardViewTextItemComponent,
|
||||
CardViewSelectItemComponent,
|
||||
CardViewKeyValuePairsItemComponent,
|
||||
CardViewArrayItemComponent
|
||||
CardViewArrayItemComponent,
|
||||
SelectFilterInputComponent
|
||||
]
|
||||
})
|
||||
export class CardViewModule {}
|
||||
|
@ -8,10 +8,14 @@
|
||||
<div *ngIf="isEditable()">
|
||||
<mat-form-field class="adf-select-item-padding-editable adf-property-value">
|
||||
<mat-select [(value)]="value"
|
||||
panelClass="adf-select-filter"
|
||||
(selectionChange)="onChange($event)"
|
||||
data-automation-class="select-box">
|
||||
|
||||
<adf-select-filter-input *ngIf="showInputFilter" (change)="onFilterInputChange($event)"></adf-select-filter-input>
|
||||
|
||||
<mat-option *ngIf="showNoneOption()">{{ 'CORE.CARDVIEW.NONE' | translate }}</mat-option>
|
||||
<mat-option *ngFor="let option of getOptions() | async"
|
||||
<mat-option *ngFor="let option of getList() | async"
|
||||
[value]="option.key">
|
||||
{{ option.label | translate }}
|
||||
</mat-option>
|
||||
|
@ -24,12 +24,13 @@ import { setupTestBed } from '../../../testing/setup-test-bed';
|
||||
import { CoreTestingModule } from '../../../testing/core.testing.module';
|
||||
import { of } from 'rxjs';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { AppConfigService } from '../../../app-config/app-config.service';
|
||||
|
||||
describe('CardViewSelectItemComponent', () => {
|
||||
|
||||
let fixture: ComponentFixture<CardViewSelectItemComponent>;
|
||||
let component: CardViewSelectItemComponent;
|
||||
let overlayContainer: OverlayContainer;
|
||||
let appConfig: AppConfigService;
|
||||
const mockData = [{ key: 'one', label: 'One' }, { key: 'two', label: 'Two' }, { key: 'three', label: 'Three' }];
|
||||
const mockDefaultProps = {
|
||||
label: 'Select box label',
|
||||
@ -50,6 +51,7 @@ describe('CardViewSelectItemComponent', () => {
|
||||
fixture = TestBed.createComponent(CardViewSelectItemComponent);
|
||||
component = fixture.componentInstance;
|
||||
overlayContainer = TestBed.inject(OverlayContainer);
|
||||
appConfig = TestBed.inject(AppConfigService);
|
||||
component.property = new CardViewSelectItemModel(mockDefaultProps);
|
||||
});
|
||||
|
||||
@ -144,4 +146,79 @@ describe('CardViewSelectItemComponent', () => {
|
||||
expect(label).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Filter', () => {
|
||||
it('should render a list of filtered options', () => {
|
||||
appConfig.config['content-metadata'] = {
|
||||
selectFilterLimit: 0
|
||||
};
|
||||
let optionsElement: any[];
|
||||
component.property = new CardViewSelectItemModel({
|
||||
...mockDefaultProps,
|
||||
editable: true
|
||||
});
|
||||
component.editable = true;
|
||||
component.displayNoneOption = false;
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
|
||||
const selectBox = fixture.debugElement.query(By.css('.mat-select-trigger'));
|
||||
selectBox.triggerEventHandler('click', {});
|
||||
|
||||
fixture.detectChanges();
|
||||
optionsElement = Array.from(overlayContainer.getContainerElement().querySelectorAll('mat-option'));
|
||||
expect(optionsElement.length).toBe(3);
|
||||
|
||||
const filterInput = fixture.debugElement.query(By.css('.adf-select-filter-input input'));
|
||||
filterInput.nativeElement.value = mockData[0].label;
|
||||
filterInput.nativeElement.dispatchEvent(new Event('input'));
|
||||
|
||||
fixture.detectChanges();
|
||||
optionsElement = Array.from(overlayContainer.getContainerElement().querySelectorAll('mat-option'));
|
||||
expect(optionsElement.length).toBe(1);
|
||||
expect(optionsElement[0].innerText).toEqual(mockData[0].label);
|
||||
});
|
||||
|
||||
it('should hide filter if options are less then limit', () => {
|
||||
appConfig.config['content-metadata'] = {
|
||||
selectFilterLimit: mockData.length + 1
|
||||
};
|
||||
component.property = new CardViewSelectItemModel({
|
||||
...mockDefaultProps,
|
||||
editable: true
|
||||
});
|
||||
component.editable = true;
|
||||
component.displayNoneOption = false;
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
|
||||
const selectBox = fixture.debugElement.query(By.css('.mat-select-trigger'));
|
||||
selectBox.triggerEventHandler('click', {});
|
||||
fixture.detectChanges();
|
||||
|
||||
const filterInput = fixture.debugElement.query(By.css('.adf-select-filter-input'));
|
||||
expect(filterInput).toBe(null);
|
||||
});
|
||||
|
||||
it('should show filter if options are greater then limit', () => {
|
||||
appConfig.config['content-metadata'] = {
|
||||
selectFilterLimit: mockData.length - 1
|
||||
};
|
||||
component.property = new CardViewSelectItemModel({
|
||||
...mockDefaultProps,
|
||||
editable: true
|
||||
});
|
||||
component.editable = true;
|
||||
component.displayNoneOption = false;
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
|
||||
const selectBox = fixture.debugElement.query(By.css('.mat-select-trigger'));
|
||||
selectBox.triggerEventHandler('click', {});
|
||||
fixture.detectChanges();
|
||||
|
||||
const filterInput = fixture.debugElement.query(By.css('.adf-select-filter-input'));
|
||||
expect(filterInput).not.toBe(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -15,20 +15,23 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, Input, OnChanges } from '@angular/core';
|
||||
import { Component, Input, OnChanges, OnDestroy } from '@angular/core';
|
||||
import { CardViewSelectItemModel } from '../../models/card-view-selectitem.model';
|
||||
import { CardViewUpdateService } from '../../services/card-view-update.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { CardViewSelectItemOption } from '../../interfaces/card-view.interfaces';
|
||||
import { MatSelectChange } from '@angular/material/select';
|
||||
import { BaseCardView } from '../base-card-view';
|
||||
import { AppConfigService } from '../../../app-config/app-config.service';
|
||||
import { takeUntil, map } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-card-view-selectitem',
|
||||
templateUrl: './card-view-selectitem.component.html',
|
||||
styleUrls: ['./card-view-selectitem.component.scss']
|
||||
})
|
||||
export class CardViewSelectItemComponent extends BaseCardView<CardViewSelectItemModel<string>> implements OnChanges {
|
||||
export class CardViewSelectItemComponent extends BaseCardView<CardViewSelectItemModel<string>> implements OnChanges, OnDestroy {
|
||||
static HIDE_FILTER_LIMIT = 5;
|
||||
|
||||
@Input() editable: boolean = false;
|
||||
|
||||
@ -41,13 +44,29 @@ export class CardViewSelectItemComponent extends BaseCardView<CardViewSelectItem
|
||||
displayEmpty: boolean = true;
|
||||
|
||||
value: string;
|
||||
filter: string = '';
|
||||
showInputFilter: boolean = false;
|
||||
|
||||
constructor(cardViewUpdateService: CardViewUpdateService) {
|
||||
private onDestroy$ = new Subject<void>();
|
||||
|
||||
constructor(cardViewUpdateService: CardViewUpdateService, private appConfig: AppConfigService) {
|
||||
super(cardViewUpdateService);
|
||||
}
|
||||
|
||||
ngOnChanges(): void {
|
||||
this.value = this.property.value;
|
||||
this.value = this.property.value?.toString();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.getOptions()
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe((options: CardViewSelectItemOption<string>[]) => {
|
||||
this.showInputFilter = options.length > this.optionsLimit;
|
||||
});
|
||||
}
|
||||
|
||||
onFilterInputChange(value: string) {
|
||||
this.filter = value;
|
||||
}
|
||||
|
||||
isEditable(): boolean {
|
||||
@ -58,6 +77,16 @@ export class CardViewSelectItemComponent extends BaseCardView<CardViewSelectItem
|
||||
return this.options$ || this.property.options$;
|
||||
}
|
||||
|
||||
getList(): Observable<CardViewSelectItemOption<string>[]> {
|
||||
return this.getOptions()
|
||||
.pipe(
|
||||
map((items: CardViewSelectItemOption<string>[]) => items.filter(
|
||||
(item: CardViewSelectItemOption<string>) =>
|
||||
item.label.toLowerCase().includes(this.filter.toLowerCase()))),
|
||||
takeUntil(this.onDestroy$)
|
||||
);
|
||||
}
|
||||
|
||||
onChange(event: MatSelectChange): void {
|
||||
const selectedOption = event.value !== undefined ? event.value : null;
|
||||
this.cardViewUpdateService.update(<CardViewSelectItemModel<string>> { ...this.property }, selectedOption);
|
||||
@ -71,4 +100,13 @@ export class CardViewSelectItemComponent extends BaseCardView<CardViewSelectItem
|
||||
get showProperty(): boolean {
|
||||
return this.displayEmpty || !this.property.isEmpty();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy$.next();
|
||||
this.onDestroy$.complete();
|
||||
}
|
||||
|
||||
private get optionsLimit(): number {
|
||||
return this.appConfig.get<number>('content-metadata.selectFilterLimit', CardViewSelectItemComponent.HIDE_FILTER_LIMIT);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
|
||||
<div class="adf-select-filter-input-container">
|
||||
<mat-form-field>
|
||||
<input matInput
|
||||
autocomplete="off"
|
||||
(keydown)="handleKeydown($event)"
|
||||
[placeholder]="'SELECT_FILTER.INPUT.PLACEHOLDER' | translate"
|
||||
#selectFilterInput
|
||||
[ngModel]="term"
|
||||
(ngModelChange)="onModelChange($event)"
|
||||
[attr.aria-label]="'SELECT_FILTER.INPUT.ARIA_LABEL' | translate"
|
||||
(change)="$event.stopPropagation()"
|
||||
/>
|
||||
|
||||
<button mat-button
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
[attr.aria-label]="'SELECT_FILTER.BUTTON.ARIA_LABEL' | translate"
|
||||
*ngIf="term"
|
||||
(keydown.enter)="reset($event)"
|
||||
(click)="reset()">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
</div>
|
@ -0,0 +1,35 @@
|
||||
@mixin adf-select-filter-input-theme($theme) {
|
||||
$mat-select-panel-max-height: 256px !default;
|
||||
$select-filter-height: 4em !default;
|
||||
$background: map-get($theme, background);
|
||||
$foreground: map-get($theme, foreground);
|
||||
|
||||
.adf-select-filter-input {
|
||||
height: $select-filter-height;
|
||||
display: flex;
|
||||
|
||||
.adf-select-filter-input-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
z-index: 100;
|
||||
font-size: 14px;
|
||||
color: mat-color($foreground, text, 0.87);
|
||||
line-height: 3em;
|
||||
height: $select-filter-height;
|
||||
padding: 5px 16px 0;
|
||||
background: mat-color($background, card);
|
||||
}
|
||||
|
||||
.mat-form-field {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-select-panel.adf-select-filter {
|
||||
transform: none !important;
|
||||
overflow-x: hidden !important;
|
||||
max-height: calc(#{$mat-select-panel-max-height} + #{$select-filter-height});
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2019 Alfresco Software, Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||
import { setupTestBed } from '../../../../testing/setup-test-bed';
|
||||
import { CoreTestingModule } from '../../../../testing/core.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { SelectFilterInputComponent } from './select-filter-input.component';
|
||||
import { MatSelect } from '@angular/material/select';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { ESCAPE } from '@angular/cdk/keycodes';
|
||||
|
||||
describe('SelectFilterInputComponent', () => {
|
||||
|
||||
let fixture: ComponentFixture<SelectFilterInputComponent>;
|
||||
let component: SelectFilterInputComponent;
|
||||
let matSelect: MatSelect;
|
||||
|
||||
setupTestBed({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
CoreTestingModule,
|
||||
NoopAnimationsModule
|
||||
],
|
||||
providers: [ MatSelect ]
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SelectFilterInputComponent);
|
||||
component = fixture.componentInstance;
|
||||
matSelect = TestBed.inject(MatSelect);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should focus input on initialization', async(() => {
|
||||
spyOn(component.selectFilterInput.nativeElement, 'focus');
|
||||
matSelect.openedChange.next(true);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.selectFilterInput.nativeElement.focus).toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should clear search term on close', async(() => {
|
||||
component.onModelChange('some-search-term');
|
||||
expect(component.term).toBe('some-search-term');
|
||||
|
||||
matSelect.openedChange.next(false);
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(component.term).toBe('');
|
||||
}));
|
||||
|
||||
it('should emit event when value changes', async(() => {
|
||||
spyOn(component.change, 'next');
|
||||
component.onModelChange('some-search-term');
|
||||
expect(component.change.next).toHaveBeenCalledWith('some-search-term');
|
||||
}));
|
||||
|
||||
it('should reset value on reset() event', () => {
|
||||
component.onModelChange('some-search-term');
|
||||
expect(component.term).toBe('some-search-term');
|
||||
|
||||
component.reset();
|
||||
expect(component.term).toBe('');
|
||||
});
|
||||
|
||||
it('should reset value on Escape event', () => {
|
||||
component.onModelChange('some-search-term');
|
||||
expect(component.term).toBe('some-search-term');
|
||||
|
||||
component.selectFilterInput.nativeElement.dispatchEvent(new KeyboardEvent('keydown', {'keyCode': ESCAPE} as any));
|
||||
fixture.detectChanges();
|
||||
expect(component.term).toBe('');
|
||||
});
|
||||
});
|
@ -0,0 +1,86 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2019 Alfresco Software, Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, ViewEncapsulation, ViewChild, ElementRef, OnDestroy, Inject, Output, EventEmitter } from '@angular/core';
|
||||
import { ESCAPE, TAB } from '@angular/cdk/keycodes';
|
||||
import { MatSelect } from '@angular/material/select';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-select-filter-input',
|
||||
templateUrl: './select-filter-input.component.html',
|
||||
styleUrls: ['./select-filter-input.component.scss'],
|
||||
host: { 'class': 'adf-select-filter-input' },
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class SelectFilterInputComponent implements OnDestroy {
|
||||
@ViewChild('selectFilterInput', { read: ElementRef, static: false }) selectFilterInput: ElementRef;
|
||||
@Output() change = new EventEmitter<string>();
|
||||
|
||||
term = '';
|
||||
private onDestroy$ = new Subject<void>();
|
||||
|
||||
constructor(@Inject(MatSelect) private matSelect: MatSelect) {}
|
||||
|
||||
onModelChange(value: string) {
|
||||
this.change.next(value);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.change
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe((val: string) => this.term = val );
|
||||
|
||||
this.matSelect.openedChange
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe((isOpened: boolean) => {
|
||||
if (isOpened) {
|
||||
this.selectFilterInput.nativeElement.focus();
|
||||
} else {
|
||||
this.change.next('');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
reset(event?: KeyboardEvent) {
|
||||
if (event) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
this.change.next('');
|
||||
this.selectFilterInput.nativeElement.focus();
|
||||
}
|
||||
|
||||
handleKeydown($event: KeyboardEvent) {
|
||||
if (this.term) {
|
||||
if ($event.keyCode === ESCAPE) {
|
||||
event.stopPropagation();
|
||||
this.change.next('');
|
||||
}
|
||||
|
||||
if (($event.target as HTMLInputElement).tagName === 'INPUT' && $event.keyCode === TAB) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy$.next();
|
||||
this.onDestroy$.complete();
|
||||
}
|
||||
}
|
@ -23,5 +23,6 @@ export * from './card-view-item-dispatcher/card-view-item-dispatcher.component';
|
||||
export * from './card-view-mapitem/card-view-mapitem.component';
|
||||
export * from './card-view-textitem/card-view-textitem.component';
|
||||
export * from './card-view-selectitem/card-view-selectitem.component';
|
||||
export * from './card-view-selectitem/select-filter-input/select-filter-input.component';
|
||||
export * from './card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component';
|
||||
export * from './card-view-arrayitem/card-view-arrayitem.component';
|
||||
|
@ -35,7 +35,7 @@ export class CardViewSelectItemModel<T> extends CardViewBaseItemModel implements
|
||||
get displayValue() {
|
||||
return this.options$.pipe(
|
||||
switchMap((options) => {
|
||||
const option = options.find((o) => o.key === this.value);
|
||||
const option = options.find((o) => o.key === this.value?.toString());
|
||||
return of(option ? option.label : '');
|
||||
})
|
||||
);
|
||||
|
@ -23,7 +23,8 @@ export {
|
||||
CardViewTextItemComponent,
|
||||
CardViewSelectItemComponent,
|
||||
CardViewKeyValuePairsItemComponent,
|
||||
CardViewArrayItemComponent
|
||||
CardViewArrayItemComponent,
|
||||
SelectFilterInputComponent
|
||||
} from './components/card-view.components';
|
||||
|
||||
export * from './interfaces/card-view.interfaces';
|
||||
|
@ -509,5 +509,14 @@
|
||||
"CLIPBOARD": {
|
||||
"CLICK_TO_COPY": "Click to copy",
|
||||
"SUCCESS_COPY": "Text copied to clipboard"
|
||||
},
|
||||
"SELECT_FILTER": {
|
||||
"INPUT": {
|
||||
"PLACEHOLDER": "Search",
|
||||
"ARIA_LABEL": "Search options"
|
||||
},
|
||||
"BUTTON": {
|
||||
"ARIA_LABEL": "Clear"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user