Skip to content
Open
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
70 changes: 68 additions & 2 deletions live-editing/configs/ComboConfigGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,76 @@ export class ComboConfigGenerator implements IConfigGenerator {
shortenComponentPathBy: '/lists/combo/'
}));

// combo overview
configs.push(new Config({
additionalFiles: ['/src/app/data/heroData.ts', '/src/app/lists/combo/combo-styling/layout.scss'],
appConfig: BaseAppConfig,
component: 'ComboStylingComponent'
component: 'ComboOverviewComponent',
shortenComponentPathBy: '/lists/combo/'
}));

// combo type
configs.push(new Config({
appConfig: BaseAppConfig,
component: 'ComboTypeComponent',
shortenComponentPathBy: '/lists/combo/'
}));

// combo disabled
configs.push(new Config({
appConfig: BaseAppConfig,
component: 'ComboDisabledComponent',
shortenComponentPathBy: '/lists/combo/'
}));

// combo size
configs.push(new Config({
appConfig: BaseAppConfig,
component: 'ComboSizeComponent',
shortenComponentPathBy: '/lists/combo/'
}));

// combo states
configs.push(new Config({
appConfig: BaseAppConfig,
component: 'ComboStatesComponent',
shortenComponentPathBy: '/lists/combo/'
}));

// combo validation
configs.push(new Config({
appConfig: BaseAppConfig,
component: 'ComboValidationComponent',
shortenComponentPathBy: '/lists/combo/'
}));

// combo dropdown size
configs.push(new Config({
appConfig: BaseAppConfig,
component: 'ComboDropdownSizeComponent',
shortenComponentPathBy: '/lists/combo/'
}));

// combo search input
configs.push(new Config({
appConfig: BaseAppConfig,
component: 'ComboSearchInputComponent',
shortenComponentPathBy: '/lists/combo/'
}));

// combo styling
configs.push(new Config({
appConfig: BaseAppConfig,
component: 'ComboStylingComponent',
shortenComponentPathBy: '/lists/combo/'
}));

// combo tailwind styling
configs.push(new Config({
additionalDependencies: ['tailwindcss', '@tailwindcss/postcss'],
additionalFiles: ['.postcssrc.json'],
appConfig: BaseAppConfig,
component: 'ComboTailwindStylingComponent',
shortenComponentPathBy: '/lists/combo/'
}));

configs.push(new Config({
Expand Down
24 changes: 24 additions & 0 deletions src/app/lists/combo/combo-disabled/combo-disabled.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<div class="states">
<span></span>
<span class="state-label state-column">Enabled</span>
<span class="state-label state-column">Disabled</span>
@for (row of rows; track $index) {
@let groupStart = $index === 2;
<span class="state-label" [class.group-start]="groupStart">{{ row.label }}</span>
@for (disabled of [false, true]; track disabled) {
<div [class.group-start]="groupStart">
<igx-combo
[type]="row.type"
[disabled]="disabled"
placeholder="Country"
searchPlaceholder="Search"
valueKey="id"
displayKey="name"
groupKey="region"
[data]="countries"
[ngModel]="row.value">
</igx-combo>
</div>
}
}
</div>
35 changes: 35 additions & 0 deletions src/app/lists/combo/combo-disabled/combo-disabled.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
:host {
/* styles.scss asks the page for the large size; the combos keep their own
default medium size here. */
--ig-size: var(--ig-size-medium);

display: flex;
align-items: center;
justify-content: center;
height: 100%;
padding: 1rem;
}

.states {
display: grid;
grid-template-columns: max-content repeat(2, minmax(0, 17.4375rem));
width: 100%;
justify-content: center;
align-items: center;
column-gap: 1.75rem;
row-gap: 1.5rem;
}

.group-start {
margin-top: 1.5rem;
}

.state-label {
font: 400 13px / 20px "Aktiv Grotesk", sans-serif;
letter-spacing: 0.3px;
color: var(--ig-gray-600);
}

.state-column {
justify-self: center;
}
37 changes: 37 additions & 0 deletions src/app/lists/combo/combo-disabled/combo-disabled.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { IgxComboComponent } from 'igniteui-angular/combo';
import { IgxInputGroupType } from 'igniteui-angular/input-group';

interface Country {
id: string;
name: string;
region: string;
}

interface DisabledRow {
label: string;
type: IgxInputGroupType;
value: string[];
}

@Component({
selector: 'app-combo-disabled',
styleUrls: ['./combo-disabled.component.scss'],
templateUrl: './combo-disabled.component.html',
imports: [IgxComboComponent, FormsModule]
})
export class ComboDisabledComponent {
public countries: Country[] = [
{ id: 'BY', name: 'Belarus', region: 'Europe' },
{ id: 'BE', name: 'Belgium', region: 'Europe' },
{ id: 'BG', name: 'Bulgaria', region: 'Europe' }
];

public rows: DisabledRow[] = [
{ label: 'Idle', type: 'border', value: [] },
{ label: 'Filled', type: 'border', value: ['BY', 'BE'] },
{ label: 'Idle', type: 'box', value: [] },
{ label: 'Filled', type: 'box', value: ['BY', 'BE'] }
];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<div class="sizes">
@for (size of sizes; track size.label) {
<div class="size">
<span class="state-label">{{ size.label }}</span>
<!-- The input field is hidden, so the dropdown opens at the element around the combo,
and a click elsewhere does not close it. -->
<div #dropdown class="dropdown {{ size.className }}">
<igx-combo
searchPlaceholder="Search"
valueKey="id"
displayKey="name"
groupKey="group"
[data]="options"
[overlaySettings]="{ target: dropdown, closeOnOutsideClick: false }"
(closing)="keepOpen($event)">
</igx-combo>
</div>
</div>
}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
:host {
display: flex;
align-items: flex-start;
justify-content: center;
height: 100%;
padding: 2rem 1rem;
}

.sizes {
display: grid;
grid-template-columns: repeat(3, 11.25rem);
column-gap: 1rem;
}

.size {
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
}

.dropdown {
width: 100%;
}

/* Only the dropdown of the combo is shown, so the input field is hidden. */
.dropdown ::ng-deep igx-combo > igx-input-group {
display: none;
}


.small {
--ig-size: var(--ig-size-small);
}

.medium {
--ig-size: var(--ig-size-medium);
}

.large {
--ig-size: var(--ig-size-large);
}

.state-label {
font: 400 13px / 20px "Aktiv Grotesk", sans-serif;
letter-spacing: 0.3px;
color: var(--ig-gray-600);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Component, ElementRef, afterNextRender, inject, viewChildren } from '@angular/core';
import { IgxComboComponent } from 'igniteui-angular/combo';
import { IBaseCancelableBrowserEventArgs } from 'igniteui-angular/core';
import { forkJoin, take } from 'rxjs';

interface Option {
id: number;
name: string;
group: string;
}

interface DropdownSize {
label: string;
className: string;
}

@Component({
selector: 'app-combo-dropdown-size',
styleUrls: ['./combo-dropdown-size.component.scss'],
templateUrl: './combo-dropdown-size.component.html',
imports: [IgxComboComponent]
})
export class ComboDropdownSizeComponent {
public options: Option[] = [1, 2, 3].map((id) => ({ id, name: 'Item', group: 'Header' }));

public sizes: DropdownSize[] = [
{ label: 'Small', className: 'small' },
{ label: 'Medium', className: 'medium' },
{ label: 'Large', className: 'large' }
];

private combos = viewChildren(IgxComboComponent);

constructor() {
const element = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;

// The combos are shown open. Opening a combo moves the focus to its search input, so
// the sample is inert until the combos open and the page keeps its focus.
afterNextRender(() => {
const combos = this.combos();
element.inert = true;
forkJoin(combos.map((combo) => combo.opened.pipe(take(1)))).subscribe(() => {
element.inert = false;
});
combos.forEach((combo) => combo.open());
});
}

// The input fields are hidden, so the dropdowns stay open and each one works on its own.
public keepOpen(event: IBaseCancelableBrowserEventArgs): void {
event.cancel = true;
}
}
14 changes: 14 additions & 0 deletions src/app/lists/combo/combo-overview/combo-overview.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<igx-combo
class="locations"
type="border"
placeholder="Cities"
searchPlaceholder="Search cities"
valueKey="id"
displayKey="name"
groupKey="country"
[data]="cities">
<label igxLabel>Locations</label>
<igx-prefix>
<igx-icon family="material" name="place"></igx-icon>
</igx-prefix>
</igx-combo>
15 changes: 15 additions & 0 deletions src/app/lists/combo/combo-overview/combo-overview.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
:host {
/* styles.scss asks the page for the large size; the combo keeps its own
default medium size here. */
--ig-size: var(--ig-size-medium);

display: flex;
align-items: flex-start;
justify-content: center;
height: 100%;
padding: 2rem 1rem;
}

.locations {
width: 22.5rem;
}
47 changes: 47 additions & 0 deletions src/app/lists/combo/combo-overview/combo-overview.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Component, ElementRef, afterNextRender, inject, viewChild } from '@angular/core';
import { IgxComboComponent } from 'igniteui-angular/combo';
import { IgxIconComponent, IgxIconService } from 'igniteui-angular/icon';
import { IgxLabelDirective, IgxPrefixDirective } from 'igniteui-angular/input-group';
import { take } from 'rxjs';

const placeIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/></svg>';

interface City {
id: string;
name: string;
country: string;
}

@Component({
selector: 'app-combo-overview',
styleUrls: ['./combo-overview.component.scss'],
templateUrl: './combo-overview.component.html',
imports: [IgxComboComponent, IgxLabelDirective, IgxPrefixDirective, IgxIconComponent]
})
export class ComboOverviewComponent {
public cities: City[] = [
{ id: 'BG01', name: 'Sofia', country: 'Country of Bulgaria' },
{ id: 'BG02', name: 'Plovdiv', country: 'Country of Bulgaria' },
{ id: 'BG03', name: 'Varna', country: 'Country of Bulgaria' },
{ id: 'BG04', name: 'Burgas', country: 'Country of Bulgaria' },
{ id: 'BG05', name: 'Pleven', country: 'Country of Bulgaria' }
];

private combo = viewChild.required(IgxComboComponent);

constructor() {
const element = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;
inject(IgxIconService).addSvgIconFromText('place', placeIcon, 'material');

// The combo is shown open. Opening it moves the focus to its search input, so the
// sample is inert until the combo opens and the page keeps its focus.
afterNextRender(() => {
const combo = this.combo();
element.inert = true;
combo.opened.pipe(take(1)).subscribe(() => {
element.inert = false;
});
combo.open();
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<div class="states">
@for (state of states; track state.label) {
<div class="state">
<span class="state-label">{{ state.label }}</span>
<!-- The input field is hidden, so the dropdown opens at the element around the combo,
and a click elsewhere does not close it. -->
<div #search class="search {{ state.className }}">
<igx-combo
[searchPlaceholder]="state.text ?? 'Search'"
[data]="[]"
[overlaySettings]="{ target: search, closeOnOutsideClick: false }">
</igx-combo>
</div>
</div>
}
</div>
Loading
Loading