From fb8ec8ac860d6692ccc655178c80eb7ccd386536 Mon Sep 17 00:00:00 2001 From: ddincheva Date: Wed, 18 Aug 2021 08:58:10 +0300 Subject: [PATCH 01/33] feat(Grid): introduce new properties rowClasses and rowStyles #9969 --- .../src/lib/grids/grid-base.directive.ts | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts index ab0f247134c..cef8a2a3d47 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts @@ -343,6 +343,7 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements * * ``` */ + @DeprecateProperty('`evenRowCSS` is deprecated. We suggest using `rowClasses` property instead.') @Input() public evenRowCSS = 'igx-grid__tr--even'; @@ -354,9 +355,47 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements * * ``` */ + @DeprecateProperty('`oddRowCSS` is deprecated. We suggest using `rowClasses` property instead.') @Input() public oddRowCSS = 'igx-grid__tr--odd'; + /** + * Sets a conditional class selector to the grid's row element. + * Accepts an object literal, containing key-value pairs, + * where the key is the name of the CSS class and the value is + * either a callback function that returns a boolean, or boolean, like so: + * ```typescript + * callback = (row: RowType) => { return row.selected > 6; } + * rowClasses = { 'className' : this.callback }; + * ``` + * ```html + * + * ``` + * + * @memberof IgxColumnComponent + */ + @Input() + public rowClasses: any; + + /** + * Sets conditional style properties on the grid row element. + * It accepts an object literal where the keys are + * the style properties and the value is an expression to be evaluated. + * ```typescript + * styles = { + * background: 'yellow', + * color: (row: RowType) => row.selected : 'red': 'white' + * } + * ``` + * ```html + * + * ``` + * + * @memberof IgxColumnComponent + */ + @Input() + public rowStyles = null; + /** * Gets/Sets the primary key. * From 021540acb34878765c79c1830dccb8e3b55b2ff9 Mon Sep 17 00:00:00 2001 From: ddincheva Date: Wed, 18 Aug 2021 09:14:49 +0300 Subject: [PATCH 02/33] feat(*): initial implementation of rowClasses and rowStyles pipes #9969 --- .../src/lib/grids/common/grid-pipes.module.ts | 12 +++-- .../src/lib/grids/common/pipes.ts | 54 +++++++++++++++++++ 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/common/grid-pipes.module.ts b/projects/igniteui-angular/src/lib/grids/common/grid-pipes.module.ts index b92b7fa91fa..37b4c80649a 100644 --- a/projects/igniteui-angular/src/lib/grids/common/grid-pipes.module.ts +++ b/projects/igniteui-angular/src/lib/grids/common/grid-pipes.module.ts @@ -19,7 +19,9 @@ import { IgxColumnFormatterPipe, IgxSummaryFormatterPipe, IgxGridAddRowPipe, - IgxHeaderGroupWidthPipe + IgxHeaderGroupWidthPipe, + IgxGridRowClassesPipe, + IgxGridRowStylesPipe } from './pipes'; @NgModule({ @@ -42,7 +44,9 @@ import { IgxGridAddRowPipe, IgxColumnFormatterPipe, IgxSummaryFormatterPipe, - IgxHeaderGroupWidthPipe + IgxHeaderGroupWidthPipe, + IgxGridRowClassesPipe, + IgxGridRowStylesPipe ], exports: [ IgxGridFilterConditionPipe, @@ -63,7 +67,9 @@ import { IgxGridAddRowPipe, IgxColumnFormatterPipe, IgxSummaryFormatterPipe, - IgxHeaderGroupWidthPipe + IgxHeaderGroupWidthPipe, + IgxGridRowClassesPipe, + IgxGridRowStylesPipe ], imports: [ CommonModule diff --git a/projects/igniteui-angular/src/lib/grids/common/pipes.ts b/projects/igniteui-angular/src/lib/grids/common/pipes.ts index 98592f730a1..38880c35821 100644 --- a/projects/igniteui-angular/src/lib/grids/common/pipes.ts +++ b/projects/igniteui-angular/src/lib/grids/common/pipes.ts @@ -63,6 +63,60 @@ export class IgxGridCellStylesPipe implements PipeTransform { } } +/** + * @hidden + * @internal + */ + @Pipe({ + name: 'igxGridRowClasses' +}) +export class IgxGridRowClassesPipe implements PipeTransform { + constructor(private gridAPI: GridBaseAPIService) { } + + public transform(cssClasses: { [prop: string]: any }, index: any, __: number): string { + if (!cssClasses) { + return ''; + } + const result = []; + for (const cssClass of Object.keys(cssClasses)) { + const callbackOrValue = cssClasses[cssClass]; + const grid = (this.gridAPI.grid as any); + const row = grid.getRowByIndex(index); + const apply = typeof callbackOrValue === 'function' ? callbackOrValue(row) : callbackOrValue; + if (apply) { + result.push(cssClass); + } + } + return result.join(' '); + } +} + +/** + * @hidden + * @internal + */ + @Pipe({ + name: 'igxGridRowStyles' +}) +export class IgxGridRowStylesPipe implements PipeTransform { + + constructor(private gridAPI: GridBaseAPIService) { } + + public transform(styles: { [prop: string]: any }, index: number, __: number): { [prop: string]: any } { + const css = {}; + if (!styles) { + return css; + } + const grid = (this.gridAPI.grid as any); + for (const prop of Object.keys(styles)) { + const cb = styles[prop]; + const row = grid.getRowByIndex(index); + css[prop] = typeof cb === 'function' ? cb(row) : cb; + } + return css; + } +} + /** * @hidden * @internal From 8f4a6ed9e8ff877064e7b5713f9b3502198b9fd2 Mon Sep 17 00:00:00 2001 From: ddincheva Date: Wed, 18 Aug 2021 09:17:37 +0300 Subject: [PATCH 03/33] feat(*): add rowClasses and rowStyles properties to the data row element #9969 --- .../src/lib/grids/grid/grid.component.html | 8 +++-- .../hierarchical-grid.component.html | 8 +++-- .../grids/tree-grid/tree-grid.component.html | 8 +++-- .../grid-cell-styling.sample.html | 29 +++++++++++++++++++ .../grid-cell-styling.sample.scss | 10 +++++++ .../grid-cell-styling.sample.ts | 16 +++++++++- 6 files changed, 72 insertions(+), 7 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.component.html b/projects/igniteui-angular/src/lib/grids/grid/grid.component.html index 93d16df591c..f00ce3a9c24 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.component.html @@ -93,11 +93,15 @@ - + - + diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html index 51d97f22cc8..965928a7731 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html @@ -67,12 +67,16 @@ - + - + diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html index 0a8118e86e6..303d129ef64 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html @@ -69,11 +69,15 @@ - + - + diff --git a/src/app/gird-cell-styling/grid-cell-styling.sample.html b/src/app/gird-cell-styling/grid-cell-styling.sample.html index b7431557c0f..68ea50b0308 100644 --- a/src/app/gird-cell-styling/grid-cell-styling.sample.html +++ b/src/app/gird-cell-styling/grid-cell-styling.sample.html @@ -31,6 +31,35 @@ > +

Grid sample with rowClasses property applied based on row ID

+ + + + + + + + row.cells.some(s => s.active); + + // eslint-disable-next-line @typescript-eslint/member-ordering + public rowClasses = { + pinnedClass: this.rowCondition, + selected: this.selectedRowCondition + }; + public condition(rowData: any): boolean { return rowData[this.grid1.primaryKey] === 'BLONP'; } @@ -57,6 +67,10 @@ export class GridCellStylingSampleComponent implements OnInit { return rowData[columnKey] > 6; } + public rowCondition(row: RowType) { + return row.pinned; + } + public ngOnInit(): void { this.columns = [ { field: 'ID' }, From 77a599374f78f34809e33f7c9fdfc49df8e8c839 Mon Sep 17 00:00:00 2001 From: ddincheva Date: Thu, 19 Aug 2021 10:12:05 +0300 Subject: [PATCH 04/33] chore(*): update pipe parameters --- .../src/lib/grids/common/pipes.ts | 15 +++++++-------- .../src/lib/grids/grid/grid.component.html | 8 ++++---- .../hierarchical-grid.component.html | 8 ++++---- .../lib/grids/tree-grid/tree-grid.component.html | 8 ++++---- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/common/pipes.ts b/projects/igniteui-angular/src/lib/grids/common/pipes.ts index c900ca8cedf..0d4810ce0f7 100644 --- a/projects/igniteui-angular/src/lib/grids/common/pipes.ts +++ b/projects/igniteui-angular/src/lib/grids/common/pipes.ts @@ -7,7 +7,7 @@ import { GridType } from './grid.interface'; import { IgxColumnComponent } from '../columns/column.component'; import { ColumnDisplayOrder } from './enums'; import { IgxColumnActionsComponent } from '../column-actions/column-actions.component'; -import { IgxSummaryOperand, IgxSummaryResult } from '../grid/public_api'; +import { IgxGridRow, IgxSummaryOperand, IgxSummaryResult } from '../grid/public_api'; /** * @hidden @@ -71,17 +71,17 @@ export class IgxGridCellStylesPipe implements PipeTransform { name: 'igxGridRowClasses' }) export class IgxGridRowClassesPipe implements PipeTransform { - constructor(private gridAPI: GridBaseAPIService) { } - public transform(cssClasses: { [prop: string]: any }, index: any, __: number): string { + constructor(private gridAPI: GridBaseAPIService) { } + + public transform(cssClasses: { [prop: string]: any }, rowData: any, index: number, __: number): string { if (!cssClasses) { return ''; } const result = []; for (const cssClass of Object.keys(cssClasses)) { const callbackOrValue = cssClasses[cssClass]; - const grid = (this.gridAPI.grid as any); - const row = grid.getRowByIndex(index); + const row = new IgxGridRow((this.gridAPI.grid as any), index, rowData); const apply = typeof callbackOrValue === 'function' ? callbackOrValue(row) : callbackOrValue; if (apply) { result.push(cssClass); @@ -102,15 +102,14 @@ export class IgxGridRowStylesPipe implements PipeTransform { constructor(private gridAPI: GridBaseAPIService) { } - public transform(styles: { [prop: string]: any }, index: number, __: number): { [prop: string]: any } { + public transform(styles: { [prop: string]: any }, rowData: any, index: number, __: number): { [prop: string]: any } { const css = {}; if (!styles) { return css; } - const grid = (this.gridAPI.grid as any); for (const prop of Object.keys(styles)) { const cb = styles[prop]; - const row = grid.getRowByIndex(index); + const row = new IgxGridRow((this.gridAPI.grid as any), index, rowData); css[prop] = typeof cb === 'function' ? cb(row) : cb; } return css; diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.component.html b/projects/igniteui-angular/src/lib/grids/grid/grid.component.html index f00ce3a9c24..538b684d07e 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.component.html @@ -94,14 +94,14 @@ + [ngClass]="rowClasses | igxGridRowClasses:rowData:rowIndex:pipeTrigger" + [ngStyle]="rowStyles | igxGridRowStyles:rowData:rowIndex:pipeTrigger" #row> + [ngClass]="rowClasses | igxGridRowClasses:rowData:rowIndex:pipeTrigger" + [ngStyle]="rowStyles | igxGridRowStyles:rowData:rowIndex:pipeTrigger" #row #pinnedRow> diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html index 965928a7731..7582fdc416d 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html @@ -68,15 +68,15 @@ + [ngClass]="rowClasses | igxGridRowClasses:rowData:rowIndex:pipeTrigger" + [ngStyle]="rowStyles | igxGridRowStyles:rowData:rowIndex:pipeTrigger" #row> + [ngClass]="rowClasses | igxGridRowClasses:rowData:rowIndex:pipeTrigger" + [ngStyle]="rowStyles | igxGridRowStyles:rowData:rowIndex:pipeTrigger" #row #pinnedRow> diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html index 303d129ef64..26e37a29770 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html @@ -70,14 +70,14 @@ + [ngClass]="rowClasses | igxGridRowClasses:rowData:rowIndex:pipeTrigger" + [ngStyle]="rowStyles | igxGridRowStyles:rowData:rowIndex:pipeTrigger" #row> + [ngClass]="rowClasses | igxGridRowClasses:rowData:rowIndex:pipeTrigger" + [ngStyle]="rowStyles | igxGridRowStyles:rowData:rowIndex:pipeTrigger"#row #pinnedRow> From 8cf9644b25ba4bab450990dfe1479bd4fe417b65 Mon Sep 17 00:00:00 2001 From: ddincheva Date: Thu, 19 Aug 2021 14:37:20 +0300 Subject: [PATCH 05/33] test(Grid): conditional rowStyles and rowClasses #9969 --- .../lib/grids/grid/grid-row-pinning.spec.ts | 50 +++++++++++++++++-- .../test-utils/grid-base-components.spec.ts | 16 ++++++ 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts index 534a8066853..248514873bd 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-row-pinning.spec.ts @@ -10,13 +10,12 @@ import { IPinningConfig } from '../grid.common'; import { SampleTestData } from '../../test-utils/sample-test-data.spec'; import { GridFunctions } from '../../test-utils/grid-functions.spec'; import { SortingDirection } from '../../data-operations/sorting-expression.interface'; -import { IgxGridTransaction } from '../tree-grid/public_api'; -import { IgxTransactionService } from '../../services/public_api'; import { GridSummaryFunctions } from '../../test-utils/grid-functions.spec'; import { IgxStringFilteringOperand } from '../../data-operations/filtering-condition'; import { IgxPaginatorComponent } from '../../paginator/paginator.component'; import { wait, UIInteractions } from '../../test-utils/ui-interactions.spec'; import { setupGridScrollDetection } from '../../test-utils/helper-utils.spec'; +import { GridRowConditionalStylingComponent } from '../../test-utils/grid-base-components.spec'; describe('Row Pinning #grid', () => { const FIXED_ROW_CONTAINER = '.igx-grid__tr--pinned '; @@ -33,7 +32,8 @@ describe('Row Pinning #grid', () => { GridRowPinningWithMRLComponent, GridRowPinningWithMDVComponent, GridRowPinningWithTransactionsComponent, - GridRowPinningWithInitialPinningComponent + GridRowPinningWithInitialPinningComponent, + GridRowConditionalStylingComponent ], imports: [ NoopAnimationsModule, @@ -1265,6 +1265,50 @@ describe('Row Pinning #grid', () => { expect(grid.hasPinnedRecords).toBeTrue(); }); }); + + describe('Conditional row styling', () => { + + beforeEach(fakeAsync(() => { + fix = TestBed.createComponent(GridRowConditionalStylingComponent); + fix.detectChanges(); + grid = fix.componentInstance.grid; + tick(); + fix.detectChanges(); + })); + + it('Shoud be able to conditionally style rows. Check is the class present in the row native element class list', () => { + fix.detectChanges(); + const firstRow = grid.gridAPI.get_row_by_index(0); + const fourthRow = grid.gridAPI.get_row_by_index(3); + + expect(firstRow).toBeDefined(); + expect(firstRow.element.nativeElement.classList.contains('eventRow')).toBeTrue(); + expect(firstRow.element.nativeElement.classList.contains('oddRow')).toBeFalse(); + expect(fourthRow.element.nativeElement.classList.contains('eventRow')).toBeFalse(); + expect(fourthRow.element.nativeElement.classList.contains('oddRow')).toBeTrue(); + }); + + it('Should apply custom CSS bindings to the grid cells/rows. Check the style attribute to match each binding', () => { + const evenColStyles = { + background: (row) => row.index % 2 === 0 ? 'gray' : 'white', + animation: '0.75s popin' + }; + + fix.detectChanges(); + grid.rowStyles = evenColStyles; + grid.notifyChanges(true); + fix.detectChanges(); + const firstRow = grid.gridAPI.get_row_by_index(0); + const fourthRow = grid.gridAPI.get_row_by_index(3); + + const expectedEvenStyles = 'background: gray; animation: 0.75s ease 0s 1 normal none running popin;'; + const expectedOddStyles = 'background: white; animation: 0.75s ease 0s 1 normal none running popin;'; + + expect(firstRow.element.nativeElement.style.cssText).toEqual(expectedEvenStyles); + expect(fourthRow.element.nativeElement.style.cssText).toEqual(expectedOddStyles); + }); + + }); }); @Component({ diff --git a/projects/igniteui-angular/src/lib/test-utils/grid-base-components.spec.ts b/projects/igniteui-angular/src/lib/test-utils/grid-base-components.spec.ts index e9b68fca1c7..c3d6a200e0e 100644 --- a/projects/igniteui-angular/src/lib/test-utils/grid-base-components.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/grid-base-components.spec.ts @@ -118,6 +118,22 @@ export class GridWithToolbarComponent extends GridWithSizeComponent { public data = SampleTestData.contactInfoData(); } +@Component({ + template: GridTemplateStrings.declareGrid(` [autoGenerate]="true" [rowClasses]="rowClasses"`, + '', '') +}) +export class GridRowConditionalStylingComponent extends GridWithSizeComponent { + + public data = SampleTestData.contactInfoData(); + public evenRowCondition = (row) => row.index % 2 === 0; + public oddRowCondition = (row) => row.index % 2 !== 0; + + // eslint-disable-next-line @typescript-eslint/member-ordering + public rowClasses = { + eventRow: this.evenRowCondition, + oddRow: this.oddRowCondition + }; +} @Component({ template: `
From f3c45e547c964afdbfc569b4d3f0eadcf65468ee Mon Sep 17 00:00:00 2001 From: Stamen Stoychev Date: Fri, 27 Aug 2021 22:35:09 +0300 Subject: [PATCH 06/33] feat(add-row): implementing context-free beginAddRow method #9675 --- CHANGELOG.md | 10 ++- .../src/lib/grids/api.service.ts | 8 +++ .../src/lib/grids/common/crud.service.ts | 3 +- .../src/lib/grids/grid-base.directive.ts | 62 +++++++++++++++++++ .../src/lib/grids/grid/grid-add-row.spec.ts | 33 +++++++++- src/app/grid-add-row/grid-add-row.sample.html | 6 ++ src/app/grid-add-row/grid-add-row.sample.ts | 17 ++++- 7 files changed, 135 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70465739c1b..7764d4a3efa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes for each version of this project will be documented in this file. +## 13.0.0 +- `igxGrid`, `igxHierarchicalGrid`, `igxTreeGrid` + - Added a public method that spawns the add row UI for an arbitrary record in the current data view. It accepts a rowID (PK when one is defined, index otherwise). You can also pass `null` to spawn the UI as the very first record. Please, note that the new record is still added at the end of the data view, after the end-user submits it. + ```typescript + this.grid.beginAddRow('ALFKI'); // spawns the add row UI under the row with PK 'ALFKI' + this.grid.beginAddRow(null); // spawns the add row UI as the first record + ``` + ## 12.1.2 - `igxGrid` - The column formatter callback signature now accepts the row data as an additional argument: @@ -53,7 +61,7 @@ All notable changes for each version of this project will be documented in this - `IgxGridCellComponent`, `IgxTreeGridCellComponent`, `IgxHierarchicalGridCellComponent` are no longer exposed in the public API. Instead, a new class `IgxGridCell` replaces all of these. It is a facade class which exposes only the public API of the above mentioned. Automatic migration will change these imports with `CellType`, which is the interface implemented by `IgxGridCell` - **Behavioral changes** - `getCellByKey`, `getCellByColumn`, `getCellByColumnVisibleIndex`, `row.cells`, `column.cells`, `grid.selectedCells` now return an `IgxGridCell` the `CellType` interface. - - `cell` in `IGridCellEventArgs` is now `CellType`. `IGridCellEventArgs` are emitetd in `cellClick`, `selected`, `contextMenu` and `doubleClick` events. + - `cell` in `IGridCellEventArgs` is now `CellType`. `IGridCellEventArgs` are emitted in `cellClick`, `selected`, `contextMenu` and `doubleClick` events. - `let-cell` property in cell template is now `CellType`. - `getCellByColumnVisibleIndex` is now deprecated and will be removed in next major version. Use `getCellByKey`, `getCellByColumn` instead. diff --git a/projects/igniteui-angular/src/lib/grids/api.service.ts b/projects/igniteui-angular/src/lib/grids/api.service.ts index 6caf115f56d..15a73893be6 100644 --- a/projects/igniteui-angular/src/lib/grids/api.service.ts +++ b/projects/igniteui-angular/src/lib/grids/api.service.ts @@ -393,6 +393,14 @@ export class GridBaseAPIService { return this.grid.primaryKey ? this.getRowData(rowID) : rowID; } + /** + * Returns the index of the record in the data view by pk or -1 if not found or primaryKey is not set. + * @param pk + */ + public get_rec_index_by_id(pk: string | number): number { + return this.grid.primaryKey ? this.grid.dataView.findIndex(rec => rec[this.grid.primaryKey] === pk) : -1; + } + public allow_expansion_state_change(rowID, expanded) { return this.grid.expansionStates.get(rowID) !== expanded; } diff --git a/projects/igniteui-angular/src/lib/grids/common/crud.service.ts b/projects/igniteui-angular/src/lib/grids/common/crud.service.ts index 1f3f9c26430..a0fc63767a6 100644 --- a/projects/igniteui-angular/src/lib/grids/common/crud.service.ts +++ b/projects/igniteui-angular/src/lib/grids/common/crud.service.ts @@ -436,7 +436,7 @@ export class IgxRowAddCrudState extends IgxRowCrudState { * @hidden @internal */ public createAddRowParent(row: IgxRowDirective, newRowAsChild?: boolean) { - const rowIndex = row ? row.index : this.grid.rowList.length - 1; + const rowIndex = row ? row.index : -1; const rowId = row ? row.rowID : (rowIndex >= 0 ? this.grid.rowList.last.rowID : null); const isInPinnedArea = this.grid.isRecordPinnedByViewIndex(rowIndex); @@ -580,6 +580,7 @@ export class IgxGridCRUDService extends IgxRowAddCrudState { this.grid.navigateTo(this.row.index, -1); const dummyRow = this.grid.gridAPI.get_row_by_index(this.row.index); dummyRow.triggerAddAnimation(); + dummyRow.cdr.detectChanges(); dummyRow.addAnimationEnd.pipe(first()).subscribe(() => { const cell = dummyRow.cells.find(c => c.editable); if (cell) { diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts index 5aae5d4d217..8b47d43f1ab 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts @@ -5927,6 +5927,68 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements this.crudService.endEdit(commit, event); } + /** + * Enters add mode for the specified rowID (primary key if one is defined, index otherwise) + * + * @remarks + * If null is passed as rowID, the row adding UI is spawned as the first record in the data view + * @remarks + * Spawning the UI to add a child for a record only works if you provide a rowID + * @example + * ```typescript + * this.grid.beginAddRow('ALFKI'); + * this.grid.beginAddRow(null); + * ``` + * @param rowID - The PK or index to spawn the add row UI for, or null to spawn it as the first record in the data view + * @param asChild - Whether the record should be added as a child. Only applicable to igxTreeGrid. + */ + public beginAddRow(rowID: any, asChild?: boolean): void { + let index = rowID; + if (rowID == null) { + if (asChild) { + console.warn("The record cannot be added as a child to an unspecified record."); + return; + } + index = 0; + } else if (this.primaryKey !== null) { + // find the index of the record with that PK + index = this.gridAPI.get_rec_index_by_id(rowID); + rowID = index; + if (index == -1) { + console.warn("No row with the specified PK was found."); + return; + } + } + // check if the index is valid - won't support anything outside the data view + if (index >= 0 && index < this.dataView.length) { + // check if the index is in the view port + if (index < this.virtualizationState.startIndex || + index >= this.virtualizationState.startIndex + this.virtualizationState.chunkSize) { + this.verticalScrollContainer.chunkLoad + .pipe(first(), takeUntil(this.destroy$)) + .subscribe(() => { + this.beginAddRowForIndex(rowID, asChild); + }); + this.navigateTo(index); + this.notifyChanges(true); + return; + } + this.beginAddRowForIndex(rowID, asChild); + } else { + console.warn("The row with the specified PK or index is outside of the current data view."); + } + } + + protected beginAddRowForIndex(index: number, asChild: boolean = false) { + const row: IgxRowDirective = index == null ? + null : this.rowList.find(r => r.index === index); + if (row !== undefined) { + this.crudService.enterAddRowMode(row, asChild); + } else { + console.warn("No row with the specified PK or index was found."); + } + } + protected switchTransactionService(val: boolean) { if (val) { this._transactions = this.transactionFactory.create(TRANSACTION_TYPE.Base); diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-add-row.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-add-row.spec.ts index 0607e79880c..965b32f7050 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-add-row.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-add-row.spec.ts @@ -1,6 +1,6 @@ import { IgxGridModule, IgxGridComponent } from './public_api'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { TestBed, fakeAsync } from '@angular/core/testing'; +import { TestBed, fakeAsync, tick } from '@angular/core/testing'; import { configureTestSuite } from '../../test-utils/configure-suite'; import { DebugElement } from '@angular/core'; import { GridFunctions, GridSummaryFunctions } from '../../test-utils/grid-functions.spec'; @@ -22,6 +22,8 @@ import { IgxGridRowComponent } from './grid-row.component'; import { takeUntil, first } from 'rxjs/operators'; import { Subject } from 'rxjs'; +const DEBOUNCETIME = 30; + describe('IgxGrid - Row Adding #grid', () => { const GRID_ROW = 'igx-grid-row'; const DISPLAY_CONTAINER = 'igx-display-container'; @@ -479,6 +481,35 @@ describe('IgxGrid - Row Adding #grid', () => { expect(grid.gridAPI.get_row_by_index(1).addRowUI).toBeTrue(); }); + + it('Should scroll and start adding a row as the first one when using the public API method', async () => { + await wait(DEBOUNCETIME); + fixture.detectChanges(); + + grid.navigateTo(20, 0); + + await wait(DEBOUNCETIME); + fixture.detectChanges(); + + grid.beginAddRow(null); + + await wait(DEBOUNCETIME); + fixture.detectChanges(); + + expect(grid.gridAPI.get_row_by_index(0).addRowUI).toBeTrue(); + }); + + xit('Should scroll and start adding a row as for a row that is not in view', async () => { + await wait(DEBOUNCETIME); + fixture.detectChanges(); + + grid.beginAddRow('FAMIA'); + + await wait(DEBOUNCETIME); + fixture.detectChanges(); + + expect(grid.gridAPI.get_row_by_index(8).addRowUI).toBeTrue(); + }); }); describe('Exit add row mode tests', () => { diff --git a/src/app/grid-add-row/grid-add-row.sample.html b/src/app/grid-add-row/grid-add-row.sample.html index 426b8e9a441..708ff7ff158 100644 --- a/src/app/grid-add-row/grid-add-row.sample.html +++ b/src/app/grid-add-row/grid-add-row.sample.html @@ -43,6 +43,12 @@

Settings

{{value}} + + + + + +
diff --git a/src/app/grid-add-row/grid-add-row.sample.ts b/src/app/grid-add-row/grid-add-row.sample.ts index 8ad9c580d4c..4962187c85c 100644 --- a/src/app/grid-add-row/grid-add-row.sample.ts +++ b/src/app/grid-add-row/grid-add-row.sample.ts @@ -1,4 +1,5 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; +import { IgxGridComponent } from 'igniteui-angular'; @Component({ selector: 'app-grid-add-row', @@ -6,6 +7,10 @@ import { Component, OnInit } from '@angular/core'; templateUrl: `grid-add-row.sample.html` }) export class GridAddRowSampleComponent implements OnInit { + + @ViewChild(IgxGridComponent) + public grid: IgxGridComponent; + public data: any[]; public dataFull: any[]; public columns: any[]; @@ -69,4 +74,14 @@ export class GridAddRowSampleComponent implements OnInit { this.data = []; /* eslint-enable max-len */ } + + public beginAddRowAtIndex(index: string) { + const numeric = parseInt(index, 10); + const PK = this.grid.dataView[numeric]['ID']; + this.grid.beginAddRow(PK); + } + + public beginAddRowStart() { + this.grid.beginAddRow(null); + } } From d07c4c4656cb3f58d10d7147cc58f2ad97caeeaf Mon Sep 17 00:00:00 2001 From: Stamen Stoychev Date: Mon, 30 Aug 2021 10:59:50 +0300 Subject: [PATCH 07/33] chore(*): fixing lint warnings --- .../igniteui-angular/src/lib/grids/api.service.ts | 1 + .../src/lib/grids/grid-base.directive.ts | 12 ++++++------ .../src/lib/grids/grid/grid-add-row.spec.ts | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/api.service.ts b/projects/igniteui-angular/src/lib/grids/api.service.ts index 15a73893be6..7020ba52af1 100644 --- a/projects/igniteui-angular/src/lib/grids/api.service.ts +++ b/projects/igniteui-angular/src/lib/grids/api.service.ts @@ -395,6 +395,7 @@ export class GridBaseAPIService { /** * Returns the index of the record in the data view by pk or -1 if not found or primaryKey is not set. + * * @param pk */ public get_rec_index_by_id(pk: string | number): number { diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts index 9e5a10aab54..f4e32619e8a 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts @@ -5976,7 +5976,7 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements let index = rowID; if (rowID == null) { if (asChild) { - console.warn("The record cannot be added as a child to an unspecified record."); + console.warn('The record cannot be added as a child to an unspecified record.'); return; } index = 0; @@ -5984,10 +5984,10 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements // find the index of the record with that PK index = this.gridAPI.get_rec_index_by_id(rowID); rowID = index; - if (index == -1) { - console.warn("No row with the specified PK was found."); + if (index === -1) { + console.warn('No row with the specified PK was found.'); return; - } + } } // check if the index is valid - won't support anything outside the data view if (index >= 0 && index < this.dataView.length) { @@ -6005,7 +6005,7 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements } this.beginAddRowForIndex(rowID, asChild); } else { - console.warn("The row with the specified PK or index is outside of the current data view."); + console.warn('The row with the specified PK or index is outside of the current data view.'); } } @@ -6015,7 +6015,7 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements if (row !== undefined) { this.crudService.enterAddRowMode(row, asChild); } else { - console.warn("No row with the specified PK or index was found."); + console.warn('No row with the specified PK or index was found.'); } } diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-add-row.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-add-row.spec.ts index 965b32f7050..dd0ed026668 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-add-row.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-add-row.spec.ts @@ -487,7 +487,7 @@ describe('IgxGrid - Row Adding #grid', () => { fixture.detectChanges(); grid.navigateTo(20, 0); - + await wait(DEBOUNCETIME); fixture.detectChanges(); From 52e77e2433c6b2a24a5b8fb246debfaee1a1af57 Mon Sep 17 00:00:00 2001 From: mrApptastic <30831839+mrApptastic@users.noreply.github.com> Date: Mon, 6 Sep 2021 16:18:58 +0200 Subject: [PATCH 08/33] Update grid-resources.ts "Gitter" means "fence" in Danish: https://ordnet.dk/ddo/ordbog?query=gitter (In Danish - sorry) Hence, "Tabel" (Table) is a better translation. Perhaps even simply "No data" -> "Ingen data" would be better. --- projects/igniteui-angular-i18n/src/i18n/DA/grid-resources.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/igniteui-angular-i18n/src/i18n/DA/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/DA/grid-resources.ts index be7ae6e6505..b936efe9069 100644 --- a/projects/igniteui-angular-i18n/src/i18n/DA/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/DA/grid-resources.ts @@ -6,7 +6,7 @@ const GridResourceStringsDA_: ExpandRequire = { igx_grid_groupByArea_select_message: 'Vælg alle rækker i gruppen med navnet {0} og værdi {1}.', igx_grid_groupByArea_deselect_message: 'Fravælg alle rækker i gruppen med navnet {0} og værdi {1}.', igx_grid_emptyFilteredGrid_message: 'Ingen poster fundet', - igx_grid_emptyGrid_message: 'Gitter har ingen data', + igx_grid_emptyGrid_message: 'Tabel har ingen data', igx_grid_filter: 'Filter', igx_grid_filter_row_close: 'Luk', igx_grid_filter_row_reset: 'Nulstil', From f7a275d7325196d9bc4804817c0a8764b65834a3 Mon Sep 17 00:00:00 2001 From: Stamen Stoychev Date: Wed, 8 Sep 2021 23:17:17 +0300 Subject: [PATCH 09/33] fix(row-adding): splitting to two methods, fixing pinning #9675 --- CHANGELOG.md | 12 +++-- .../src/lib/grids/common/crud.service.ts | 3 +- .../src/lib/grids/grid-base.directive.ts | 49 +++++++++++++++---- .../src/lib/grids/grid/grid-add-row.spec.ts | 4 +- src/app/grid-add-row/grid-add-row.sample.html | 5 ++ src/app/grid-add-row/grid-add-row.sample.ts | 9 ++-- 6 files changed, 62 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4afe8a6d52d..1635a61e5f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,14 +2,18 @@ All notable changes for each version of this project will be documented in this file. -## 12.1.5 +## 12.1.6 ### New Features - `igxGrid`, `igxHierarchicalGrid`, `igxTreeGrid` - - Added a public method that spawns the add row UI for an arbitrary record in the current data view. It accepts a rowID (PK when one is defined, index otherwise). You can also pass `null` to spawn the UI as the very first record. Please, note that the new record is still added at the end of the data view, after the end-user submits it. + - Added two public methods that spawn the add row UI for an arbitrary record in the current data view. One that accepts a rowID to use as the row the UI spawns under and the other specifying the index at which to spawn it. Please, note that the new record is still added at the end of the data view, after the end-user submits it. ```typescript - this.grid.beginAddRow('ALFKI'); // spawns the add row UI under the row with PK 'ALFKI' - this.grid.beginAddRow(null); // spawns the add row UI as the first record + this.grid.beginAddRowById('ALFKI'); // spawns the add row UI under the row with PK 'ALFKI' + this.grid.beginAddRowById('ALFKI', true); // spawns the add row UI to add a child for the row with PK 'ALFKI' + this.grid.beginAddRowById(null); // spawns the add row UI as the first record + this.grid.beginAddRowByIndex(10); // spawns the add row UI at index 10 + this.grid.beginAddRowByIndex(10, true); // spawns the add row UI to add a child for the row at index 9 + this.grid.beginAddRowByIndex(0); // spawns the add row UI as the first record ``` ## 12.1.3 diff --git a/projects/igniteui-angular/src/lib/grids/common/crud.service.ts b/projects/igniteui-angular/src/lib/grids/common/crud.service.ts index a0fc63767a6..fb5ce90e063 100644 --- a/projects/igniteui-angular/src/lib/grids/common/crud.service.ts +++ b/projects/igniteui-angular/src/lib/grids/common/crud.service.ts @@ -437,8 +437,7 @@ export class IgxRowAddCrudState extends IgxRowCrudState { */ public createAddRowParent(row: IgxRowDirective, newRowAsChild?: boolean) { const rowIndex = row ? row.index : -1; - const rowId = row ? row.rowID : (rowIndex >= 0 ? this.grid.rowList.last.rowID : null); - + const rowId = row ? row.rowID : null; const isInPinnedArea = this.grid.isRecordPinnedByViewIndex(rowIndex); const pinIndex = this.grid.pinnedRecords.findIndex(x => x[this.primaryKey] === rowId); const unpinIndex = this.grid.getUnpinnedIndexById(rowId); diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts index f4e32619e8a..3d9ffe2dd76 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts @@ -156,6 +156,7 @@ import { IgxPaginatorComponent } from '../paginator/paginator.component'; import { IgxGridHeaderRowComponent } from './headers/grid-header-row.component'; import { IgxGridGroupByAreaComponent } from './grouping/grid-group-by-area.component'; import { IgxFlatTransactionFactory, TRANSACTION_TYPE } from '../services/transaction/transaction-factory.service'; +import { SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION } from 'constants'; let FAKE_ROW_ID = -1; const DEFAULT_ITEMS_PER_PAGE = 15; @@ -5958,7 +5959,7 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements } /** - * Enters add mode for the specified rowID (primary key if one is defined, index otherwise) + * Enters add mode by spawning the UI under the specified row by rowID. * * @remarks * If null is passed as rowID, the row adding UI is spawned as the first record in the data view @@ -5966,13 +5967,14 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements * Spawning the UI to add a child for a record only works if you provide a rowID * @example * ```typescript - * this.grid.beginAddRow('ALFKI'); - * this.grid.beginAddRow(null); + * this.grid.beginAddRowById('ALFKI'); + * this.grid.beginAddRowById('ALFKI', true); + * this.grid.beginAddRowById(null); * ``` - * @param rowID - The PK or index to spawn the add row UI for, or null to spawn it as the first record in the data view + * @param rowID - The rowID to spawn the add row UI for, or null to spawn it as the first record in the data view * @param asChild - Whether the record should be added as a child. Only applicable to igxTreeGrid. */ - public beginAddRow(rowID: any, asChild?: boolean): void { + public beginAddRowById(rowID: any, asChild?: boolean): void { let index = rowID; if (rowID == null) { if (asChild) { @@ -5980,20 +5982,25 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements return; } index = 0; - } else if (this.primaryKey !== null) { + } else { // find the index of the record with that PK index = this.gridAPI.get_rec_index_by_id(rowID); rowID = index; if (index === -1) { - console.warn('No row with the specified PK was found.'); + console.warn('No row with the specified ID was found.'); return; } } + if (!this.dataView.length) { + this.beginAddRowForIndex(rowID, asChild); + return; + } // check if the index is valid - won't support anything outside the data view if (index >= 0 && index < this.dataView.length) { // check if the index is in the view port - if (index < this.virtualizationState.startIndex || - index >= this.virtualizationState.startIndex + this.virtualizationState.chunkSize) { + if ((index < this.virtualizationState.startIndex || + index >= this.virtualizationState.startIndex + this.virtualizationState.chunkSize) && + !this.isRecordPinnedByViewIndex(index)) { this.verticalScrollContainer.chunkLoad .pipe(first(), takeUntil(this.destroy$)) .subscribe(() => { @@ -6009,6 +6016,30 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements } } + /** + * Enters add mode by spawning the UI at the specified index. + * + * @remarks + * Accepted values for index are integers from 0 to this.grid.dataView.length + * @remarks + * When adding the row as a child, the parent row is the one at the previous index. You cannot add a child at index 0. + * @example + * ```typescript + * this.grid.beginAddRowByIndex(10); + * this.grid.beginAddRowByIndex(10, true); + * this.grid.beginAddRowByIndex(0); + * ``` + * @param index - The index to spawn the UI at. Accepts integers from 0 to this.grid.dataView.length + * @param asChild - Whether the record should be added as a child. Only applicable to igxTreeGrid. + */ + public beginAddRowByIndex(index: number, asChild?: boolean): void { + if (index === 0) { + return this.beginAddRowById(null, asChild); + } + const record = this.dataView[index - 1]; + return this.beginAddRowById(this.primaryKey ? record[this.primaryKey] : record, asChild); + } + protected beginAddRowForIndex(index: number, asChild: boolean = false) { const row: IgxRowDirective = index == null ? null : this.rowList.find(r => r.index === index); diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-add-row.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-add-row.spec.ts index dd0ed026668..b66d83ad032 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-add-row.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-add-row.spec.ts @@ -491,7 +491,7 @@ describe('IgxGrid - Row Adding #grid', () => { await wait(DEBOUNCETIME); fixture.detectChanges(); - grid.beginAddRow(null); + grid.beginAddRowById(null); await wait(DEBOUNCETIME); fixture.detectChanges(); @@ -503,7 +503,7 @@ describe('IgxGrid - Row Adding #grid', () => { await wait(DEBOUNCETIME); fixture.detectChanges(); - grid.beginAddRow('FAMIA'); + grid.beginAddRowById('FAMIA'); await wait(DEBOUNCETIME); fixture.detectChanges(); diff --git a/src/app/grid-add-row/grid-add-row.sample.html b/src/app/grid-add-row/grid-add-row.sample.html index 708ff7ff158..3433f7a8fe9 100644 --- a/src/app/grid-add-row/grid-add-row.sample.html +++ b/src/app/grid-add-row/grid-add-row.sample.html @@ -49,6 +49,11 @@

Settings

+ + + + + diff --git a/src/app/grid-add-row/grid-add-row.sample.ts b/src/app/grid-add-row/grid-add-row.sample.ts index 4962187c85c..6edce1304be 100644 --- a/src/app/grid-add-row/grid-add-row.sample.ts +++ b/src/app/grid-add-row/grid-add-row.sample.ts @@ -77,11 +77,14 @@ export class GridAddRowSampleComponent implements OnInit { public beginAddRowAtIndex(index: string) { const numeric = parseInt(index, 10); - const PK = this.grid.dataView[numeric]['ID']; - this.grid.beginAddRow(PK); + this.grid.beginAddRowByIndex(numeric); } public beginAddRowStart() { - this.grid.beginAddRow(null); + this.grid.beginAddRowById(null); + } + + public beginAddRowById(string: string) { + this.grid.beginAddRowById(string); } } From a95f1261850a021aefa31fba1d586f4a9c6491dc Mon Sep 17 00:00:00 2001 From: Stamen Stoychev Date: Wed, 8 Sep 2021 23:21:59 +0300 Subject: [PATCH 10/33] chore(*): removing faulty import --- projects/igniteui-angular/src/lib/grids/grid-base.directive.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts index d961c4f30f9..e44a2b54d22 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts @@ -156,7 +156,6 @@ import { IgxPaginatorComponent } from '../paginator/paginator.component'; import { IgxGridHeaderRowComponent } from './headers/grid-header-row.component'; import { IgxGridGroupByAreaComponent } from './grouping/grid-group-by-area.component'; import { IgxFlatTransactionFactory, TRANSACTION_TYPE } from '../services/transaction/transaction-factory.service'; -import { SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION } from 'constants'; let FAKE_ROW_ID = -1; const DEFAULT_ITEMS_PER_PAGE = 15; From 35470acac126508c32e0875d7d8ed85423f3888e Mon Sep 17 00:00:00 2001 From: Stamen Stoychev Date: Fri, 10 Sep 2021 13:47:21 +0300 Subject: [PATCH 11/33] fix(row-adding): api implementation with tree-grid specifics #9429 --- .../src/lib/grids/api.service.ts | 19 +++++++- .../src/lib/grids/grid-base.directive.ts | 5 +-- .../grids/tree-grid/tree-grid-api.service.ts | 26 +++++++++++ .../tree-grid-add-row.sample.html | 45 +++++++++++++------ .../tree-grid-add-row.sample.scss | 16 +++++++ .../tree-grid-add-row.sample.ts | 41 +++++++++++++---- 6 files changed, 127 insertions(+), 25 deletions(-) create mode 100644 src/app/tree-grid-add-row/tree-grid-add-row.sample.scss diff --git a/projects/igniteui-angular/src/lib/grids/api.service.ts b/projects/igniteui-angular/src/lib/grids/api.service.ts index 7020ba52af1..263761d6ade 100644 --- a/projects/igniteui-angular/src/lib/grids/api.service.ts +++ b/projects/igniteui-angular/src/lib/grids/api.service.ts @@ -96,6 +96,21 @@ export class GridBaseAPIService { return this.grid.rowList.find((row) => row.index === rowIndex); } + /** + * Gets the rowID of the record at the specified data view index + * + * @param index + * @param dataCollection + */ + public get_rec_id_by_index(index: number, dataCollection?: any[]): any { + dataCollection = dataCollection || this.grid.data; + if (index >= 0 && index < this.grid.dataView.length) { + const rec = this.grid.dataView[index]; + return this.grid.primaryKey ? rec.data[this.grid.primaryKey] : rec.data; + } + return null; + } + public get_cell_by_key(rowSelector: any, field: string): IgxGridCellComponent { const row = this.get_row_by_key(rowSelector); if (row && row.cells) { @@ -397,8 +412,10 @@ export class GridBaseAPIService { * Returns the index of the record in the data view by pk or -1 if not found or primaryKey is not set. * * @param pk + * @param dataCollection */ - public get_rec_index_by_id(pk: string | number): number { + public get_rec_index_by_id(pk: string | number, dataCollection?: any[]): number { + dataCollection = dataCollection || this.grid.data; return this.grid.primaryKey ? this.grid.dataView.findIndex(rec => rec[this.grid.primaryKey] === pk) : -1; } diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts index e44a2b54d22..5aae291dcd5 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts @@ -5992,7 +5992,7 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements index = 0; } else { // find the index of the record with that PK - index = this.gridAPI.get_rec_index_by_id(rowID); + index = this.gridAPI.get_rec_index_by_id(rowID, this.dataView); rowID = index; if (index === -1) { console.warn('No row with the specified ID was found.'); @@ -6044,8 +6044,7 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements if (index === 0) { return this.beginAddRowById(null, asChild); } - const record = this.dataView[index - 1]; - return this.beginAddRowById(this.primaryKey ? record[this.primaryKey] : record, asChild); + return this.beginAddRowById(this.gridAPI.get_rec_id_by_index(index - 1, this.dataView), asChild); } protected beginAddRowForIndex(index: number, asChild: boolean = false) { diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts index df3ba497ed5..f77f9723e2c 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts @@ -169,6 +169,32 @@ export class IgxTreeGridAPIService extends GridBaseAPIService= 0 && index < this.grid.dataView.length) { + const rec = this.grid.dataView[index]; + return this.grid.primaryKey ? rec.data[this.grid.primaryKey] : rec.data; + } + return null; + } + + /** + * Returns the index of the record in the data view by pk or -1 if not found or primaryKey is not set. + * + * @param pk + * @param dataCollection + */ + public get_rec_index_by_id(pk: string | number, dataCollection?: any[]): number { + dataCollection = dataCollection || this.grid.data; + return this.grid.primaryKey ? this.grid.dataView.findIndex(rec => rec.data[this.grid.primaryKey] === pk) : -1; + } + public addRowToData(data: any, parentRowID?: any) { if (parentRowID !== undefined && parentRowID !== null) { diff --git a/src/app/tree-grid-add-row/tree-grid-add-row.sample.html b/src/app/tree-grid-add-row/tree-grid-add-row.sample.html index 169b8fca1df..d538c964ab4 100644 --- a/src/app/tree-grid-add-row/tree-grid-add-row.sample.html +++ b/src/app/tree-grid-add-row/tree-grid-add-row.sample.html @@ -1,14 +1,33 @@
- - - - - - - - -
+ + + + + + + + + +
+
+ +
+
+ + + + + +
+
+ + + + + +
+
\ No newline at end of file diff --git a/src/app/tree-grid-add-row/tree-grid-add-row.sample.scss b/src/app/tree-grid-add-row/tree-grid-add-row.sample.scss new file mode 100644 index 00000000000..1b78b63822b --- /dev/null +++ b/src/app/tree-grid-add-row/tree-grid-add-row.sample.scss @@ -0,0 +1,16 @@ +.three-columns { + display: flex; + width: 900px; +} + +.column { + flex-grow: 1; + height: 150px; + display: flex; + flex-direction: column; + justify-content: space-around; +} + +.column + .column { + margin-left: 2%; +} \ No newline at end of file diff --git a/src/app/tree-grid-add-row/tree-grid-add-row.sample.ts b/src/app/tree-grid-add-row/tree-grid-add-row.sample.ts index d3962ab5ebc..b9eccf09a1e 100644 --- a/src/app/tree-grid-add-row/tree-grid-add-row.sample.ts +++ b/src/app/tree-grid-add-row/tree-grid-add-row.sample.ts @@ -1,11 +1,15 @@ -import { Component, OnInit } from '@angular/core'; -import { ColumnPinningPosition, RowPinningPosition } from 'igniteui-angular'; +import { Component, OnInit, ViewChild } from '@angular/core'; +import { ColumnPinningPosition, IgxTreeGridComponent, RowPinningPosition } from 'igniteui-angular'; @Component({ selector: 'app-tree-grid-add-row', + styleUrls: ['tree-grid-add-row.sample.scss'], templateUrl: `tree-grid-add-row.sample.html` }) export class TreeGridAddRowSampleComponent implements OnInit { + @ViewChild(IgxTreeGridComponent) + public grid: IgxTreeGridComponent; + public result: string; public data: any[]; @@ -41,8 +45,10 @@ export class TreeGridAddRowSampleComponent implements OnInit { { Salary: 2500, employeeID: 3, PID: -1, firstName: 'Steven', lastName: 'Buchanan', Title: 'CTO' }, // sub of ID 0 { Salary: 2500, employeeID: 4, PID: 0, firstName: 'Janet', lastName: 'Leverling', Title: 'Sales Manager' }, - { Salary: 3500, employeeID: 5, PID: 0, firstName: 'Laura', lastName: 'Callahan', - Title: 'Inside Sales Coordinator' }, + { + Salary: 3500, employeeID: 5, PID: 0, firstName: 'Laura', lastName: 'Callahan', + Title: 'Inside Sales Coordinator' + }, { Salary: 1500, employeeID: 6, PID: 0, firstName: 'Margaret', lastName: 'Peacock', Title: 'Sales Representative' }, { Salary: 2500, employeeID: 7, PID: 0, firstName: 'Michael', lastName: 'Suyama', Title: 'Sales Representative' }, // sub of ID 4 @@ -61,14 +67,33 @@ export class TreeGridAddRowSampleComponent implements OnInit { { Salary: 3500, employeeID: 17, PID: 15, firstName: 'Armand', lastName: 'Ross', Title: 'Product Owner' }, { Salary: 1500, employeeID: 18, PID: 15, firstName: 'Dane', lastName: 'Rodriquez', Title: 'Team Leader' }, // sub of ID 19 - { Salary: 2500, employeeID: 19, PID: 18, firstName: 'Declan', lastName: 'Lester', - Title: 'Senior Software Developer' }, - { Salary: 3500, employeeID: 20, PID: 18, firstName: 'Bernard', lastName: 'Jarvis', - Title: 'Senior Software Developer' }, + { + Salary: 2500, employeeID: 19, PID: 18, firstName: 'Declan', lastName: 'Lester', + Title: 'Senior Software Developer' + }, + { + Salary: 3500, employeeID: 20, PID: 18, firstName: 'Bernard', lastName: 'Jarvis', + Title: 'Senior Software Developer' + }, { Salary: 1500, employeeID: 21, PID: 18, firstName: 'Jason', lastName: 'Clark', Title: 'QA' }, { Salary: 1500, employeeID: 22, PID: 18, firstName: 'Mark', lastName: 'Young', Title: 'QA' }, // sub of ID 20 { Salary: 1500, employeeID: 23, PID: 20, firstName: 'Jeremy', lastName: 'Donaldson', Title: 'Software Developer' } ]; } + + + public beginAddRowAtIndex(index: string) { + const numeric = parseInt(index, 10); + this.grid.beginAddRowByIndex(numeric); + } + + public beginAddRowStart() { + this.grid.beginAddRowById(null); + } + + public beginAddRowById(string: string) { + const numeric = parseInt(string, 10); + this.grid.beginAddRowById(numeric); + } } From c22157ed6edd2544e9eb6097b273063f8ac6da1d Mon Sep 17 00:00:00 2001 From: Stamen Stoychev Date: Fri, 10 Sep 2021 14:10:56 +0300 Subject: [PATCH 12/33] chore(*): resolving an issue in the API from leftover code. --- projects/igniteui-angular/src/lib/grids/api.service.ts | 8 ++++---- .../src/lib/grids/tree-grid/tree-grid-api.service.ts | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/api.service.ts b/projects/igniteui-angular/src/lib/grids/api.service.ts index 263761d6ade..452df1cbbab 100644 --- a/projects/igniteui-angular/src/lib/grids/api.service.ts +++ b/projects/igniteui-angular/src/lib/grids/api.service.ts @@ -104,9 +104,9 @@ export class GridBaseAPIService { */ public get_rec_id_by_index(index: number, dataCollection?: any[]): any { dataCollection = dataCollection || this.grid.data; - if (index >= 0 && index < this.grid.dataView.length) { - const rec = this.grid.dataView[index]; - return this.grid.primaryKey ? rec.data[this.grid.primaryKey] : rec.data; + if (index >= 0 && index < dataCollection.length) { + const rec = dataCollection[index]; + return this.grid.primaryKey ? rec[this.grid.primaryKey] : rec; } return null; } @@ -416,7 +416,7 @@ export class GridBaseAPIService { */ public get_rec_index_by_id(pk: string | number, dataCollection?: any[]): number { dataCollection = dataCollection || this.grid.data; - return this.grid.primaryKey ? this.grid.dataView.findIndex(rec => rec[this.grid.primaryKey] === pk) : -1; + return this.grid.primaryKey ? dataCollection.findIndex(rec => rec[this.grid.primaryKey] === pk) : -1; } public allow_expansion_state_change(rowID, expanded) { diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts index f77f9723e2c..92d45d10a51 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts @@ -177,8 +177,8 @@ export class IgxTreeGridAPIService extends GridBaseAPIService= 0 && index < this.grid.dataView.length) { - const rec = this.grid.dataView[index]; + if (index >= 0 && index < dataCollection.length) { + const rec = dataCollection[index]; return this.grid.primaryKey ? rec.data[this.grid.primaryKey] : rec.data; } return null; @@ -192,7 +192,7 @@ export class IgxTreeGridAPIService extends GridBaseAPIService rec.data[this.grid.primaryKey] === pk) : -1; + return this.grid.primaryKey ? dataCollection.findIndex(rec => rec.data[this.grid.primaryKey] === pk) : -1; } public addRowToData(data: any, parentRowID?: any) { From 6beef3b1af71ecffaa0b79ec097cbc732ee37be4 Mon Sep 17 00:00:00 2001 From: Stamen Stoychev Date: Fri, 10 Sep 2021 16:58:47 +0300 Subject: [PATCH 13/33] fix(row-adding): implementing changes from review comments. --- CHANGELOG.md | 21 +++++++++------- .../src/lib/grids/grid-base.directive.ts | 11 +++----- .../grids/tree-grid/tree-grid.component.ts | 25 +++++++++++++++++++ 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1635a61e5f0..91dfaed27cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,15 +6,18 @@ All notable changes for each version of this project will be documented in this ### New Features - `igxGrid`, `igxHierarchicalGrid`, `igxTreeGrid` - - Added two public methods that spawn the add row UI for an arbitrary record in the current data view. One that accepts a rowID to use as the row the UI spawns under and the other specifying the index at which to spawn it. Please, note that the new record is still added at the end of the data view, after the end-user submits it. - ```typescript - this.grid.beginAddRowById('ALFKI'); // spawns the add row UI under the row with PK 'ALFKI' - this.grid.beginAddRowById('ALFKI', true); // spawns the add row UI to add a child for the row with PK 'ALFKI' - this.grid.beginAddRowById(null); // spawns the add row UI as the first record - this.grid.beginAddRowByIndex(10); // spawns the add row UI at index 10 - this.grid.beginAddRowByIndex(10, true); // spawns the add row UI to add a child for the row at index 9 - this.grid.beginAddRowByIndex(0); // spawns the add row UI as the first record - ``` + - Added two public methods that spawn the add row UI for an arbitrary record in the current data view. One that accepts a rowID to use as the row the UI spawns under and the other accepting an index that has a distinct implementation for `IgxTreeGrid`. Please, refer to the official documentation for more information:[Grid Row Adding](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/row-adding) and [Tree Grid Row Adding](https://www.infragistics.com/products/ignite-ui-angular/angular/components/treegrid/row-adding). + + _Note:_ That the new record is still added at the end of the data view, after the end-user submits it. + ```typescript + this.grid.beginAddRowById('ALFKI'); // spawns the add row UI under the row with PK 'ALFKI' + this.grid.beginAddRowById(null); // spawns the add row UI as the first record + this.grid.beginAddRowByIndex(10); // spawns the add row UI at index 10 + this.grid.beginAddRowByIndex(0); // spawns the add row UI as the first record + this.treeGrid.beginAddRowById('ALFKI', true); // spawns the add row UI to add a child for the row with PK 'ALFKI' + this.treeGrid.beginAddRowByIndex(10, true); // spawns the add row UI to add a child for the row at index 10 + this.treeGrid.beginAddRowByIndex(null); // spawns the add row UI as the first record + ``` ## 12.1.3 diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts index 5aae291dcd5..f656720302a 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts @@ -6029,22 +6029,17 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements * * @remarks * Accepted values for index are integers from 0 to this.grid.dataView.length - * @remarks - * When adding the row as a child, the parent row is the one at the previous index. You cannot add a child at index 0. * @example * ```typescript - * this.grid.beginAddRowByIndex(10); - * this.grid.beginAddRowByIndex(10, true); * this.grid.beginAddRowByIndex(0); * ``` * @param index - The index to spawn the UI at. Accepts integers from 0 to this.grid.dataView.length - * @param asChild - Whether the record should be added as a child. Only applicable to igxTreeGrid. */ - public beginAddRowByIndex(index: number, asChild?: boolean): void { + public beginAddRowByIndex(index: number): void { if (index === 0) { - return this.beginAddRowById(null, asChild); + return this.beginAddRowById(null); } - return this.beginAddRowById(this.gridAPI.get_rec_id_by_index(index - 1, this.dataView), asChild); + return this.beginAddRowById(this.gridAPI.get_rec_id_by_index(index - 1, this.dataView)); } protected beginAddRowForIndex(index: number, asChild: boolean = false) { diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts index efc47f3611b..0bf45875401 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts @@ -605,6 +605,31 @@ export class IgxTreeGridComponent extends IgxGridBaseDirective implements GridTy this.notifyChanges(); } + /** + * Enters add mode by spawning the UI with the context of the specified row by index. + * + * @remarks + * Accepted values for index are integers from 0 to this.grid.dataView.length + * @remarks + * When adding the row as a child, the parent row is the specified row. + * @remarks + * To spawn the UI on top, call the function with index = null or a negative number. In this case trying to add this row as a child will result in error. + * @example + * ```typescript + * this.grid.beginAddRowByIndex(10); + * this.grid.beginAddRowByIndex(10, true); + * this.grid.beginAddRowByIndex(null); + * ``` + * @param index - The index to spawn the UI at. Accepts integers from 0 to this.grid.dataView.length + * @param asChild - Whether the record should be added as a child. Only applicable to igxTreeGrid. + */ + public beginAddRowByIndex(index: number, asChild?: boolean): void { + if (index === null || index < 0) { + return this.beginAddRowById(null, asChild); + } + return this.beginAddRowById(this.gridAPI.get_rec_id_by_index(index, this.dataView), asChild); + } + /** * @hidden */ From c20c99bf1d3f1967bec09ff5095dda463051683a Mon Sep 17 00:00:00 2001 From: Stamen Stoychev Date: Fri, 10 Sep 2021 17:13:47 +0300 Subject: [PATCH 14/33] chore(*): fixing lint error --- .../src/lib/grids/tree-grid/tree-grid.component.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts index 0bf45875401..c452f399732 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts @@ -613,7 +613,8 @@ export class IgxTreeGridComponent extends IgxGridBaseDirective implements GridTy * @remarks * When adding the row as a child, the parent row is the specified row. * @remarks - * To spawn the UI on top, call the function with index = null or a negative number. In this case trying to add this row as a child will result in error. + * To spawn the UI on top, call the function with index = null or a negative number. + * In this case trying to add this row as a child will result in error. * @example * ```typescript * this.grid.beginAddRowByIndex(10); From 9827a3df0d60f770fb58d575af881339c2e0eaf6 Mon Sep 17 00:00:00 2001 From: Radoslav Karaivanov Date: Mon, 13 Sep 2021 10:19:16 +0300 Subject: [PATCH 15/33] perf(grid-rows): Cleaned row style bindings --- .../src/lib/grids/common/pipes.ts | 82 +++++++++++++------ .../src/lib/grids/grid/grid-row.component.ts | 7 +- .../src/lib/grids/grid/grid.component.html | 4 +- .../hierarchical-grid.component.html | 4 +- .../src/lib/grids/row.directive.ts | 23 ------ .../tree-grid/tree-grid-row.component.ts | 9 -- .../grids/tree-grid/tree-grid.component.html | 4 +- 7 files changed, 66 insertions(+), 67 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/common/pipes.ts b/projects/igniteui-angular/src/lib/grids/common/pipes.ts index a261403691a..566d9fb8697 100644 --- a/projects/igniteui-angular/src/lib/grids/common/pipes.ts +++ b/projects/igniteui-angular/src/lib/grids/common/pipes.ts @@ -7,8 +7,16 @@ import { GridType } from './grid.interface'; import { IgxColumnComponent } from '../columns/column.component'; import { ColumnDisplayOrder } from './enums'; import { IgxColumnActionsComponent } from '../column-actions/column-actions.component'; -import { IgxGridRow, IgxSummaryOperand, IgxSummaryResult } from '../grid/public_api'; import { IgxAddRow } from './crud.service'; +import { IgxGridRow } from '../grid-public-row'; +import { IgxTreeGridRowComponent } from '../tree-grid/tree-grid-row.component'; +import { IgxGridRowComponent } from '../grid/grid-row.component'; +import { IgxHierarchicalRowComponent } from '../hierarchical-grid/hierarchical-row.component'; +import { IgxSummaryOperand, IgxSummaryResult } from '../summaries/grid-summary'; + +interface CSSProp { + [prop: string]: any; +} /** * @hidden @@ -19,7 +27,7 @@ import { IgxAddRow } from './crud.service'; }) export class IgxGridCellStyleClassesPipe implements PipeTransform { - public transform(cssClasses: { [prop: string]: any }, _: any, data: any, field: string, index: number, __: number): string { + public transform(cssClasses: CSSProp, _: any, data: any, field: string, index: number, __: number): string { if (!cssClasses) { return ''; } @@ -48,8 +56,7 @@ export class IgxGridCellStyleClassesPipe implements PipeTransform { }) export class IgxGridCellStylesPipe implements PipeTransform { - public transform(styles: { [prop: string]: any }, _: any, data: any, field: string, index: number, __: number): - { [prop: string]: any } { + public transform(styles: CSSProp, _: any, data: any, field: string, index: number, __: number): CSSProp { const css = {}; if (!styles) { return css; @@ -64,31 +71,62 @@ export class IgxGridCellStylesPipe implements PipeTransform { } } +type _RowType = IgxGridRowComponent | IgxTreeGridRowComponent | IgxHierarchicalRowComponent; + /** * @hidden * @internal */ - @Pipe({ - name: 'igxGridRowClasses' -}) +@Pipe({ name: 'igxGridRowClasses' }) export class IgxGridRowClassesPipe implements PipeTransform { + public row: IgxGridRow; - constructor(private gridAPI: GridBaseAPIService) { } + constructor(private gridAPI: GridBaseAPIService) { + this.row = new IgxGridRow(this.gridAPI.grid as any, -1, {}); + } - public transform(cssClasses: { [prop: string]: any }, rowData: any, index: number, __: number): string { - if (!cssClasses) { - return ''; + public transform( + cssClasses: CSSProp, + row: _RowType, + rowData: any, + selected: boolean, + dirty: boolean, + deleted: boolean, + dragging: boolean, + index: number, + mrl: boolean, + _: number + ) { + const result = new Set(['igx-grid__tr', index % 2 ? row.grid.evenRowCSS : row.grid.oddRowCSS]); + const mapping = [ + [selected, 'igx-grid__tr--selected'], + [row.inEditMode, 'igx-grid_-tr--edit'], + [dirty, 'igx-grid__tr--edited'], + [deleted, 'igx-grid__tr--deleted'], + [dragging, 'igx-grid__tr--drag'], + [mrl, 'igx-grid__tr--mrl'] + ]; + + for (const [state, _class] of mapping) { + if (state) { + result.add(_class as string); + } } - const result = []; - for (const cssClass of Object.keys(cssClasses)) { + + if (row instanceof IgxTreeGridRowComponent && row.treeRow.isFilteredOutParent) { + result.add('igx-grid__tr--filtered'); + } + + for (const cssClass of Object.keys(cssClasses ?? {})) { const callbackOrValue = cssClasses[cssClass]; - const row = new IgxGridRow((this.gridAPI.grid as any), index, rowData); - const apply = typeof callbackOrValue === 'function' ? callbackOrValue(row) : callbackOrValue; + this.row.index = index; + (this.row as any)._data = rowData; + const apply = typeof callbackOrValue === 'function' ? callbackOrValue(this.row) : callbackOrValue; if (apply) { - result.push(cssClass); + result.add(cssClass); } } - return result.join(' '); + return result; } } @@ -96,21 +134,19 @@ export class IgxGridRowClassesPipe implements PipeTransform { * @hidden * @internal */ - @Pipe({ - name: 'igxGridRowStyles' -}) +@Pipe({ name: 'igxGridRowStyles' }) export class IgxGridRowStylesPipe implements PipeTransform { constructor(private gridAPI: GridBaseAPIService) { } - public transform(styles: { [prop: string]: any }, rowData: any, index: number, __: number): { [prop: string]: any } { + public transform(styles: CSSProp, rowData: any, index: number, __: number): CSSProp { const css = {}; if (!styles) { return css; } for (const prop of Object.keys(styles)) { const cb = styles[prop]; - const row = new IgxGridRow((this.gridAPI.grid as any), index, rowData); + const row = new IgxGridRow((this.gridAPI.grid as any), index, rowData); css[prop] = typeof cb === 'function' ? cb(row) : cb; } return css; @@ -394,7 +430,7 @@ export class IgxGridAddRowPipe implements PipeTransform { @Pipe({ name: 'igxHeaderGroupWidth' }) export class IgxHeaderGroupWidthPipe implements PipeTransform { - public transform(width: any, minWidth: any, hasLayout: boolean ) { + public transform(width: any, minWidth: any, hasLayout: boolean) { return hasLayout ? '' : `${Math.max(parseFloat(width), minWidth)}px`; } } diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-row.component.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-row.component.ts index de3dc2a6689..8e2f592c0b7 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-row.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-row.component.ts @@ -1,4 +1,4 @@ -import { Component, forwardRef, ChangeDetectionStrategy, HostBinding } from '@angular/core'; +import { Component, forwardRef, ChangeDetectionStrategy } from '@angular/core'; import { IgxGridComponent } from './grid.component'; import { IgxRowDirective } from '../row.directive'; @@ -10,11 +10,6 @@ import { IgxRowDirective } from '../row.directive'; }) export class IgxGridRowComponent extends IgxRowDirective { - @HostBinding('class.igx-grid__tr--mrl') - public get hasColumnLayouts(): boolean { - return this.grid.hasColumnLayouts; - } - public getContext(col, row) { return { $implicit: col, diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.component.html b/projects/igniteui-angular/src/lib/grids/grid/grid.component.html index 978ae869b82..e6e2cc08ffb 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.component.html @@ -94,13 +94,13 @@ diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html index 7f6c857fe8c..a04d3d2e7f0 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html @@ -68,14 +68,14 @@
diff --git a/projects/igniteui-angular/src/lib/grids/row.directive.ts b/projects/igniteui-angular/src/lib/grids/row.directive.ts index 06df8fd35ae..b9d7d50491e 100644 --- a/projects/igniteui-angular/src/lib/grids/row.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/row.directive.ts @@ -211,14 +211,6 @@ export class IgxRowDirective implemen return this.index; } - /** - * @hidden - */ - @HostBinding('class') - get styleClasses(): string { - return this.resolveClasses(); - } - /** * @hidden */ @@ -583,21 +575,6 @@ export class IgxRowDirective implemen this.addAnimationEnd.emit(this); } - /** - * @hidden - */ - protected resolveClasses(): string { - const indexClass = this.index % 2 ? this.grid.evenRowCSS : this.grid.oddRowCSS; - const selectedClass = this.selected ? 'igx-grid__tr--selected' : ''; - const editClass = this.inEditMode ? 'igx-grid__tr--edit' : ''; - const dirtyClass = this.dirty ? 'igx-grid__tr--edited' : ''; - const deletedClass = this.deleted ? 'igx-grid__tr--deleted' : ''; - const mrlClass = this.grid.hasColumnLayouts ? 'igx-grid__tr--mrl' : ''; - const dragClass = this.dragging ? 'igx-grid__tr--drag' : ''; - return `${this.defaultCssClass} ${indexClass} ${selectedClass} ${editClass} ${dirtyClass} - ${deletedClass} ${mrlClass} ${dragClass}`.trim(); - } - /** * @hidden */ diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-row.component.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-row.component.ts index aeff4edbc16..a150bcd45d9 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-row.component.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-row.component.ts @@ -159,13 +159,4 @@ export class IgxTreeGridRowComponent extends IgxRowDirective From 25f208f2e1fe08a15895ff76747683b335a085e8 Mon Sep 17 00:00:00 2001 From: Radoslav Karaivanov Date: Mon, 13 Sep 2021 14:27:26 +0300 Subject: [PATCH 16/33] Address review comments --- .../src/lib/grids/common/pipes.ts | 15 +++++++-------- .../src/lib/grids/grid/grid.component.html | 4 ++-- .../hierarchical-grid.component.html | 4 ++-- .../lib/grids/tree-grid/tree-grid.component.html | 4 ++-- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/common/pipes.ts b/projects/igniteui-angular/src/lib/grids/common/pipes.ts index 566d9fb8697..0e4cee9f97b 100644 --- a/projects/igniteui-angular/src/lib/grids/common/pipes.ts +++ b/projects/igniteui-angular/src/lib/grids/common/pipes.ts @@ -88,23 +88,26 @@ export class IgxGridRowClassesPipe implements PipeTransform { public transform( cssClasses: CSSProp, row: _RowType, - rowData: any, + editMode: boolean, selected: boolean, dirty: boolean, deleted: boolean, dragging: boolean, index: number, mrl: boolean, + filteredOut: boolean, _: number ) { const result = new Set(['igx-grid__tr', index % 2 ? row.grid.evenRowCSS : row.grid.oddRowCSS]); const mapping = [ [selected, 'igx-grid__tr--selected'], - [row.inEditMode, 'igx-grid_-tr--edit'], + [editMode, 'igx-grid__tr--edit'], [dirty, 'igx-grid__tr--edited'], [deleted, 'igx-grid__tr--deleted'], [dragging, 'igx-grid__tr--drag'], - [mrl, 'igx-grid__tr--mrl'] + [mrl, 'igx-grid__tr--mrl'], + // Tree grid only + [filteredOut, 'igx-grid__tr--filtered'] ]; for (const [state, _class] of mapping) { @@ -113,14 +116,10 @@ export class IgxGridRowClassesPipe implements PipeTransform { } } - if (row instanceof IgxTreeGridRowComponent && row.treeRow.isFilteredOutParent) { - result.add('igx-grid__tr--filtered'); - } - for (const cssClass of Object.keys(cssClasses ?? {})) { const callbackOrValue = cssClasses[cssClass]; this.row.index = index; - (this.row as any)._data = rowData; + (this.row as any)._data = row.rowData; const apply = typeof callbackOrValue === 'function' ? callbackOrValue(this.row) : callbackOrValue; if (apply) { result.add(cssClass); diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.component.html b/projects/igniteui-angular/src/lib/grids/grid/grid.component.html index e6e2cc08ffb..fcc9b789609 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.component.html @@ -94,13 +94,13 @@ diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html index a04d3d2e7f0..4a701566e31 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html @@ -68,14 +68,14 @@
diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html index 87b63d50bd5..c1b17663aaf 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html @@ -70,13 +70,13 @@ From 853c638722c0dc2956ab400e4b213835a952880a Mon Sep 17 00:00:00 2001 From: Zdravko Kolev Date: Fri, 10 Sep 2021 18:21:28 +0300 Subject: [PATCH 17/33] fix(grid): Add check for shadowRoot --- .../lib/directives/drag-drop/drag-drop.directive.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/projects/igniteui-angular/src/lib/directives/drag-drop/drag-drop.directive.ts b/projects/igniteui-angular/src/lib/directives/drag-drop/drag-drop.directive.ts index 6b72e1c5d4e..e577d848e0f 100644 --- a/projects/igniteui-angular/src/lib/directives/drag-drop/drag-drop.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/drag-drop/drag-drop.directive.ts @@ -1211,10 +1211,18 @@ export class IgxDragDirective implements AfterContentInit, OnDestroy { originalEvent }; - const elementsFromPoint = this.getElementsAtPoint(pageX, pageY); + let elementsFromPoint = this.getElementsAtPoint(pageX, pageY); + + // Check for shadowRoot instance and use it if present + for (const elFromPoint of elementsFromPoint) { + if (elFromPoint?.shadowRoot !== null) { + elementsFromPoint = elFromPoint.shadowRoot.elementsFromPoint(pageX, pageY); + } + } + for (const element of elementsFromPoint) { if (element.getAttribute('droppable') === 'true' && - element !== this.ghostElement && element !== this.element.nativeElement) { + element !== this.ghostElement && element !== this.element.nativeElement) { topDropArea = element; break; } From bb4b3be535cc4d33865959dd6ebca29cd2728fab Mon Sep 17 00:00:00 2001 From: ddincheva Date: Tue, 14 Sep 2021 09:32:37 +0300 Subject: [PATCH 18/33] chore(*): update the changelog --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9565b5331b2..6ec2f68c745 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,16 @@ All notable changes for each version of this project will be documented in this file. -## 12.1.6 +## 13.0.0 + +### General +- `igxGrid`, `igxHierarchicalGrid`, `igxTreeGrid` + - 'oddRowCSS' and 'evenRowCSS' properties has been deprecated ### New Features - `igxGrid`, `igxHierarchicalGrid`, `igxTreeGrid` - Added capability to restore the state of multi column headers with `IgxGridStateDirective`. + - Introduced new 'rowStyles' and 'rowClasses' grid properties which allows to define a custom styling on each grid row ## 12.1.3 From 0692da1170a904523b70c9a4dbae86746377d819 Mon Sep 17 00:00:00 2001 From: Hristo Anastasov Date: Tue, 14 Sep 2021 11:55:57 +0300 Subject: [PATCH 19/33] chore(*): update version in changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7a5f28a453..b07453d56fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes for each version of this project will be documented in this file. -## 13.0.0 +## 12.2.0 ### General - `igxGrid`, `igxHierarchicalGrid`, `igxTreeGrid` From 2cd179e0ec6fe5f7579d7445ac13ca608b39b489 Mon Sep 17 00:00:00 2001 From: Rumyana Andriova <54146583+randriova@users.noreply.github.com> Date: Wed, 15 Sep 2021 15:36:49 +0300 Subject: [PATCH 20/33] feat(i18n): Adding Norwegian language - master --- .../src/i18n/NB/calendar-resources.ts | 24 +++ .../src/i18n/NB/carousel-resources.ts | 14 ++ .../src/i18n/NB/date-picker-resources.ts | 12 ++ .../i18n/NB/date-range-picker-resources.ts | 12 ++ .../src/i18n/NB/grid-resources.ts | 141 ++++++++++++++++++ .../src/i18n/NB/list-resources.ts | 12 ++ .../src/i18n/NB/paginator-resources.ts | 16 ++ .../src/i18n/NB/resources.ts | 24 +++ .../src/i18n/NB/time-picker-resources.ts | 14 ++ .../src/i18n/NB/tree-resources.ts | 12 ++ projects/igniteui-angular-i18n/src/index.ts | 11 ++ 11 files changed, 292 insertions(+) create mode 100644 projects/igniteui-angular-i18n/src/i18n/NB/calendar-resources.ts create mode 100644 projects/igniteui-angular-i18n/src/i18n/NB/carousel-resources.ts create mode 100644 projects/igniteui-angular-i18n/src/i18n/NB/date-picker-resources.ts create mode 100644 projects/igniteui-angular-i18n/src/i18n/NB/date-range-picker-resources.ts create mode 100644 projects/igniteui-angular-i18n/src/i18n/NB/grid-resources.ts create mode 100644 projects/igniteui-angular-i18n/src/i18n/NB/list-resources.ts create mode 100644 projects/igniteui-angular-i18n/src/i18n/NB/paginator-resources.ts create mode 100644 projects/igniteui-angular-i18n/src/i18n/NB/resources.ts create mode 100644 projects/igniteui-angular-i18n/src/i18n/NB/time-picker-resources.ts create mode 100644 projects/igniteui-angular-i18n/src/i18n/NB/tree-resources.ts diff --git a/projects/igniteui-angular-i18n/src/i18n/NB/calendar-resources.ts b/projects/igniteui-angular-i18n/src/i18n/NB/calendar-resources.ts new file mode 100644 index 00000000000..47991d0c2c1 --- /dev/null +++ b/projects/igniteui-angular-i18n/src/i18n/NB/calendar-resources.ts @@ -0,0 +1,24 @@ +import { ICalendarResourceStrings } from 'igniteui-angular'; + +// exported below as re-cast to create declaration type with expanded properties +const CalendarResourceStringsNB_: ExpandRequire = { + igx_calendar_previous_month: 'Forrige måned', + igx_calendar_next_month: 'Neste måned', + igx_calendar_select_month: 'Velg måned', + igx_calendar_select_year: 'Velg år', + igx_calendar_range_start: 'Rekkevidde start', + igx_calendar_range_end: 'Rekkevidde slutt', + igx_calendar_selected_month_is: 'Valgt måned er ', + igx_calendar_first_picker_of: 'Den første plukkeren på {0} starter fra', + igx_calendar_multi_selection: 'Flervalgskalender med {0} datovelgere', + igx_calendar_range_selection: 'Områdevalgskalender med {0} datovelgere', + igx_calendar_single_selection: 'Kalender med {0} datovelgere', + igx_calendar_singular_multi_selection: 'Kalender med flere valg', + igx_calendar_singular_range_selection: 'Områdevalgskalender', + igx_calendar_singular_single_selection: 'Kalender' +}; + +/** + * Norwegian resource strings for IgxCalendar + */ +export const CalendarResourceStringsNB = CalendarResourceStringsNB_ as ExpandRequire; diff --git a/projects/igniteui-angular-i18n/src/i18n/NB/carousel-resources.ts b/projects/igniteui-angular-i18n/src/i18n/NB/carousel-resources.ts new file mode 100644 index 00000000000..0e1a1e899c7 --- /dev/null +++ b/projects/igniteui-angular-i18n/src/i18n/NB/carousel-resources.ts @@ -0,0 +1,14 @@ +import { ICarouselResourceStrings } from 'igniteui-angular'; + +// exported below as re-cast to create declaration type with expanded properties +const CarouselResourceStringsNB_: ExpandRequire = { + igx_carousel_of: 'av', + igx_carousel_slide: 'lysbilde', + igx_carousel_previous_slide: 'forrige lysbilde', + igx_carousel_next_slide: 'neste lysbilde' +}; + +/** + * Norwegian resource strings for IgxCarousel + */ +export const CarouselResourceStringsNB = CarouselResourceStringsNB_ as ExpandRequire; diff --git a/projects/igniteui-angular-i18n/src/i18n/NB/date-picker-resources.ts b/projects/igniteui-angular-i18n/src/i18n/NB/date-picker-resources.ts new file mode 100644 index 00000000000..2d415e5bfaf --- /dev/null +++ b/projects/igniteui-angular-i18n/src/i18n/NB/date-picker-resources.ts @@ -0,0 +1,12 @@ +import { IDatePickerResourceStrings } from 'igniteui-angular'; + +// exported below as re-cast to create declaration type with expanded properties +const DatePickerResourceStringsNB_: ExpandRequire = { + igx_date_picker_change_date: 'Endre dato', + igx_date_picker_choose_date: 'Velg dato' +}; + +/** + * Portuguese resource strings for IgxDatePicker + */ +export const DatePickerResourceStringsNB = DatePickerResourceStringsNB_ as ExpandRequire; diff --git a/projects/igniteui-angular-i18n/src/i18n/NB/date-range-picker-resources.ts b/projects/igniteui-angular-i18n/src/i18n/NB/date-range-picker-resources.ts new file mode 100644 index 00000000000..f8db0b592c9 --- /dev/null +++ b/projects/igniteui-angular-i18n/src/i18n/NB/date-range-picker-resources.ts @@ -0,0 +1,12 @@ +import { IDateRangePickerResourceStrings } from 'igniteui-angular'; + +// exported below as re-cast to create declaration type with expanded properties +const DateRangePickerResourceStringsNB_: ExpandRequire = { + igx_date_range_picker_date_separator: 'til', + igx_date_range_picker_done_button: 'Ferdig' +}; + +/** + * Norwegian resource strings for IgxDateRangePicker + */ +export const DateRangePickerResourceStringsNB = DateRangePickerResourceStringsNB_ as ExpandRequire; diff --git a/projects/igniteui-angular-i18n/src/i18n/NB/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/NB/grid-resources.ts new file mode 100644 index 00000000000..ef969195657 --- /dev/null +++ b/projects/igniteui-angular-i18n/src/i18n/NB/grid-resources.ts @@ -0,0 +1,141 @@ +import { IGridResourceStrings } from 'igniteui-angular'; + +// exported below as re-cast to create declaration type with expanded properties +const GridResourceStringsNB_: ExpandRequire = { + igx_grid_groupByArea_message: 'Dra en kolonneoverskrift og slipp den her for å gruppere etter den kolonnen.', + igx_grid_groupByArea_select_message: 'Velg alle radene i gruppen med feltnavn {0} og verdi {1}.', + igx_grid_groupByArea_deselect_message: 'Opphev valg av alle radene i gruppen med feltnavn {0} og verdi {1}.', + igx_grid_emptyFilteredGrid_message: 'Ingen opptak funnet.', + igx_grid_emptyGrid_message: 'Rutenettet har ingen data.', + igx_grid_filter: 'Filter', + igx_grid_filter_row_close: 'Lukk', + igx_grid_filter_row_reset: 'Nullstille', + igx_grid_filter_row_placeholder: 'Legg til filterverdi', + igx_grid_filter_row_boolean_placeholder: 'Alle', + igx_grid_filter_row_date_placeholder: 'Hentedato', + igx_grid_filter_row_time_placeholder: 'Hentetid', + igx_grid_filter_operator_and: 'Og', + igx_grid_filter_operator_or: 'Eller', + igx_grid_complex_filter: 'Kompleks filter', + igx_grid_filter_contains: 'Inneholder', + igx_grid_filter_doesNotContain: 'Inneholder ikke', + igx_grid_filter_startsWith: 'Begynner med', + igx_grid_filter_endsWith: 'Slutter med', + igx_grid_filter_equals: 'Er lik', + igx_grid_filter_doesNotEqual: 'Er ikke lik', + igx_grid_filter_empty: 'Tømme', + igx_grid_filter_notEmpty: 'Ikke tom', + igx_grid_filter_null: 'Null', + igx_grid_filter_notNull: 'Ikke null', + igx_grid_filter_before: 'Før', + igx_grid_filter_after: 'Etter', + igx_grid_filter_at: 'På', + igx_grid_filter_not_at: 'Ikke på', + igx_grid_filter_at_before: 'Kl. eller før', + igx_grid_filter_at_after: 'Kl. eller etter', + igx_grid_filter_today: 'I dag', + igx_grid_filter_yesterday: 'I går', + igx_grid_filter_thisMonth: 'Denne måneden', + igx_grid_filter_lastMonth: 'Forrige måned', + igx_grid_filter_nextMonth: 'Neste måned', + igx_grid_filter_thisYear: 'I år', + igx_grid_filter_lastYear: 'I fjor', + igx_grid_filter_nextYear: 'Neste år', + igx_grid_filter_greaterThan: 'Større enn', + igx_grid_filter_lessThan: 'Mindre enn', + igx_grid_filter_greaterThanOrEqualTo: 'Større enn eller lik', + igx_grid_filter_lessThanOrEqualTo: 'Mindre enn eller lik', + igx_grid_filter_true: 'True', + igx_grid_filter_false: 'False', + igx_grid_filter_all: 'Alle', + igx_grid_filter_condition_placeholder: 'Velg filter', + igx_grid_summary_count: 'Telle', + igx_grid_summary_min: 'Min', + igx_grid_summary_max: 'Maks', + igx_grid_summary_sum: 'Sum', + igx_grid_summary_average: 'Gj.sn', + igx_grid_summary_earliest: 'Tidligst', + igx_grid_summary_latest: 'Siste', + igx_grid_excel_filter_moving_left: 'gå til venstre', + igx_grid_excel_filter_moving_left_short: 'venstre', + igx_grid_excel_filter_moving_right: 'Flytt til høyre', + igx_grid_excel_filter_moving_right_short: 'Ikke sant', + igx_grid_excel_filter_moving_header: 'bevege seg', + igx_grid_excel_filter_sorting_asc: 'stigende', + igx_grid_excel_filter_sorting_asc_short: 'stige', + igx_grid_excel_filter_sorting_desc: 'synkende', + igx_grid_excel_filter_sorting_desc_short: 'synk', + igx_grid_excel_filter_sorting_header: 'sortere', + igx_grid_excel_filter_clear: 'Fjern kolonnefiltre', + igx_grid_excel_custom_dialog_add: 'legg til filter', + igx_grid_excel_custom_dialog_clear: 'Tøm filteret', + igx_grid_excel_custom_dialog_header: 'Egendefinert automatisk filtrering i kolonnen: ', + igx_grid_excel_cancel: 'avbryt', + igx_grid_excel_apply: 'søke om', + igx_grid_excel_search_placeholder: 'Søk', + igx_grid_excel_select_all: 'Velg alle', + igx_grid_excel_select_all_search_results: 'Velg alle søkeresultatene', + igx_grid_excel_add_to_filter: 'Legg til gjeldende valg for å filtrere', + igx_grid_excel_blanks: '(Tomme)', + igx_grid_excel_hide: 'Skjul kolonne', + igx_grid_excel_show: 'Vis kolonne', + igx_grid_excel_pin: 'Fest kolonne', + igx_grid_excel_unpin: 'Løsne kolonnen', + igx_grid_excel_select: 'Velg kolonne', + igx_grid_excel_deselect: 'Opphev valg av kolonne', + igx_grid_excel_text_filter: 'Tekstfilter', + igx_grid_excel_number_filter: 'Nummerfilter', + igx_grid_excel_date_filter: 'Datofilter', + igx_grid_excel_boolean_filter: 'Boolsk filter', + igx_grid_excel_currency_filter: 'Valutafilter', + igx_grid_excel_custom_filter: 'Tilpasset filter...', + igx_grid_advanced_filter_title: 'Avansert filtrering', + igx_grid_advanced_filter_and_group: '"Og"-gruppe', + igx_grid_advanced_filter_or_group: '"Eller"-gruppe', + igx_grid_advanced_filter_end_group: 'Sluttgruppe', + igx_grid_advanced_filter_create_and_group: 'Opprett "Og"-gruppe', + igx_grid_advanced_filter_create_or_group: 'Opprett "Eller"-gruppe', + igx_grid_advanced_filter_and_label: 'og', + igx_grid_advanced_filter_or_label: 'eller', + igx_grid_advanced_filter_add_condition: 'Tilstand', + igx_grid_advanced_filter_ungroup: 'Opphev gruppering', + igx_grid_advanced_filter_delete: 'Slett', + igx_grid_advanced_filter_delete_filters: 'Slett filtre', + igx_grid_advanced_filter_initial_text: 'Start med å opprette en gruppe forhold knyttet til "Og" eller "Eller"', + igx_grid_advanced_filter_column_placeholder: 'Velg kolonne', + igx_grid_advanced_filter_value_placeholder: 'Verdi', + igx_grid_pinned_row_indicator: 'Festet', + igx_grid_hiding_check_all_label: 'Gjem alle', + igx_grid_hiding_uncheck_all_label: 'Vis alt', + igx_grid_pinning_check_all_label: 'Fest alle', + igx_grid_pinning_uncheck_all_label: 'Løsne alle', + igx_grid_row_edit_btn_done: 'Ferdig', + igx_grid_row_edit_btn_cancel: 'Avbryt', + igx_grid_toolbar_actions_filter_prompt: 'Filtrer kolonneliste...', + igx_grid_toolbar_pinning_button_tooltip: 'Åpne rullegardinmenyen for kolonnefester', + igx_grid_toolbar_hiding_button_tooltip: 'Åpne kolonne som skjuler rullegardinmenyen', + igx_grid_toolbar_pinning_title: 'Festede kolonner', + igx_grid_toolbar_hiding_title: 'Synlige kolonner', + igx_grid_toolbar_advanced_filtering_button_tooltip: 'Åpne avansert filtreringsdialogboks', + igx_grid_toolbar_advanced_filtering_button_label: 'Avansert filtrering', + igx_grid_toolbar_exporter_button_tooltip: 'Åpne rullegardinmenyen for eksportør', + igx_grid_toolbar_exporter_button_label: 'Eksporter', + igx_grid_toolbar_exporter_excel_entry_text: 'Eksporter til Excel', + igx_grid_toolbar_exporter_csv_entry_text: 'Eksporter til CSV', + igx_grid_snackbar_addrow_label: 'Rad lagt til', + igx_grid_snackbar_addrow_actiontext: 'FORESTILLING', + igx_grid_actions_edit_label: 'Redigere', + igx_grid_actions_add_label: 'Legge til', + igx_grid_add_row_label: 'LEGG TIL RAD', + igx_grid_actions_add_child_label: 'Legg til barn', + igx_grid_actions_delete_label: 'Slett', + igx_grid_actions_pin_label: 'Fest', + igx_grid_actions_unpin_label: 'Løsne', + igx_grid_actions_jumpUp_label: 'Hoppe opp', + igx_grid_actions_jumpDown_label: 'Hopp ned' +}; + +/** + * Norwegian resource strings for IgxGrid + */ +export const GridResourceStringsNB = GridResourceStringsNB_ as ExpandRequire; diff --git a/projects/igniteui-angular-i18n/src/i18n/NB/list-resources.ts b/projects/igniteui-angular-i18n/src/i18n/NB/list-resources.ts new file mode 100644 index 00000000000..65a2e747e0d --- /dev/null +++ b/projects/igniteui-angular-i18n/src/i18n/NB/list-resources.ts @@ -0,0 +1,12 @@ +import { IListResourceStrings } from 'igniteui-angular'; + +// exported below as re-cast to create declaration type with expanded properties +const ListResourceStringsNB_: ExpandRequire = { + igx_list_no_items: 'Det er ingen elementer på listen.', + igx_list_loading: 'Laster inn data fra serveren...' +}; + +/** + * Norwegian resource strings for IgxList + */ +export const ListResourceStringsNB = ListResourceStringsNB_ as ExpandRequire; diff --git a/projects/igniteui-angular-i18n/src/i18n/NB/paginator-resources.ts b/projects/igniteui-angular-i18n/src/i18n/NB/paginator-resources.ts new file mode 100644 index 00000000000..8b89db6262d --- /dev/null +++ b/projects/igniteui-angular-i18n/src/i18n/NB/paginator-resources.ts @@ -0,0 +1,16 @@ +import { IPaginatorResourceStrings } from 'igniteui-angular'; + +// exported below as re-cast to create declaration type with expanded properties +const PaginatorResourceStringsNB_: ExpandRequire = { + igx_paginator_label: 'Elementer per side', + igx_paginator_pager_text: 'av', + igx_paginator_first_page_button_text: 'Gå til første side', + igx_paginator_previous_page_button_text: 'Forrige side', + igx_paginator_last_page_button_text: 'Gå til siste side', + igx_paginator_next_page_button_text: 'Neste side' +}; + +/** + * Norwegian resource strings for IgxPaginator + */ +export const PaginatorResourceStringsNB = PaginatorResourceStringsNB_ as ExpandRequire; diff --git a/projects/igniteui-angular-i18n/src/i18n/NB/resources.ts b/projects/igniteui-angular-i18n/src/i18n/NB/resources.ts new file mode 100644 index 00000000000..955174c335a --- /dev/null +++ b/projects/igniteui-angular-i18n/src/i18n/NB/resources.ts @@ -0,0 +1,24 @@ +import { GridResourceStringsNB } from './grid-resources'; +import { PaginatorResourceStringsNB } from './paginator-resources'; +import { TimePickerResourceStringsNB } from './time-picker-resources'; +import { DatePickerResourceStringsNB } from './date-picker-resources'; +import { DateRangePickerResourceStringsNB } from './date-range-picker-resources'; +import { CarouselResourceStringsNB } from './carousel-resources'; +import { ListResourceStringsNB } from './list-resources'; +import { CalendarResourceStringsNB } from './calendar-resources'; +import { TreeResourceStringsNB } from './tree-resources'; + +/** + * Norwegian resource strings for all components + */ +export const IgxResourceStringsNB = { + ...GridResourceStringsNB, + ...PaginatorResourceStringsNB, + ...TimePickerResourceStringsNB, + ...DatePickerResourceStringsNB, + ...DateRangePickerResourceStringsNB, + ...CarouselResourceStringsNB, + ...ListResourceStringsNB, + ...CalendarResourceStringsNB, + ...TreeResourceStringsNB +}; diff --git a/projects/igniteui-angular-i18n/src/i18n/NB/time-picker-resources.ts b/projects/igniteui-angular-i18n/src/i18n/NB/time-picker-resources.ts new file mode 100644 index 00000000000..8997e417ac2 --- /dev/null +++ b/projects/igniteui-angular-i18n/src/i18n/NB/time-picker-resources.ts @@ -0,0 +1,14 @@ +import { ITimePickerResourceStrings } from 'igniteui-angular'; + +// exported below as re-cast to create declaration type with expanded properties +const TimePickerResourceStringsNB_: ExpandRequire = { + igx_time_picker_ok: 'OK', + igx_time_picker_cancel: 'Avbryt', + igx_time_picker_change_time: 'Endre tid', + igx_time_picker_choose_time: 'Velg tid' +}; + +/** + * Norwegian resource strings for IgxTimePicker + */ +export const TimePickerResourceStringsNB = TimePickerResourceStringsNB_ as ExpandRequire; diff --git a/projects/igniteui-angular-i18n/src/i18n/NB/tree-resources.ts b/projects/igniteui-angular-i18n/src/i18n/NB/tree-resources.ts new file mode 100644 index 00000000000..468c045b483 --- /dev/null +++ b/projects/igniteui-angular-i18n/src/i18n/NB/tree-resources.ts @@ -0,0 +1,12 @@ +import { ITreeResourceStrings } from 'igniteui-angular'; + +// exported below as re-cast to create declaration type with expanded properties +const TreeResourceStringsNB_: ExpandRequire = { + igx_expand: 'Vis', + igx_collapse: 'Skjul' +}; + +/** + * Norwegian resource strings for IgxTree + */ +export const TreeResourceStringsNB = TreeResourceStringsNB_ as ExpandRequire; diff --git a/projects/igniteui-angular-i18n/src/index.ts b/projects/igniteui-angular-i18n/src/index.ts index f63d91a793f..cb5ecb33a5a 100644 --- a/projects/igniteui-angular-i18n/src/index.ts +++ b/projects/igniteui-angular-i18n/src/index.ts @@ -198,3 +198,14 @@ export * from './i18n/TR/carousel-resources'; export * from './i18n/TR/list-resources'; export * from './i18n/TR/tree-resources'; export * from './i18n/TR/resources'; +// Norwegian (NB) +export * from './i18n/NB/calendar-resources'; +export * from './i18n/NB/grid-resources'; +export * from './i18n/NB/paginator-resources'; +export * from './i18n/NB/time-picker-resources'; +export * from './i18n/NB/date-picker-resources'; +export * from './i18n/NB/date-range-picker-resources'; +export * from './i18n/NB/carousel-resources'; +export * from './i18n/NB/list-resources'; +export * from './i18n/NB/tree-resources'; +export * from './i18n/NB/resources'; From 43a7f49630134750e544a26e3c8d767be54b3fb2 Mon Sep 17 00:00:00 2001 From: Marin Popov Date: Wed, 15 Sep 2021 18:51:51 +0300 Subject: [PATCH 21/33] fix(dialog): Reset letter-spacing for all nested elements inside the dialog-content. (#10113) Co-authored-by: MPopov Co-authored-by: Simeon Simeonoff --- .../src/lib/core/styles/components/dialog/_dialog-theme.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/projects/igniteui-angular/src/lib/core/styles/components/dialog/_dialog-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/dialog/_dialog-theme.scss index 320d33de67f..edc73c5f7f4 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/dialog/_dialog-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/dialog/_dialog-theme.scss @@ -221,5 +221,9 @@ @include igx-type-style($type-scale, $content) { margin: 0; } + + > * { + letter-spacing: normal; + } } } From 71b44886f80f29660ea713b815c7bf2d7e7e5722 Mon Sep 17 00:00:00 2001 From: igdmdimitrov <49060557+igdmdimitrov@users.noreply.github.com> Date: Thu, 16 Sep 2021 13:46:03 +0300 Subject: [PATCH 22/33] fix(esf): added missing aria related attributes - master (#10105) * fix(esf): added missing aria related attributes Co-authored-by: Galina Edinakova --- .../excel-style/excel-style-clear-filters.component.html | 3 ++- .../excel-style/excel-style-conditional-filter.component.html | 4 +++- .../filtering/excel-style/excel-style-hiding.component.html | 3 ++- .../filtering/excel-style/excel-style-pinning.component.html | 3 ++- .../excel-style/excel-style-selecting.component.html | 4 +++- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-clear-filters.component.html b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-clear-filters.component.html index 15729aea30d..daf5c34339d 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-clear-filters.component.html +++ b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-clear-filters.component.html @@ -2,7 +2,8 @@ tabindex="0" [ngClass]="clearFilterClass()" (keydown)="onClearFilterKeyDown($event)" - (click)="clearFilter()"> + (click)="clearFilter()" + role="menuitem"> {{ esf.grid.resourceStrings.igx_grid_excel_filter_clear }} clear diff --git a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-conditional-filter.component.html b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-conditional-filter.component.html index fd9125e0c44..367febf178b 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-conditional-filter.component.html +++ b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-conditional-filter.component.html @@ -3,7 +3,9 @@ class="igx-excel-filter__actions-filter" (keydown)="onTextFilterKeyDown($event)" (click)="onTextFilterClick($event)" - [igxDropDownItemNavigation]="subMenu"> + [igxDropDownItemNavigation]="subMenu" + role="menuitem" + aria-haspopup="true"> {{ subMenuText }} keyboard_arrow_right diff --git a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-hiding.component.html b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-hiding.component.html index 0321b6daa08..a2b9f676415 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-hiding.component.html +++ b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-hiding.component.html @@ -1,7 +1,8 @@
+ (click)="esf.onHideToggle()" + role="menuitem"> {{ esf.column.hidden ? esf.grid.resourceStrings.igx_grid_excel_show : esf.grid.resourceStrings.igx_grid_excel_hide }} {{ esf.column.hidden ? 'visibility' : 'visibility_off' }}
diff --git a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-pinning.component.html b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-pinning.component.html index 20bb7280e9b..7074ecacff6 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-pinning.component.html +++ b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-pinning.component.html @@ -1,7 +1,8 @@
+ tabindex="0" + role="menuitem"> {{ esf.column.pinned ? esf.grid.resourceStrings.igx_grid_excel_unpin : esf.grid.resourceStrings.igx_grid_excel_pin }}
diff --git a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-selecting.component.html b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-selecting.component.html index ce1438f7783..88f2274c60b 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-selecting.component.html +++ b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-selecting.component.html @@ -1,7 +1,9 @@
+ (click)="esf.onSelect()" + role="button" + [attr.aria-pressed]="esf.column.selected"> {{esf.grid.resourceStrings.igx_grid_excel_select }} done
From de5e5c4f15eb90de174e1811fb3784583c59d0b1 Mon Sep 17 00:00:00 2001 From: jackofdiamond5 <16020256+jackofdiamond5@users.noreply.github.com> Date: Wed, 18 Aug 2021 15:29:33 +0300 Subject: [PATCH 23/33] feat(stepper): add initial files --- .../lib/stepper/igx-stepper.component.html | 1 + .../src/lib/stepper/igx-stepper.component.ts | 61 +++++++++++++++++++ .../lib/stepper/step/igx-step.component.html | 4 ++ .../lib/stepper/step/igx-step.component.ts | 53 ++++++++++++++++ src/app/app.module.ts | 8 ++- src/app/app.routing.ts | 5 ++ src/app/routing.ts | 5 ++ src/app/stepper/stepper.sample.html | 51 ++++++++++++++++ src/app/stepper/stepper.sample.scss | 0 src/app/stepper/stepper.sample.ts | 7 +++ 10 files changed, 193 insertions(+), 2 deletions(-) create mode 100644 projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html create mode 100644 projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts create mode 100644 projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html create mode 100644 projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts create mode 100644 src/app/stepper/stepper.sample.html create mode 100644 src/app/stepper/stepper.sample.scss create mode 100644 src/app/stepper/stepper.sample.ts diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html new file mode 100644 index 00000000000..2277fc6c9fd --- /dev/null +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html @@ -0,0 +1 @@ + diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts new file mode 100644 index 00000000000..797e08e2fe6 --- /dev/null +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts @@ -0,0 +1,61 @@ +import { AfterContentInit, Component, ContentChildren, Input, NgModule, OnDestroy, QueryList } from '@angular/core'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { IgxAccordionModule } from '../accordion/accordion.module'; +import { IgxCarouselModule } from '../carousel/carousel.component'; +import { IBaseEventArgs } from '../core/utils'; +import { IgxStepComponent } from './step/igx-step.component'; + +@Component({ + selector: 'igx-stepper', + templateUrl: 'igx-stepper.component.html' +}) +export class IgxStepperComponent implements AfterContentInit, OnDestroy { + @ContentChildren(IgxStepComponent) + public steps: QueryList; + + @Input() + public linear: boolean; + + private destroy$ = new Subject(); + + public navigateTo(id: number) { + this.steps.forEach(s => { + s.toggleActive(id); + }); + } + + public ngAfterContentInit() { + this.steps.forEach(s => { + s.activated.pipe(takeUntil(this.destroy$)).subscribe((e: IBaseEventArgs) => { + const stepperId = e.owner.id; + this.steps.forEach(_s => { + _s.toggleActive(stepperId); + }); + }); + }); + } + + public ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + } +} + +@NgModule({ + imports: [ + BrowserAnimationsModule, + IgxCarouselModule, + IgxAccordionModule + ], + declarations: [ + IgxStepComponent, + IgxStepperComponent + ], + exports: [ + IgxStepComponent, + IgxStepperComponent + ] +}) +export class IgxStepperModule { } diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html new file mode 100644 index 00000000000..07ee66c6e1d --- /dev/null +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html @@ -0,0 +1,4 @@ + + + + diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts new file mode 100644 index 00000000000..e69290f9aaf --- /dev/null +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts @@ -0,0 +1,53 @@ +import { Component, ContentChild, EventEmitter, HostListener, Input, Output } from '@angular/core'; +import { IBaseEventArgs, mkenum } from '../../core/utils'; +import { IgxIconComponent } from '../../icon/icon.component'; +import { IgxLabelDirective } from '../../input-group/public_api'; + +let NEXT_ID = 0; + +@Component({ + selector: 'igx-step', + templateUrl: 'igx-step.component.html' +}) +export class IgxStepComponent { + @Input() + public id = NEXT_ID++; + + @Input() + public skip: boolean; + + @Input() + public interactable = true; + + @ContentChild(IgxIconComponent) + public icon: IgxIconComponent; + + @ContentChild(IgxLabelDirective) + public label: IgxLabelDirective; + + @Output() + public activated = new EventEmitter(); + + public active: boolean; + + private get inactive() { + return this.skip || !this.interactable; + } + + @HostListener('click') + public onClick() { + if (this.inactive) { + return; + } + + this.activated.emit({ owner: this }); + } + + public toggleActive(id: number) { + if (this.inactive) { + return; + } + + this.active = id === this.id; + } +} diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 289f8e1b686..afaef4d96ff 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -153,6 +153,8 @@ import { GridLocalizationSampleComponent } from './grid-localization/grid-locali import { TreeGridGroupBySampleComponent } from './tree-grid-groupby/tree-grid-groupby.sample'; import { PaginationSampleComponent } from './pagination/pagination.component'; import { GridCellAPISampleComponent } from './grid-cell-api/grid-cell-api.sample'; +import { IgxStepperModule } from 'projects/igniteui-angular/src/lib/stepper/igx-stepper.component'; +import { IgxStepperSampleComponent } from './stepper/stepper.sample'; const components = [ AccordionSampleComponent, @@ -286,7 +288,8 @@ const components = [ GridNestedPropsSampleComponent, IgxColumnGroupingDirective, GridColumnTypesSampleComponent, - GridLocalizationSampleComponent + GridLocalizationSampleComponent, + IgxStepperSampleComponent ]; @NgModule({ @@ -317,7 +320,8 @@ const components = [ routing, HammerModule, IgxDateTimeEditorModule, - IgxButtonModule + IgxButtonModule, + IgxStepperModule ], providers: [ LocalService, diff --git a/src/app/app.routing.ts b/src/app/app.routing.ts index 196a0b79083..e2cc1ac12cc 100644 --- a/src/app/app.routing.ts +++ b/src/app/app.routing.ts @@ -95,6 +95,7 @@ import { GridLocalizationSampleComponent } from './grid-localization/grid-locali import { TreeGridGroupBySampleComponent } from './tree-grid-groupby/tree-grid-groupby.sample'; import { PaginationSampleComponent } from './pagination/pagination.component'; import { GridCellAPISampleComponent } from './grid-cell-api/grid-cell-api.sample'; +import { IgxStepperSampleComponent } from './stepper/stepper.sample'; const appRoutes = [ { @@ -446,6 +447,10 @@ const appRoutes = [ { path: 'pagination', Comment: PaginationSampleComponent + }, + { + path: 'stepper', + component: IgxStepperSampleComponent } ]; diff --git a/src/app/routing.ts b/src/app/routing.ts index 95add95642a..d22f4e8827e 100644 --- a/src/app/routing.ts +++ b/src/app/routing.ts @@ -125,6 +125,7 @@ import { GridLocalizationSampleComponent } from './grid-localization/grid-locali import { TreeGridGroupBySampleComponent } from './tree-grid-groupby/tree-grid-groupby.sample'; import { PaginationSampleComponent } from './pagination/pagination.component'; import { GridCellAPISampleComponent } from './grid-cell-api/grid-cell-api.sample'; +import { IgxStepperSampleComponent as StepperSampleComponent } from './stepper/stepper.sample'; const appRoutes = [ { @@ -598,6 +599,10 @@ const appRoutes = [ },{ path: 'pagination', component: PaginationSampleComponent + }, + { + path: 'stepper', + component: StepperSampleComponent } ]; diff --git a/src/app/stepper/stepper.sample.html b/src/app/stepper/stepper.sample.html new file mode 100644 index 00000000000..09782593eb2 --- /dev/null +++ b/src/app/stepper/stepper.sample.html @@ -0,0 +1,51 @@ + + + +
+ + + + done + +
Test me daddy
+
+ + + calendar_today + + + + + + alarm + + + + + + check_circle + + + Apple + Orange + Grapes + Banana + + + + + delete + +
+ +
+
+
+
+ diff --git a/src/app/stepper/stepper.sample.scss b/src/app/stepper/stepper.sample.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/app/stepper/stepper.sample.ts b/src/app/stepper/stepper.sample.ts new file mode 100644 index 00000000000..64ffef6bb83 --- /dev/null +++ b/src/app/stepper/stepper.sample.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + templateUrl: 'stepper.sample.html', + styleUrls: ['stepper.sample.scss'] +}) +export class IgxStepperSampleComponent { } From 1eebe575e1e447d0c7651782e4152052d6a1b4f6 Mon Sep 17 00:00:00 2001 From: teodosia Date: Thu, 26 Aug 2021 13:04:31 +0300 Subject: [PATCH 24/33] feat(stepper): igx-stepper initial implementation --- .../src/lib/stepper/common.ts | 42 +++ .../src/lib/stepper/igx-stepper.component.ts | 249 ++++++++++++++++-- .../src/lib/stepper/igx-stepper.directive.ts | 56 ++++ .../lib/stepper/step/igx-step.component.html | 4 +- .../lib/stepper/step/igx-step.component.ts | 234 ++++++++++++++-- src/app/app.component.ts | 5 + src/app/stepper/stepper.sample.html | 38 +-- src/app/stepper/stepper.sample.ts | 52 +++- 8 files changed, 610 insertions(+), 70 deletions(-) create mode 100644 projects/igniteui-angular/src/lib/stepper/common.ts create mode 100644 projects/igniteui-angular/src/lib/stepper/igx-stepper.directive.ts diff --git a/projects/igniteui-angular/src/lib/stepper/common.ts b/projects/igniteui-angular/src/lib/stepper/common.ts new file mode 100644 index 00000000000..f2167992280 --- /dev/null +++ b/projects/igniteui-angular/src/lib/stepper/common.ts @@ -0,0 +1,42 @@ +import { InjectionToken } from '@angular/core'; +import { CancelableEventArgs, IBaseEventArgs } from '../core/utils'; +import { IgxStepperComponent } from './igx-stepper.component'; + +// Events +export interface IStepperEventArgs extends IBaseEventArgs { + index: number; + owner: IgxStepperComponent; +} + +export interface IStepperCancelableEventArgs extends CancelableEventArgs { + oldIndex: number; + newIndex: number; + owner: IgxStepperComponent; +} + +// Enums +export enum IgxStepperOrienatation { + Horizontal, + Vertical +} + +export enum IgxStepType { + Indicator, + Label, + Full +} + +export enum IgxStepperLabelPosition { + Bottom, + Top, + End, + Start +} + +export enum IgxStepperProgressLine { + Solid, + Dashed +} + +// Token +export const IGX_STEPPER_COMPONENT = new InjectionToken('IgxStepperToken'); diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts index 797e08e2fe6..136d208e949 100644 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts @@ -1,61 +1,260 @@ -import { AfterContentInit, Component, ContentChildren, Input, NgModule, OnDestroy, QueryList } from '@angular/core'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { CommonModule } from '@angular/common'; +import { + AfterContentInit, Component, ContentChildren, EventEmitter, + HostBinding, Input, NgModule, OnDestroy, Output, QueryList +} from '@angular/core'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; -import { IgxAccordionModule } from '../accordion/accordion.module'; -import { IgxCarouselModule } from '../carousel/carousel.component'; -import { IBaseEventArgs } from '../core/utils'; +import { + IgxStepperLabelPosition, IgxStepperOrienatation, + IgxStepType, IGX_STEPPER_COMPONENT, IStepperCancelableEventArgs, IStepperEventArgs +} from './common'; +import { + IgxStepValidIconDirective, IgxStepInvalidIconDirective, + IgxStepIconDirective, IgxStepLabelDirective +} from './igx-stepper.directive'; import { IgxStepComponent } from './step/igx-step.component'; +let NEXT_ID = 0; + @Component({ selector: 'igx-stepper', - templateUrl: 'igx-stepper.component.html' + templateUrl: 'igx-stepper.component.html', + providers: [ + { provide: IGX_STEPPER_COMPONENT, useExisting: IgxStepperComponent }, + ] }) export class IgxStepperComponent implements AfterContentInit, OnDestroy { - @ContentChildren(IgxStepComponent) - public steps: QueryList; + /** + * Get/Set the `id` of the stepper component. + * Default value is `"igx-stepper-0"`; + * ```html + * + * ``` + * ```typescript + * const stepperId = this.stepper.id; + * ``` + */ + @HostBinding('attr.id') + @Input() + public id = `igx-stepper-${NEXT_ID++}`; + + /** @hidden @internal **/ + @HostBinding('class.igx-stepper') + public cssClass = 'igx-stepper'; + /** + * Get all steps. + * + * ```typescript + * const steps: IgxStepComponent[] = this.stepper.steps; + * ``` + */ @Input() - public linear: boolean; + public get steps(): IgxStepComponent[] { + return this._steps?.toArray(); + } - private destroy$ = new Subject(); + /** + * Get/Set the stepper orientation. + * + * ```typescript + * this.stepper.orientation = IgxStepperOrienatation.Vertical; + * ``` + */ + @Input() + public get orientation(): IgxStepperOrienatation { + return this._orientation; + } - public navigateTo(id: number) { - this.steps.forEach(s => { - s.toggleActive(id); - }); + public set orientation(value: IgxStepperOrienatation) { + if (this._orientation !== value) { } + } + + /** + * Get/Set the type of the steps. + * + * ```typescript + * this.stepper.stepType = IgxStepType.Indicator; + * ``` + */ + @Input() + public get stepType(): IgxStepType { + return this._stepType; + } + + public set stepType(value: IgxStepType) { + if (value !== this._stepType) { + this._stepType = value; + this._steps?.forEach(step => { + step.isLabelVisible = !(this._stepType === IgxStepType.Indicator); + step.isIndicatorVisible = !(this._stepType === IgxStepType.Label); + }); + } + } + + /** + * Get/Set the position of the steps label. + * + * ```typescript + * this.stepper.labelPosition = IgxStepperLabelPosition.Top; + * ``` + */ + @Input() + public get labelPosition(): IgxStepperLabelPosition { + return this._labelPosition; + } + + public set labelPosition(value: IgxStepperLabelPosition) { + if (value !== this._labelPosition) { + this._labelPosition = value; + this._steps?.forEach(step => step.label.position = this.labelPosition); + } + } + + /** + * Get/Set whether the stepper is linear. + * Only if the active step is valid the user is able to move forward. + * + * ```html + * + * ``` + */ + @Input() + public linear = false; + + /** + * Get/Set the animation settings. + * + * ```html + * + * ``` + */ + @Input() + public get animationSettings() { + return this._animationSettings; + } + + public set animationSettings(value: any) { + this._animationSettings = value; } + /** + * Emitted when the stepper's active step is changing. + * + *```html + * + * + * ``` + * + *```typescript + * public handleActiveStepChanging(event: IStepperCancelableEventArgs) { + * if (event.newIndex < event.oldIndex) { + * event.cancel = true; + * } + * } + *``` + */ + @Output() + public activeStepChanging = new EventEmitter(); + + /** + * Emitted when the active step is changed. + * + * @example + * ``` + * + * ``` + */ + @Output() + public activeStepChanged = new EventEmitter(); + + @ContentChildren(IgxStepComponent) + private _steps: QueryList; + + /** @hidden @internal */ + public _activeStep: IgxStepComponent = null; + + private _orientation = IgxStepperOrienatation.Horizontal; + private _stepType = IgxStepType.Full; + private _labelPosition = IgxStepperLabelPosition.Bottom; + private _animationSettings; + private destroy$ = new Subject(); + + /** @hidden @internal */ public ngAfterContentInit() { - this.steps.forEach(s => { - s.activated.pipe(takeUntil(this.destroy$)).subscribe((e: IBaseEventArgs) => { - const stepperId = e.owner.id; - this.steps.forEach(_s => { - _s.toggleActive(stepperId); - }); + this.steps?.forEach(s => { + s.activeChanged.pipe(takeUntil(this.destroy$)).subscribe((e) => { + if (e) { + if (this._activeStep) { + this._activeStep.active = false; + } + this.steps.filter(_s => _s.index === s.index)[0].active = true; + this._activeStep = s; + + const evArgs: IStepperEventArgs = { index: s.index, owner: this }; + this.activeStepChanged.emit(evArgs); + } }); }); } + /** @hidden @internal */ public ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); } + + public navigateTo(index: number) { + const step = this._steps.filter(s => s.index === index)[0]; + if (!step || step.disabled) { + return; + } + + if (!this._activeStep) { + step.active = true; + } + + if (this._activeStep && this._activeStep.index !== index) { + this._activeStep.active = false; + step.active = true; + } + } + + private getNextStep() { + if (this._activeStep) { + return this._activeStep.index === this.steps.length - 1 ? this._activeStep : + this._steps.find(s => s.index > this._activeStep.index && !s.disabled && !s.skip); + } + } + + private getPrevStep() { + if (this._activeStep) { + return this._activeStep.index === 0 ? this._activeStep : + this._steps.find(s => s.index < this._activeStep.index && !s.disabled && !s.skip); + } + } } @NgModule({ imports: [ - BrowserAnimationsModule, - IgxCarouselModule, - IgxAccordionModule + CommonModule ], declarations: [ IgxStepComponent, - IgxStepperComponent + IgxStepperComponent, + IgxStepLabelDirective, + IgxStepIconDirective, + IgxStepValidIconDirective, + IgxStepInvalidIconDirective ], exports: [ IgxStepComponent, - IgxStepperComponent + IgxStepperComponent, + IgxStepLabelDirective, + IgxStepIconDirective, + IgxStepValidIconDirective, + IgxStepInvalidIconDirective ] }) export class IgxStepperModule { } diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.directive.ts b/projects/igniteui-angular/src/lib/stepper/igx-stepper.directive.ts new file mode 100644 index 00000000000..2875a981c4a --- /dev/null +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.directive.ts @@ -0,0 +1,56 @@ +import { Directive, HostBinding, Input } from '@angular/core'; +import { IgxStepperLabelPosition } from './common'; + +@Directive({ + selector: '[igxStepValidIcon]' +}) +export class IgxStepValidIconDirective { + @HostBinding('class.igx-step__icon--valid') + public defaultClass = true; +} + +@Directive({ + selector: '[igxStepInvalidIcon]' +}) +export class IgxStepInvalidIconDirective { + @HostBinding('class.igx-step__icon--invalid') + public defaultClass = true; +} +@Directive({ + selector: '[igxStepIcon]' +}) +export class IgxStepIconDirective { + @HostBinding('class.igx-step__icon') + public defaultClass = true; +} + +@Directive({ + selector: '[igxStepLabel]' +}) + +export class IgxStepLabelDirective { + @Input() public position = IgxStepperLabelPosition.Bottom; + + @HostBinding('class.igx-step__label') + public defaultClass = true; + + @HostBinding('class.igx-step__label--bottom') + public get bottomClass() { + return this.position === IgxStepperLabelPosition.Bottom; + } + + @HostBinding('class.igx-step__label--top') + public get topClass() { + return this.position === IgxStepperLabelPosition.Top; + } + + @HostBinding('class.igx-step__label--end') + public get endClass() { + return this.position === IgxStepperLabelPosition.End; + } + + @HostBinding('class.igx-step__label--start') + public get startClass() { + return this.position === IgxStepperLabelPosition.Start; + } +} diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html index 07ee66c6e1d..cd759d15265 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html @@ -1,4 +1,4 @@ - - + + diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts index e69290f9aaf..a11f3ecc4ff 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts @@ -1,7 +1,7 @@ -import { Component, ContentChild, EventEmitter, HostListener, Input, Output } from '@angular/core'; -import { IBaseEventArgs, mkenum } from '../../core/utils'; -import { IgxIconComponent } from '../../icon/icon.component'; -import { IgxLabelDirective } from '../../input-group/public_api'; +import { Component, ContentChild, EventEmitter, HostBinding, HostListener, Inject, Input, Output } from '@angular/core'; +import { IgxStepperProgressLine, IGX_STEPPER_COMPONENT, IStepperCancelableEventArgs } from '../common'; +import { IgxStepperComponent } from '../igx-stepper.component'; +import { IgxStepIconDirective, IgxStepLabelDirective } from '../igx-stepper.directive'; let NEXT_ID = 0; @@ -10,44 +10,228 @@ let NEXT_ID = 0; templateUrl: 'igx-step.component.html' }) export class IgxStepComponent { + /** + * Get/Set the `id` of the step component. + * Default value is `"igx-step-0"`; + * ```html + * + * ``` + * ```typescript + * const stepId = this.step.id; + * ``` + */ + @HostBinding('attr.id') @Input() - public id = NEXT_ID++; + public id = `igx-step-${NEXT_ID++}`; + /** @hidden @internal **/ + @HostBinding('class.igx-step') + public cssClass = 'igx-step'; + + /** + * Get the step index inside of the stepper. + * + * ```typescript + * const step = this.stepper.steps[1]; + * const stepIndex: number = step.index; + * ``` + */ @Input() - public skip: boolean; + public get index(): number { + return this._index; + } + /** + * Get/Set whether the step should be skipped. It could be activated on click. + * + * ```html + * + * ... + * + * ... + * + * ``` + * + * ```typescript + * this.stepper.steps[1].skip = true; + * ``` + */ @Input() - public interactable = true; + public skip = false; - @ContentChild(IgxIconComponent) - public icon: IgxIconComponent; + /** + * Get/Set whether the step is interactable. + * + * ```html + * + * ... + * + * ... + * + * ``` + * + * ```typescript + * this.stepper.steps[1].disabled = true; + * ``` + */ + @Input() + @HostBinding('class.igx-step--disabled') + public disabled = false; - @ContentChild(IgxLabelDirective) - public label: IgxLabelDirective; + /** + * Get/Set whether the step is activated. + * + * ```html + * + * ... + * + * ... + * + * ``` + * + * ```typescript + * this.stepper.steps[1].active = true; + * ``` + */ + @Input() + @HostBinding('class.igx-step--active') + public get active(): boolean { + return this._active; + } - @Output() - public activated = new EventEmitter(); + public set active(value: boolean) { + if (this._active !== value && this.accessible) { + this._active = value; + this.activeChanged.emit(this._active); + } + } + + /** + * Get/Set whether the step is optional. + * + * ```html + * + * ... + * + * ... + * + * ``` + * + * ```typescript + * this.stepper.steps[1].optional = true; + * ``` + */ + @Input() + public get optional(): boolean { + return this._optional; + }; + + public set optonal(value: boolean) { + if (!this.disabled) { + this._optional = value; + } + } + + @Input() + @HostBinding('class.igx-step--complete') + public complete = false; + + /** + * Get/Set whether the step is valid. + * + */ + @Input() + public isValid = true; + + /** @hidden */ + @HostBinding('class.igx-step--invalid') + public get invalidClass(): boolean { + return !this.isValid; + } + + /** + * Get/Set whether the step the progress indicator type. + * + * ```typescript + * this.stepper.steps[1].completedStyle = IgxStepperProgressLine.Dashed; + * ``` + */ + @Input() + public completedStyle = IgxStepperProgressLine.Solid; + + /** @hidden @internal */ + @HostBinding('class.igx-step--solid') + public get solidClass() { + return this.complete && this.completedStyle === IgxStepperProgressLine.Solid; + } + + /** @hidden @internal */ + @HostBinding('class.igx-step--dashed') + public get dashedClass() { + return this.complete && this.completedStyle === IgxStepperProgressLine.Dashed; + } + + @ContentChild(IgxStepIconDirective) + public icon: IgxStepIconDirective; + + @ContentChild(IgxStepLabelDirective) + public label: IgxStepLabelDirective; - public active: boolean; + /** + * Emitted when the step's `active` property is changed. + * + * ```html + * + * + * + * + * ``` + * + * ```typescript + * const step: IgxStepComponent = this.stepper.step[0]; + * step.activeChanged.pipe(takeUntil(this.destroy$)).subscribe((e: boolean) => console.log("Step active state changed to ", e)) + * ``` + */ + @Output() + public activeChanged = new EventEmitter(); - private get inactive() { - return this.skip || !this.interactable; + private get accessible() { + return (this.stepper.linear && this.stepper._activeStep?.isValid) || !this.disabled; } + /** @hidden @internal */ + public isLabelVisible = true; + /** @hidden @internal */ + public isIndicatorVisible = true; + + private _index = NEXT_ID - 1; + private _active = false; + private _optional = false; + + constructor(@Inject(IGX_STEPPER_COMPONENT) public stepper: IgxStepperComponent) { } + @HostListener('click') public onClick() { - if (this.inactive) { + if (!this.accessible) { return; } - - this.activated.emit({ owner: this }); + const evArgs: IStepperCancelableEventArgs = { + oldIndex: this.stepper._activeStep?.index, + newIndex: this.index, + owner: this.stepper, + cancel: false + }; + this.stepper.activeStepChanging.emit(evArgs); + if (!evArgs.cancel) { + this.active = true; + } } - public toggleActive(id: number) { - if (this.inactive) { - return; - } + // public toggleActive(id: number) { + // if (this.inactive) { + // return; + // } - this.active = id === this.id; - } + // this.active = id === this.index; + // } } diff --git a/src/app/app.component.ts b/src/app/app.component.ts index d4100bff3c6..13260d3399e 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -449,6 +449,11 @@ export class AppComponent implements OnInit { icon: 'feedback', name: 'Snackbar' }, + { + link: '/stepper', + icon: 'format_list_bulleted', + name: 'Stepper' + }, { link: '/tabs', icon: 'tab', diff --git a/src/app/stepper/stepper.sample.html b/src/app/stepper/stepper.sample.html index 09782593eb2..3d07d0ba232 100644 --- a/src/app/stepper/stepper.sample.html +++ b/src/app/stepper/stepper.sample.html @@ -9,28 +9,32 @@
- - - done - + + + done +
Test me daddy
- - calendar_today - + + calendar_today + - - alarm - + + alarm + - - check_circle - + + check_circle + Apple Orange @@ -39,9 +43,9 @@ - - delete - + + delete +
@@ -49,3 +53,5 @@

+ + diff --git a/src/app/stepper/stepper.sample.ts b/src/app/stepper/stepper.sample.ts index 64ffef6bb83..9b13ace3a6b 100644 --- a/src/app/stepper/stepper.sample.ts +++ b/src/app/stepper/stepper.sample.ts @@ -1,7 +1,55 @@ -import { Component } from '@angular/core'; +import { AfterViewInit, Component, ViewChild } from '@angular/core'; +import { IgxStepperLabelPosition, IgxStepperProgressLine, IgxStepType } from 'projects/igniteui-angular/src/lib/stepper/common'; +import { IgxStepperComponent } from 'projects/igniteui-angular/src/lib/stepper/igx-stepper.component'; @Component({ templateUrl: 'stepper.sample.html', styleUrls: ['stepper.sample.scss'] }) -export class IgxStepperSampleComponent { } +export class IgxStepperSampleComponent implements AfterViewInit { + @ViewChild('stepper', { static: true }) public stepper: IgxStepperComponent; + public stepType = IgxStepType.Full; + public labelPos = IgxStepperLabelPosition.Bottom; + public stepTypes = [ + { label: 'Indicator', stepType: IgxStepType.Indicator, selected: this.stepType === IgxStepType.Indicator, togglable: true }, + { label: 'Label', stepType: IgxStepType.Label, selected: this.stepType === IgxStepType.Label, togglable: true }, + { label: 'Full', stepType: IgxStepType.Full, selected: this.stepType === IgxStepType.Full, togglable: true } + ]; + public labelPositions = [ + { label: 'Bottom', labelPos: IgxStepperLabelPosition.Bottom, + selected: this.labelPos === IgxStepperLabelPosition.Bottom, togglable: true }, + { label: 'Top', labelPos: IgxStepperLabelPosition.Top, + selected: this.labelPos === IgxStepperLabelPosition.Top, togglable: true }, + { label: 'End', labelPos: IgxStepperLabelPosition.End, + selected: this.labelPos === IgxStepperLabelPosition.End, togglable: true }, + { label: 'Start', labelPos: IgxStepperLabelPosition.Start, + selected: this.labelPos === IgxStepperLabelPosition.Start, togglable: true } + ]; + public ngAfterViewInit(){ + requestAnimationFrame(() => { + this.stepper.steps[1].completedStyle = IgxStepperProgressLine.Dashed; + }); + } + public toggleStepTypes(event){ + this.stepType = this.stepTypes[event.index].stepType; + } + public toggleLabelPos(event){ + this.labelPos = this.labelPositions[event.index].labelPos; + } + + public activeChanged(event, step){ + console.log('ACTIVE CHANGED'); + console.log(event, step); + } + + public activeStepChanged(ev){ + console.log('ACTIVE STEP CHANGED'); + console.log(ev); + } + + public activeStepChanging(ev){ + // ev.cancel = true; + console.log('ACTIVE STEP CHANGING'); + console.log(ev); + } +} From 4dc07badf0759836ec2f4fe73c71d0af52562f24 Mon Sep 17 00:00:00 2001 From: MonikaKirkova Date: Fri, 3 Sep 2021 16:12:09 +0300 Subject: [PATCH 25/33] feat(stepper): added horizontal and vertical orientation --- .../src/lib/stepper/igx-stepper.component.html | 2 +- .../src/lib/stepper/igx-stepper.component.ts | 15 ++++++++++++++- .../lib/stepper/step/igx-step.component.html | 17 +++++++++++++---- .../src/lib/stepper/step/igx-step.component.ts | 2 ++ src/app/stepper/stepper.sample.html | 1 + src/app/stepper/stepper.sample.ts | 12 +++++++++++- 6 files changed, 42 insertions(+), 7 deletions(-) diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html index 2277fc6c9fd..a7c187dbfbd 100644 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html @@ -1 +1 @@ - +
diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts index 136d208e949..c54852e8592 100644 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts @@ -68,7 +68,12 @@ export class IgxStepperComponent implements AfterContentInit, OnDestroy { } public set orientation(value: IgxStepperOrienatation) { - if (this._orientation !== value) { } + if (this._orientation !== value) { + this._orientation = value; + this._steps?.forEach(step => { + step.isHorizontal = (this._orientation === IgxStepperOrienatation.Horizontal); + }); + } } /** @@ -234,6 +239,14 @@ export class IgxStepperComponent implements AfterContentInit, OnDestroy { this._steps.find(s => s.index < this._activeStep.index && !s.disabled && !s.skip); } } + + private getOrientationDisplay() { + if (this._orientation === IgxStepperOrienatation.Horizontal) { + return 'flex'; + } else { + return 'block'; + } + } } @NgModule({ diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html index cd759d15265..a8c4869a26a 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html @@ -1,4 +1,13 @@ - - - - + +
+ +
+
+
+ + +
+
+ + +
diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts index a11f3ecc4ff..3813d9a6ef2 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts @@ -203,6 +203,8 @@ export class IgxStepComponent { public isLabelVisible = true; /** @hidden @internal */ public isIndicatorVisible = true; + /** @hidden @internal */ + public isHorizontal = true; private _index = NEXT_ID - 1; private _active = false; diff --git a/src/app/stepper/stepper.sample.html b/src/app/stepper/stepper.sample.html index 3d07d0ba232..def0b479920 100644 --- a/src/app/stepper/stepper.sample.html +++ b/src/app/stepper/stepper.sample.html @@ -55,3 +55,4 @@ + \ No newline at end of file diff --git a/src/app/stepper/stepper.sample.ts b/src/app/stepper/stepper.sample.ts index 9b13ace3a6b..13008a75463 100644 --- a/src/app/stepper/stepper.sample.ts +++ b/src/app/stepper/stepper.sample.ts @@ -1,5 +1,7 @@ import { AfterViewInit, Component, ViewChild } from '@angular/core'; -import { IgxStepperLabelPosition, IgxStepperProgressLine, IgxStepType } from 'projects/igniteui-angular/src/lib/stepper/common'; +import { + IgxStepperLabelPosition, IgxStepperOrienatation, IgxStepperProgressLine, IgxStepType +} from 'projects/igniteui-angular/src/lib/stepper/common'; import { IgxStepperComponent } from 'projects/igniteui-angular/src/lib/stepper/igx-stepper.component'; @Component({ @@ -52,4 +54,12 @@ export class IgxStepperSampleComponent implements AfterViewInit { console.log('ACTIVE STEP CHANGING'); console.log(ev); } + + public changeOrientation() { + if (this.stepper.orientation === IgxStepperOrienatation.Horizontal) { + this.stepper.orientation = IgxStepperOrienatation.Vertical; + } else { + this.stepper.orientation = IgxStepperOrienatation.Horizontal; + } + } } From dcc7abb24d913c77c2a4e5646858c02400de166d Mon Sep 17 00:00:00 2001 From: mmart1n Date: Wed, 8 Sep 2021 21:46:20 +0300 Subject: [PATCH 26/33] feat(stepper): remove igxStepContent directive --- .../src/lib/stepper/common.ts | 24 +- .../lib/stepper/igx-stepper.component.html | 12 +- .../lib/stepper/igx-stepper.component.scss | 15 + .../src/lib/stepper/igx-stepper.component.ts | 360 +++++++++------- .../src/lib/stepper/igx-stepper.directive.ts | 2 +- .../lib/stepper/step/igx-step.component.html | 22 +- .../lib/stepper/step/igx-step.component.scss | 18 + .../lib/stepper/step/igx-step.component.ts | 386 +++++++++++------- .../lib/stepper/stepper-navigation.service.ts | 217 ++++++++++ .../src/lib/stepper/stepper.service.ts | 67 +++ src/app/stepper/stepper.sample.html | 25 +- src/app/stepper/stepper.sample.ts | 60 +-- 12 files changed, 838 insertions(+), 370 deletions(-) create mode 100644 projects/igniteui-angular/src/lib/stepper/igx-stepper.component.scss create mode 100644 projects/igniteui-angular/src/lib/stepper/step/igx-step.component.scss create mode 100644 projects/igniteui-angular/src/lib/stepper/stepper-navigation.service.ts create mode 100644 projects/igniteui-angular/src/lib/stepper/stepper.service.ts diff --git a/projects/igniteui-angular/src/lib/stepper/common.ts b/projects/igniteui-angular/src/lib/stepper/common.ts index f2167992280..d6514ce371d 100644 --- a/projects/igniteui-angular/src/lib/stepper/common.ts +++ b/projects/igniteui-angular/src/lib/stepper/common.ts @@ -1,24 +1,28 @@ import { InjectionToken } from '@angular/core'; -import { CancelableEventArgs, IBaseEventArgs } from '../core/utils'; +import { IBaseCancelableBrowserEventArgs, IBaseEventArgs, mkenum } from '../core/utils'; import { IgxStepperComponent } from './igx-stepper.component'; +import { IgxStepComponent } from './step/igx-step.component'; // Events -export interface IStepperEventArgs extends IBaseEventArgs { - index: number; +export interface IStepTogglingEventArgs extends IBaseEventArgs, IBaseCancelableBrowserEventArgs { + activeStep: IgxStepComponent; + previousActiveStep: IgxStepComponent; owner: IgxStepperComponent; } -export interface IStepperCancelableEventArgs extends CancelableEventArgs { - oldIndex: number; - newIndex: number; +export interface IStepToggledEventArgs extends IBaseEventArgs { + activeStep: IgxStepComponent; owner: IgxStepperComponent; } // Enums -export enum IgxStepperOrienatation { - Horizontal, - Vertical -} + +export const IgxStepperOrienatation = mkenum({ + Horizontal: 'Horizontal', + Vertical: 'Vertical' +}); +export type IgxStepperOrienatation = (typeof IgxStepperOrienatation)[keyof typeof IgxStepperOrienatation]; + export enum IgxStepType { Indicator, diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html index a7c187dbfbd..8b5c6059363 100644 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html @@ -1 +1,11 @@ -
+ +
+ +
+ +
+
+ +
+
+ diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.scss b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.scss new file mode 100644 index 00000000000..6c6c0be2496 --- /dev/null +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.scss @@ -0,0 +1,15 @@ +.igx-stepper { + display: flex; + width: 100%; + overflow: hidden; +} + +.igx-stepper--horizontal { + flex-direction: row; + justify-content: space-between; +} + +.igx-stepper--vertical { + flex-direction: column; + gap: 20px; +} diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts index c54852e8592..f187eab3064 100644 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts @@ -1,59 +1,60 @@ import { CommonModule } from '@angular/common'; import { - AfterContentInit, Component, ContentChildren, EventEmitter, - HostBinding, Input, NgModule, OnDestroy, Output, QueryList + AfterViewInit, Component, HostBinding, OnDestroy, OnInit, + Input, Output, EventEmitter, ContentChildren, QueryList, ElementRef, Optional, Inject, NgModule, ViewChild } from '@angular/core'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; +import { growVerIn, growVerOut } from '../animations/grow'; +import { slideInLeft, slideOutRight } from '../animations/slide'; +import { DisplayDensityBase, DisplayDensityToken, IDisplayDensityOptions } from '../core/displayDensity'; +import { ToggleAnimationSettings } from '../expansion-panel/toggle-animation-component'; +import { IgxStepperOrienatation, IGX_STEPPER_COMPONENT, IStepToggledEventArgs, IStepTogglingEventArgs } from './common'; import { - IgxStepperLabelPosition, IgxStepperOrienatation, - IgxStepType, IGX_STEPPER_COMPONENT, IStepperCancelableEventArgs, IStepperEventArgs -} from './common'; -import { - IgxStepValidIconDirective, IgxStepInvalidIconDirective, - IgxStepIconDirective, IgxStepLabelDirective + IgxStepIconDirective, IgxStepInvalidIconDirective, + IgxStepLabelDirective, IgxStepValidIconDirective } from './igx-stepper.directive'; import { IgxStepComponent } from './step/igx-step.component'; +import { IgxStepperService } from './stepper.service'; -let NEXT_ID = 0; @Component({ selector: 'igx-stepper', templateUrl: 'igx-stepper.component.html', + styleUrls: ['igx-stepper.component.scss'], providers: [ + IgxStepperService, { provide: IGX_STEPPER_COMPONENT, useExisting: IgxStepperComponent }, ] }) -export class IgxStepperComponent implements AfterContentInit, OnDestroy { - /** - * Get/Set the `id` of the stepper component. - * Default value is `"igx-stepper-0"`; - * ```html - * - * ``` - * ```typescript - * const stepperId = this.stepper.id; - * ``` - */ - @HostBinding('attr.id') - @Input() - public id = `igx-stepper-${NEXT_ID++}`; +export class IgxStepperComponent extends DisplayDensityBase implements OnInit, AfterViewInit, OnDestroy { + + @ViewChild('horizontalContentContainer') public horizontalContentContainer: ElementRef; - /** @hidden @internal **/ @HostBinding('class.igx-stepper') public cssClass = 'igx-stepper'; - /** - * Get all steps. + /** Get/Set the animation settings that branches should use when expanding/collpasing. + * + * ```html + * + * + * ``` * * ```typescript - * const steps: IgxStepComponent[] = this.stepper.steps; + * const animationSettings: ToggleAnimationSettings = { + * openAnimation: growVerIn, + * closeAnimation: growVerOut + * }; + * + * this.tree.animationSettings = animationSettings; * ``` */ @Input() - public get steps(): IgxStepComponent[] { - return this._steps?.toArray(); - } + public animationSettings: ToggleAnimationSettings = { + openAnimation: growVerIn, + closeAnimation: growVerOut + }; /** * Get/Set the stepper orientation. @@ -63,188 +64,231 @@ export class IgxStepperComponent implements AfterContentInit, OnDestroy { * ``` */ @Input() - public get orientation(): IgxStepperOrienatation { + public get orientation(): IgxStepperOrienatation | string { return this._orientation; } - public set orientation(value: IgxStepperOrienatation) { - if (this._orientation !== value) { - this._orientation = value; - this._steps?.forEach(step => { - step.isHorizontal = (this._orientation === IgxStepperOrienatation.Horizontal); - }); - } - } - - /** - * Get/Set the type of the steps. - * - * ```typescript - * this.stepper.stepType = IgxStepType.Indicator; - * ``` - */ - @Input() - public get stepType(): IgxStepType { - return this._stepType; - } - - public set stepType(value: IgxStepType) { - if (value !== this._stepType) { - this._stepType = value; - this._steps?.forEach(step => { - step.isLabelVisible = !(this._stepType === IgxStepType.Indicator); - step.isIndicatorVisible = !(this._stepType === IgxStepType.Label); - }); + public set orientation(value: IgxStepperOrienatation | string) { + if (this._orientation === value) { + return; } - } - - /** - * Get/Set the position of the steps label. - * - * ```typescript - * this.stepper.labelPosition = IgxStepperLabelPosition.Top; - * ``` - */ - @Input() - public get labelPosition(): IgxStepperLabelPosition { - return this._labelPosition; - } - - public set labelPosition(value: IgxStepperLabelPosition) { - if (value !== this._labelPosition) { - this._labelPosition = value; - this._steps?.forEach(step => step.label.position = this.labelPosition); + if (value === IgxStepperOrienatation.Horizontal) { + this.animationSettings = { + openAnimation: slideInLeft, + closeAnimation: slideOutRight + }; + } else { + this.animationSettings = { + openAnimation: growVerIn, + closeAnimation: growVerOut + }; } + this._orientation = value; } - /** - * Get/Set whether the stepper is linear. - * Only if the active step is valid the user is able to move forward. + /** Emitted when a node is expanding, before it finishes * * ```html - * + * + * * ``` + * + *```typescript + * public handleNodeExpanding(event: ITreeNodeTogglingEventArgs) { + * const expandedNode: IgxTreeNode = event.node; + * if (expandedNode.disabled) { + * event.cancel = true; + * } + * } + *``` */ - @Input() - public linear = false; + @Output() + public stepExpanding = new EventEmitter(); - /** - * Get/Set the animation settings. + /** Emitted when a node is expanded, after it finishes * * ```html - * + * + * * ``` + * + *```typescript + * public handleNodeExpanded(event: ITreeNodeToggledEventArgs) { + * const expandedNode: IgxTreeNode = event.node; + * console.log("Node is expanded: ", expandedNode.data); + * } + *``` */ - @Input() - public get animationSettings() { - return this._animationSettings; - } - - public set animationSettings(value: any) { - this._animationSettings = value; - } + @Output() + public stepExpanded = new EventEmitter(); - /** - * Emitted when the stepper's active step is changing. + /** Emitted when a node is collapsing, before it finishes * - *```html - * - * + * ```html + * + * * ``` * *```typescript - * public handleActiveStepChanging(event: IStepperCancelableEventArgs) { - * if (event.newIndex < event.oldIndex) { + * public handleNodeCollapsing(event: ITreeNodeTogglingEventArgs) { + * const collapsedNode: IgxTreeNode = event.node; + * if (collapsedNode.alwaysOpen) { * event.cancel = true; * } * } *``` */ @Output() - public activeStepChanging = new EventEmitter(); + public stepCollapsing = new EventEmitter(); + + /** Emitted when a node is collapsed, after it finishes + * + * @example + * ```html + * + * + * ``` + * ```typescript + * public handleNodeCollapsed(event: ITreeNodeToggledEventArgs) { + * const collapsedNode: IgxTreeNode = event.node; + * console.log("Node is collapsed: ", collapsedNode.data); + * } + * ``` + */ + @Output() + public stepCollapsed = new EventEmitter(); /** - * Emitted when the active step is changed. + * Emitted when the active node is changed. * * @example * ``` - * + * * ``` */ @Output() - public activeStepChanged = new EventEmitter(); + public activeStepChanged = new EventEmitter(); + + /** @hidden @internal */ + @ContentChildren(IgxStepComponent, { descendants: false }) + public steps: QueryList; - @ContentChildren(IgxStepComponent) - private _steps: QueryList; + // /** @hidden @internal */ + // public disabledChange = new EventEmitter(); + + private destroy$ = new Subject(); + private unsubChildren$ = new Subject(); + private _orientation: IgxStepperOrienatation | string = IgxStepperOrienatation.Vertical; + + constructor( + public stepperService: IgxStepperService, + private element: ElementRef, + @Optional() @Inject(DisplayDensityToken) protected _displayDensityOptions?: IDisplayDensityOptions) { + super(_displayDensityOptions); + this.stepperService.register(this); + // this.navService.register(this); + } /** @hidden @internal */ - public _activeStep: IgxStepComponent = null; + public get nativeElement() { + return this.element.nativeElement; + } - private _orientation = IgxStepperOrienatation.Horizontal; - private _stepType = IgxStepType.Full; - private _labelPosition = IgxStepperLabelPosition.Bottom; - private _animationSettings; - private destroy$ = new Subject(); + /** @hidden @internal */ + public handleKeydown(event: KeyboardEvent) { + // this.navService.handleKeydown(event); + } /** @hidden @internal */ - public ngAfterContentInit() { - this.steps?.forEach(s => { - s.activeChanged.pipe(takeUntil(this.destroy$)).subscribe((e) => { - if (e) { - if (this._activeStep) { - this._activeStep.active = false; - } - this.steps.filter(_s => _s.index === s.index)[0].active = true; - this._activeStep = s; + public ngOnInit() { + super.ngOnInit(); + // this.disabledChange.pipe(takeUntil(this.destroy$)).subscribe((e) => { + // this.navService.update_disabled_cache(e); + // }); - const evArgs: IStepperEventArgs = { index: s.index, owner: this }; - this.activeStepChanged.emit(evArgs); - } - }); + + //dali ni trqbva + // this.activeNodeBindingChange.pipe(takeUntil(this.destroy$)).subscribe((node) => { + // this.expandToNode(this.navService.activeNode); + // this.scrollNodeIntoView(node?.header?.nativeElement); + // }); + + + + // this.onDensityChanged.pipe(takeUntil(this.destroy$)).subscribe(() => { + // requestAnimationFrame(() => { + // this.scrollNodeIntoView(this.navService.activeStep?.header.nativeElement); + // }); + // }); + this.subToCollapsing(); + } + + /** @hidden @internal */ + public ngAfterViewInit() { + this.steps.changes.pipe(takeUntil(this.destroy$)).subscribe(() => { + this.subToChanges(); + }); + // this.scrollNodeIntoView(this.navService.activeNode?.header?.nativeElement); + this.subToChanges(); + this.steps.forEach(s => { + s.horizontalContentContainer = this.horizontalContentContainer; }); } /** @hidden @internal */ public ngOnDestroy() { + this.unsubChildren$.next(); + this.unsubChildren$.complete(); this.destroy$.next(); this.destroy$.complete(); } - public navigateTo(index: number) { - const step = this._steps.filter(s => s.index === index)[0]; - if (!step || step.disabled) { - return; - } - - if (!this._activeStep) { - step.active = true; - } - - if (this._activeStep && this._activeStep.index !== index) { - this._activeStep.active = false; - step.active = true; - } + private subToCollapsing() { + this.stepCollapsing.pipe(takeUntil(this.destroy$)).subscribe(event => { + if (event.cancel) { + return; + } + // this.navService.update_visible_cache(event.node, false); + }); + this.stepExpanding.pipe(takeUntil(this.destroy$)).subscribe(event => { + if (event.cancel) { + return; + } + // this.navService.update_visible_cache(event.node, true); + }); } - private getNextStep() { - if (this._activeStep) { - return this._activeStep.index === this.steps.length - 1 ? this._activeStep : - this._steps.find(s => s.index > this._activeStep.index && !s.disabled && !s.skip); - } + private subToChanges() { + this.unsubChildren$.next(); + this.steps.forEach(step => { + step.expandedChange.pipe(takeUntil(this.unsubChildren$)).subscribe(nodeState => { + // this.navService.update_visible_cache(node, nodeState); + }); + step.closeAnimationDone.pipe(takeUntil(this.unsubChildren$)).subscribe(() => { + // const targetElement = this.navService.focusedNode?.header.nativeElement; + // this.scrollNodeIntoView(targetElement); + }); + step.openAnimationDone.pipe(takeUntil(this.unsubChildren$)).subscribe(() => { + // const targetElement = this.navService.focusedNode?.header.nativeElement; + // this.scrollNodeIntoView(targetElement); + }); + }); + // this.navService.init_invisible_cache(); } - private getPrevStep() { - if (this._activeStep) { - return this._activeStep.index === 0 ? this._activeStep : - this._steps.find(s => s.index < this._activeStep.index && !s.disabled && !s.skip); + private scrollNodeIntoView(el: HTMLElement) { + if (!el) { + return; } - } - - private getOrientationDisplay() { - if (this._orientation === IgxStepperOrienatation.Horizontal) { - return 'flex'; - } else { - return 'block'; + const nodeRect = el.getBoundingClientRect(); + const treeRect = this.nativeElement.getBoundingClientRect(); + const topOffset = treeRect.top > nodeRect.top ? nodeRect.top - treeRect.top : 0; + const bottomOffset = treeRect.bottom < nodeRect.bottom ? nodeRect.bottom - treeRect.bottom : 0; + const shouldScroll = !!topOffset || !!bottomOffset; + if (shouldScroll && this.nativeElement.scrollHeight > this.nativeElement.clientHeight) { + // this.nativeElement.scrollTop = nodeRect.y - treeRect.y - nodeRect.height; + this.nativeElement.scrollTop = + this.nativeElement.scrollTop + bottomOffset + topOffset + (topOffset ? -1 : +1) * nodeRect.height; } } } @@ -259,7 +303,7 @@ export class IgxStepperComponent implements AfterContentInit, OnDestroy { IgxStepLabelDirective, IgxStepIconDirective, IgxStepValidIconDirective, - IgxStepInvalidIconDirective + IgxStepInvalidIconDirective, ], exports: [ IgxStepComponent, @@ -267,7 +311,7 @@ export class IgxStepperComponent implements AfterContentInit, OnDestroy { IgxStepLabelDirective, IgxStepIconDirective, IgxStepValidIconDirective, - IgxStepInvalidIconDirective + IgxStepInvalidIconDirective, ] }) export class IgxStepperModule { } diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.directive.ts b/projects/igniteui-angular/src/lib/stepper/igx-stepper.directive.ts index 2875a981c4a..7dd36d69b03 100644 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.directive.ts +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.directive.ts @@ -1,4 +1,4 @@ -import { Directive, HostBinding, Input } from '@angular/core'; +import { Directive, ElementRef, HostBinding, Input, TemplateRef } from '@angular/core'; import { IgxStepperLabelPosition } from './common'; @Directive({ diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html index a8c4869a26a..1121ab99727 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html @@ -1,13 +1,19 @@ - +
- +
-
- - + + + + + + +
+ +
-
- - + +
+
diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.scss b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.scss new file mode 100644 index 00000000000..52efaca5ea6 --- /dev/null +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.scss @@ -0,0 +1,18 @@ +.igx-step--content { + display: flex; +} + +// .igx-step::after { +// content: '\21E2'; +// color: white; +// position: relative; +// top: -50%; +// left: 100%; +// z-index: 1; +// } + +// :host ::ng-deep { +// .igx-step__content { +// display: flex; +// } +// } diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts index 3813d9a6ef2..73e741d016c 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts @@ -1,15 +1,24 @@ -import { Component, ContentChild, EventEmitter, HostBinding, HostListener, Inject, Input, Output } from '@angular/core'; -import { IgxStepperProgressLine, IGX_STEPPER_COMPONENT, IStepperCancelableEventArgs } from '../common'; +import { AnimationBuilder } from '@angular/animations'; +import { + AfterViewInit, ChangeDetectorRef, Component, ElementRef, + EventEmitter, HostBinding, Inject, Input, OnDestroy, OnInit, Output, TemplateRef, ViewChild +} from '@angular/core'; +import { takeUntil } from 'rxjs/operators'; +import { DisplayDensity } from '../../core/displayDensity'; +import { ToggleAnimationPlayer, ToggleAnimationSettings } from '../../expansion-panel/toggle-animation-component'; +import { IgxStepperOrienatation, IGX_STEPPER_COMPONENT, IStepTogglingEventArgs } from '../common'; import { IgxStepperComponent } from '../igx-stepper.component'; -import { IgxStepIconDirective, IgxStepLabelDirective } from '../igx-stepper.directive'; +import { IgxStepperService } from '../stepper.service'; let NEXT_ID = 0; @Component({ selector: 'igx-step', - templateUrl: 'igx-step.component.html' + templateUrl: 'igx-step.component.html', + styleUrls: ['igx-step.component.scss'] }) -export class IgxStepComponent { +export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, AfterViewInit, OnDestroy { + /** * Get/Set the `id` of the step component. * Default value is `"igx-step-0"`; @@ -24,9 +33,20 @@ export class IgxStepComponent { @Input() public id = `igx-step-${NEXT_ID++}`; - /** @hidden @internal **/ - @HostBinding('class.igx-step') - public cssClass = 'igx-step'; + // /** + // * To be used for load-on-demand scenarios in order to specify whether the node is loading data. + // * + // * @remarks + // * Loading nodes do not render children. + // */ + // @Input() + // public loading = false; + + + /** @hidden @internal */ + public get animationSettings(): ToggleAnimationSettings { + return this.stepper.animationSettings; + } /** * Get the step index inside of the stepper. @@ -36,204 +56,276 @@ export class IgxStepComponent { * const stepIndex: number = step.index; * ``` */ - @Input() public get index(): number { return this._index; } /** - * Get/Set whether the step should be skipped. It could be activated on click. - * - * ```html - * - * ... - * - * ... - * - * ``` + * Gets/Sets the active state of the node * - * ```typescript - * this.stepper.steps[1].skip = true; - * ``` + * @param value: boolean */ @Input() - public skip = false; + public set active(value: boolean) { + if (value) { + this.stepperService.expand(this, false); + } else { + this.stepperService.collapse(this); + } + } + + public get active(): boolean { + return this.stepperService.activeStep === this; + } + /** - * Get/Set whether the step is interactable. + * Emitted when the node's `expanded` property changes. * * ```html - * - * ... - * - * ... - * + * + * + * + * * ``` * * ```typescript - * this.stepper.steps[1].disabled = true; + * const node: IgxTreeNode = this.tree.findNodes(data[0])[0]; + * node.expandedChange.pipe(takeUntil(this.destroy$)).subscribe((e: boolean) => console.log("Node expansion state changed to ", e)) * ``` */ - @Input() - @HostBinding('class.igx-step--disabled') - public disabled = false; + @Output() + public expandedChange = new EventEmitter(); + + // /** @hidden @internal */ + // public get focused() { + // return this.isFocused && + // this.navService.focusedStep === this; + // } + + // // TODO: bind to disabled state when node is dragged + // /** + // * Gets/Sets the disabled state of the node + // * + // * @param value: boolean + // */ + // @Input() + // @HostBinding('class.igx-tree-node--disabled') + // public get disabled(): boolean { + // return this._disabled; + // } + + // public set disabled(value: boolean) { + // if (value !== this._disabled) { + // this._disabled = value; + // this.tree.disabledChange.emit(this); + // } + // } + + /** @hidden @internal */ + @HostBinding('class.igx-step') + public cssClass = 'igx-step'; + + // // TODO: will be used in Drag and Drop implementation + // /** @hidden @internal */ + // @ViewChild('ghostTemplate', { read: ElementRef }) + // public header: ElementRef; + + // @ViewChild('defaultIndicator', { read: TemplateRef, static: true }) + // private _defaultExpandIndicatorTemplate: TemplateRef; /** - * Get/Set whether the step is activated. - * - * ```html - * - * ... - * - * ... - * - * ``` - * - * ```typescript - * this.stepper.steps[1].active = true; - * ``` + * @hidden + * @internal */ - @Input() - @HostBinding('class.igx-step--active') - public get active(): boolean { - return this._active; + @ViewChild('contentTemplate',) + public contentTemplate: TemplateRef; + + @ViewChild('verticalContentContainer', { read: ElementRef }) + public verticalContentContainer: ElementRef; + + public horizontalContentContainer: ElementRef; + + /** @hidden @internal */ + public get isCompact(): boolean { + return this.stepper?.displayDensity === DisplayDensity.compact; } - public set active(value: boolean) { - if (this._active !== value && this.accessible) { - this._active = value; - this.activeChanged.emit(this._active); - } + /** @hidden @internal */ + public get isCosy(): boolean { + return this.stepper?.displayDensity === DisplayDensity.cosy; + } + + /** @hidden @internal */ + public isFocused: boolean; + + // private _disabled = false; + private _index = NEXT_ID - 1; + + constructor( + @Inject(IGX_STEPPER_COMPONENT) public stepper: IgxStepperComponent, + protected stepperService: IgxStepperService, + protected cdr: ChangeDetectorRef, + protected builder: AnimationBuilder, + private element: ElementRef + ) { + super(builder); + } + + public get isHorizontal() { + return this.stepper.orientation === IgxStepperOrienatation.Horizontal; } /** - * Get/Set whether the step is optional. - * - * ```html - * - * ... - * - * ... - * - * ``` + * The native DOM element representing the node. Could be null in certain environments. * * ```typescript - * this.stepper.steps[1].optional = true; + * // get the nativeElement of the second node + * const node: IgxTreeNode = this.tree.nodes.first(); + * const nodeElement: HTMLElement = node.nativeElement; * ``` */ - @Input() - public get optional(): boolean { - return this._optional; - }; + /** @hidden @internal */ + public get nativeElement() { + return this.element.nativeElement; + } - public set optonal(value: boolean) { - if (!this.disabled) { - this._optional = value; - } + /** @hidden @internal */ + public ngOnInit() { + this.openAnimationDone.pipe(takeUntil(this.destroy$)).subscribe( + () => { + this.stepper.stepExpanded.emit({ owner: this.stepper, activeStep: this }); + } + ); + this.closeAnimationDone.pipe(takeUntil(this.destroy$)).subscribe(() => { + this.stepper.stepCollapsed.emit({ owner: this.stepper, activeStep: this }); + this.stepperService.collapse(this); + this.cdr.markForCheck(); + }); } - @Input() - @HostBinding('class.igx-step--complete') - public complete = false; + /** @hidden @internal */ + public ngAfterViewInit() { } + + // /** + // * @hidden @internal + // * Sets the focus to the node's child, if present + // * Sets the node as the tree service's focusedNode + // * Marks the node as the current active element + // */ + // public handleFocus(): void { + // // if (this.disabled) { + // // return; + // // } + // if (this.navService.focusedStep !== this) { + // this.navService.focusedStep = this; + // } + // this.isFocused = true; + // } /** - * Get/Set whether the step is valid. - * + * @hidden @internal + * Clear the node's focused status */ - @Input() - public isValid = true; + public clearFocus(): void { + this.isFocused = false; + } - /** @hidden */ - @HostBinding('class.igx-step--invalid') - public get invalidClass(): boolean { - return !this.isValid; + /** + * @hidden @internal + */ + public onPointerDown(event) { + event.stopPropagation(); + if (this.stepperService.activeStep === this) { + return; + } + // this.navService.focusedStep = this; + this.expand(); + } + + public ngOnDestroy() { + super.ngOnDestroy(); } /** - * Get/Set whether the step the progress indicator type. + * Expands the node, triggering animation + * + * ```html + * + * My Node + * + * + * ``` * * ```typescript - * this.stepper.steps[1].completedStyle = IgxStepperProgressLine.Dashed; + * const myNode: IgxTreeNode = this.tree.findNodes(data[0])[0]; + * myNode.expand(); * ``` */ - @Input() - public completedStyle = IgxStepperProgressLine.Solid; + public expand() { + const args: IStepTogglingEventArgs = { + owner: this.stepper, + activeStep: this, + previousActiveStep: this.stepperService.previousActiveStep, + cancel: false - /** @hidden @internal */ - @HostBinding('class.igx-step--solid') - public get solidClass() { - return this.complete && this.completedStyle === IgxStepperProgressLine.Solid; - } + }; + this.stepper.stepExpanding.emit(args); + if (!args.cancel) { + this.stepperService.expand(this, true); + this.cdr.detectChanges(); + if (!this.isHorizontal) { + this.playOpenAnimation( + this.verticalContentContainer + ); + } else { + this.playOpenAnimation( + this.horizontalContentContainer + ); + } - /** @hidden @internal */ - @HostBinding('class.igx-step--dashed') - public get dashedClass() { - return this.complete && this.completedStyle === IgxStepperProgressLine.Dashed; + } } - @ContentChild(IgxStepIconDirective) - public icon: IgxStepIconDirective; - - @ContentChild(IgxStepLabelDirective) - public label: IgxStepLabelDirective; - /** - * Emitted when the step's `active` property is changed. + * Collapses the node, triggering animation * * ```html - * - * - * - * + * + * My Node + * + * * ``` * * ```typescript - * const step: IgxStepComponent = this.stepper.step[0]; - * step.activeChanged.pipe(takeUntil(this.destroy$)).subscribe((e: boolean) => console.log("Step active state changed to ", e)) + * const myNode: IgxTreeNode = this.tree.findNodes(data[0])[0]; + * myNode.collapse(); * ``` */ - @Output() - public activeChanged = new EventEmitter(); - - private get accessible() { - return (this.stepper.linear && this.stepper._activeStep?.isValid) || !this.disabled; - } - - /** @hidden @internal */ - public isLabelVisible = true; - /** @hidden @internal */ - public isIndicatorVisible = true; - /** @hidden @internal */ - public isHorizontal = true; - - private _index = NEXT_ID - 1; - private _active = false; - private _optional = false; - - constructor(@Inject(IGX_STEPPER_COMPONENT) public stepper: IgxStepperComponent) { } - - @HostListener('click') - public onClick() { - if (!this.accessible) { - return; - } - const evArgs: IStepperCancelableEventArgs = { - oldIndex: this.stepper._activeStep?.index, - newIndex: this.index, + public collapse() { + const args: IStepTogglingEventArgs = { owner: this.stepper, + activeStep: this, + previousActiveStep: this.stepperService.previousActiveStep, cancel: false + }; - this.stepper.activeStepChanging.emit(evArgs); - if (!evArgs.cancel) { - this.active = true; + this.stepper.stepCollapsing.emit(args); + if (!args.cancel) { + this.stepperService.collapsing(this); + if (!this.isHorizontal) { + this.playCloseAnimation( + this.verticalContentContainer + ); + } else { + this.playCloseAnimation( + this.horizontalContentContainer + ); + } } } - // public toggleActive(id: number) { - // if (this.inactive) { - // return; - // } - - // this.active = id === this.index; - // } + public get collapsing() { + return this.stepperService.collapsingSteps.has(this); + } } diff --git a/projects/igniteui-angular/src/lib/stepper/stepper-navigation.service.ts b/projects/igniteui-angular/src/lib/stepper/stepper-navigation.service.ts new file mode 100644 index 00000000000..cfee58fbb66 --- /dev/null +++ b/projects/igniteui-angular/src/lib/stepper/stepper-navigation.service.ts @@ -0,0 +1,217 @@ +// import { Injectable, OnDestroy } from '@angular/core'; +// import { Subject } from 'rxjs'; +// import { IgxStepperComponent } from './igx-stepper.component'; +// import { IgxStepComponent } from './step/igx-step.component'; + + +// /** @hidden @internal */ +// @Injectable() +// export class IgxStepperNavigationService implements OnDestroy { +// private stepper: IgxStepperComponent; + +// private _focusedStep: IgxStepComponent = null; + +// private _visibleChildren: IgxStepComponent[] = []; +// // private _invisibleChildren: Set = new Set(); +// // private _disabledChildren: Set = new Set(); + +// private _cacheChange = new Subject(); + +// constructor() { +// this._cacheChange.subscribe(() => { +// // this._visibleChildren = +// // this.stepper?.steps ? +// // this.stepper.steps.filter(e => !(this._invisibleChildren.has(e) || this._disabledChildren.has(e))) : +// // []; +// }); +// } + +// public register(stepper: IgxStepperComponent) { +// this.stepper = stepper; +// } + +// public get focusedStep() { +// return this._focusedStep; +// } + +// public set focusedStep(value: IgxStepComponent) { +// if (this._focusedStep === value) { +// return; +// } +// this._focusedStep = value; +// } + +// public get visibleChildren(): IgxStepComponent[] { +// return this._visibleChildren; +// } + +// // public update_disabled_cache(step: IgxStepComponent): void { +// // if (step.disabled) { +// // this._disabledChildren.add(step); +// // } else { +// // this._disabledChildren.delete(step); +// // } +// // this._cacheChange.next(); +// // } + +// // public init_invisible_cache() { +// // this.stepper.steps.filter(e => e.level === 0).forEach(step => { +// // this.update_visible_cache(step, step.expanded, false); +// // }); +// // this._cacheChange.next(); +// // } + +// // public update_visible_cache(step: IgxStepComponent, expanded: boolean, shouldEmit = true): void { +// // if (expanded) { +// // step._children.forEach(child => { +// // this._invisibleChildren.delete(child); +// // this.update_visible_cache(child, child.expanded, false); +// // }); +// // } else { +// // step.allChildren.forEach(c => this._invisibleChildren.add(c)); +// // } + +// // if (shouldEmit) { +// // this._cacheChange.next(); +// // } +// // } + +// // /** Handler for keydown events. Used in stepper.component.ts */ +// // public handleKeydown(event: KeyboardEvent) { +// // const key = event.key.toLowerCase(); +// // if (!this.focusedStep) { +// // return; +// // } +// // if (!(NAVIGATION_KEYS.has(key) || key === '*')) { +// // if (key === 'enter') { +// // this.activeStep = this.focusedStep; +// // } +// // return; +// // } +// // event.preventDefault(); +// // if (event.repeat) { +// // setTimeout(() => this.handleNavigation(event), 1); +// // } else { +// // this.handleNavigation(event); +// // } +// // } + +// public ngOnDestroy() { +// this._cacheChange.next(); +// this._cacheChange.complete(); +// } + +// // private handleNavigation(event: KeyboardEvent) { +// // switch (event.key.toLowerCase()) { +// // case 'home': +// // this.setFocusedAndActiveStep(this.visibleChildren[0]); +// // break; +// // case 'end': +// // this.setFocusedAndActiveStep(this.visibleChildren[this.visibleChildren.length - 1]); +// // break; +// // case 'arrowleft': +// // case 'left': +// // this.handleArrowLeft(); +// // break; +// // case 'arrowright': +// // case 'right': +// // this.handleArrowRight(); +// // break; +// // case 'arrowup': +// // case 'up': +// // this.handleUpDownArrow(true, event); +// // break; +// // case 'arrowdown': +// // case 'down': +// // this.handleUpDownArrow(false, event); +// // break; +// // case '*': +// // this.handleAsterisk(); +// // break; +// // case ' ': +// // case 'spacebar': +// // case 'space': +// // this.handleSpace(event.shiftKey); +// // break; +// // default: +// // return; +// // } +// // } + +// // private handleArrowLeft(): void { +// // if (this.focusedStep.expanded && +// // !this.stepperService.collapsingSteps.has(this.focusedStep) && this.focusedStep._children?.length) { +// // this.activeStep = this.focusedStep; +// // this.focusedStep.collapse(); +// // } else { +// // const parentStep = this.focusedStep.parentStep; +// // if (parentStep && !parentStep.disabled) { +// // this.setFocusedAndActiveStep(parentStep); +// // } +// // } +// // } + +// // private handleArrowRight(): void { +// // if (this.focusedStep._children.length > 0) { +// // if (!this.focusedStep.expanded) { +// // this.activeStep = this.focusedStep; +// // this.focusedStep.expand(); +// // } else { +// // if (this.stepperService.collapsingSteps.has(this.focusedStep)) { +// // this.focusedStep.expand(); +// // return; +// // } +// // const firstChild = this.focusedStep._children.find(step => !step.disabled); +// // if (firstChild) { +// // this.setFocusedAndActiveStep(firstChild); +// // } +// // } +// // } +// // } + +// // private handleUpDownArrow(isUp: boolean, event: KeyboardEvent): void { +// // const next = this.getVisibleStep(this.focusedStep, isUp ? -1 : 1); +// // if (next === this.focusedStep) { +// // return; +// // } + +// // if (event.ctrlKey) { +// // this.setFocusedAndActiveStep(next, false); +// // } else { +// // this.setFocusedAndActiveStep(next); +// // } +// // } + +// // private handleAsterisk(): void { +// // const steps = this.focusedStep.parentStep ? this.focusedStep.parentStep._children : this.stepper.rootSteps; +// // steps?.forEach(step => { +// // if (!step.disabled && (!step.expanded || this.stepperService.collapsingSteps.has(step))) { +// // step.expand(); +// // } +// // }); +// // } + +// // private handleSpace(shiftKey = false): void { +// // if (this.stepper.selection === IgxStepperSelectionType.None) { +// // return; +// // } + +// // this.activeStep = this.focusedStep; +// // if (shiftKey) { +// // this.selectionService.selectMultipleSteps(this.focusedStep); +// // return; +// // } + +// // if (this.focusedStep.selected) { +// // this.selectionService.deselectStep(this.focusedStep); +// // } else { +// // this.selectionService.selectStep(this.focusedStep); +// // } +// // } + +// // /** Gets the next visible step in the given direction - 1 -> next, -1 -> previous */ +// // private getVisibleStep(step: IgxStepComponent, dir: 1 | -1 = 1): IgxStepComponent { +// // const stepIndex = this.visibleChildren.indexOf(step); +// // return this.visibleChildren[stepIndex + dir] || step; +// // } +// } diff --git a/projects/igniteui-angular/src/lib/stepper/stepper.service.ts b/projects/igniteui-angular/src/lib/stepper/stepper.service.ts new file mode 100644 index 00000000000..157b6e8d9d7 --- /dev/null +++ b/projects/igniteui-angular/src/lib/stepper/stepper.service.ts @@ -0,0 +1,67 @@ +import { Injectable } from '@angular/core'; +import { IgxStepperComponent } from './igx-stepper.component'; +import { IgxStepComponent } from './step/igx-step.component'; + +/** @hidden @internal */ +@Injectable() +export class IgxStepperService { + + public activeStep: IgxStepComponent; + public previousActiveStep: IgxStepComponent; + + public collapsingSteps: Set = new Set(); + public stepper: IgxStepperComponent; + + /** + * Adds the step to the `expandedSteps` set and fires the steps change event + * + * @param step target step + * @param uiTrigger is the event triggered by a ui interraction (so we know if we should animate) + * @returns void + */ + public expand(step: IgxStepComponent, uiTrigger?: boolean): void { + this.collapsingSteps.delete(step); + + if (this.activeStep === step) { + return; + } + step.expandedChange.emit(true); + this.previousActiveStep = this.activeStep; + this.activeStep = step; + if (uiTrigger) { + this.previousActiveStep?.collapse(); + } else { + if (this.previousActiveStep) { + this.previousActiveStep.active = false; + } + } + } + + /** + * Adds a step to the `collapsing` collection + * + * @param step target step + */ + public collapsing(step: IgxStepComponent): void { + this.collapsingSteps.add(step); + } + + /** + * Removes the step from the 'expandedSteps' set and emits the step's change event + * + * @param step target step + * @returns void + */ + public collapse(step: IgxStepComponent): void { + this.collapsingSteps.delete(step); + if (this.activeStep === step) { + step.expandedChange.emit(false); + this.previousActiveStep = step; + this.activeStep = null; + } + } + + public register(stepper: IgxStepperComponent) { + this.stepper = stepper; + } +} diff --git a/src/app/stepper/stepper.sample.html b/src/app/stepper/stepper.sample.html index def0b479920..49ace62858e 100644 --- a/src/app/stepper/stepper.sample.html +++ b/src/app/stepper/stepper.sample.html @@ -1,4 +1,3 @@ - + + + diff --git a/src/app/stepper/stepper.sample.ts b/src/app/stepper/stepper.sample.ts index 13008a75463..99c4f4e709a 100644 --- a/src/app/stepper/stepper.sample.ts +++ b/src/app/stepper/stepper.sample.ts @@ -10,46 +10,46 @@ import { IgxStepperComponent } from 'projects/igniteui-angular/src/lib/stepper/i }) export class IgxStepperSampleComponent implements AfterViewInit { @ViewChild('stepper', { static: true }) public stepper: IgxStepperComponent; - public stepType = IgxStepType.Full; - public labelPos = IgxStepperLabelPosition.Bottom; - public stepTypes = [ - { label: 'Indicator', stepType: IgxStepType.Indicator, selected: this.stepType === IgxStepType.Indicator, togglable: true }, - { label: 'Label', stepType: IgxStepType.Label, selected: this.stepType === IgxStepType.Label, togglable: true }, - { label: 'Full', stepType: IgxStepType.Full, selected: this.stepType === IgxStepType.Full, togglable: true } - ]; - public labelPositions = [ - { label: 'Bottom', labelPos: IgxStepperLabelPosition.Bottom, - selected: this.labelPos === IgxStepperLabelPosition.Bottom, togglable: true }, - { label: 'Top', labelPos: IgxStepperLabelPosition.Top, - selected: this.labelPos === IgxStepperLabelPosition.Top, togglable: true }, - { label: 'End', labelPos: IgxStepperLabelPosition.End, - selected: this.labelPos === IgxStepperLabelPosition.End, togglable: true }, - { label: 'Start', labelPos: IgxStepperLabelPosition.Start, - selected: this.labelPos === IgxStepperLabelPosition.Start, togglable: true } - ]; - public ngAfterViewInit(){ - requestAnimationFrame(() => { - this.stepper.steps[1].completedStyle = IgxStepperProgressLine.Dashed; - }); - } - public toggleStepTypes(event){ - this.stepType = this.stepTypes[event.index].stepType; - } - public toggleLabelPos(event){ - this.labelPos = this.labelPositions[event.index].labelPos; + // public stepType = IgxStepType.Full; + // public labelPos = IgxStepperLabelPosition.Bottom; + // public stepTypes = [ + // { label: 'Indicator', stepType: IgxStepType.Indicator, selected: this.stepType === IgxStepType.Indicator, togglable: true }, + // { label: 'Label', stepType: IgxStepType.Label, selected: this.stepType === IgxStepType.Label, togglable: true }, + // { label: 'Full', stepType: IgxStepType.Full, selected: this.stepType === IgxStepType.Full, togglable: true } + // ]; + // public labelPositions = [ + // { label: 'Bottom', labelPos: IgxStepperLabelPosition.Bottom, + // selected: this.labelPos === IgxStepperLabelPosition.Bottom, togglable: true }, + // { label: 'Top', labelPos: IgxStepperLabelPosition.Top, + // selected: this.labelPos === IgxStepperLabelPosition.Top, togglable: true }, + // { label: 'End', labelPos: IgxStepperLabelPosition.End, + // selected: this.labelPos === IgxStepperLabelPosition.End, togglable: true }, + // { label: 'Start', labelPos: IgxStepperLabelPosition.Start, + // selected: this.labelPos === IgxStepperLabelPosition.Start, togglable: true } + // ]; + public ngAfterViewInit() { + // requestAnimationFrame(() => { + // this.stepper.steps[1].completedStyle = IgxStepperProgressLine.Dashed; + // }); } + // public toggleStepTypes(event){ + // this.stepType = this.stepTypes[event.index].stepType; + // } + // public toggleLabelPos(event){ + // this.labelPos = this.labelPositions[event.index].labelPos; + // } - public activeChanged(event, step){ + public activeChanged(event, step) { console.log('ACTIVE CHANGED'); console.log(event, step); } - public activeStepChanged(ev){ + public activeStepChanged(ev) { console.log('ACTIVE STEP CHANGED'); console.log(ev); } - public activeStepChanging(ev){ + public activeStepChanging(ev) { // ev.cancel = true; console.log('ACTIVE STEP CHANGING'); console.log(ev); From 852c92df3add453f575bb24ae6bc3afc2c5a830e Mon Sep 17 00:00:00 2001 From: mmart1n Date: Thu, 9 Sep 2021 17:20:17 +0300 Subject: [PATCH 27/33] feat(stepper): extend igxCarouselBase --- .../lib/stepper/igx-stepper.component.html | 6 ++- .../src/lib/stepper/igx-stepper.component.ts | 43 ++++++++++++++----- .../src/lib/stepper/igx-stepper.directive.ts | 2 +- .../lib/stepper/step/igx-step.component.ts | 36 ++++++++-------- 4 files changed, 56 insertions(+), 31 deletions(-) diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html index 8b5c6059363..2f7b2b70d70 100644 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html @@ -4,8 +4,10 @@
-
- +
+ + +
diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts index f187eab3064..8e9de963f55 100644 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts @@ -1,13 +1,14 @@ +import { AnimationBuilder } from '@angular/animations'; import { CommonModule } from '@angular/common'; import { AfterViewInit, Component, HostBinding, OnDestroy, OnInit, - Input, Output, EventEmitter, ContentChildren, QueryList, ElementRef, Optional, Inject, NgModule, ViewChild + Input, Output, EventEmitter, ContentChildren, QueryList, ElementRef, NgModule, ViewChild } from '@angular/core'; +import { IgxCarouselComponentBase } from 'igniteui-angular'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { growVerIn, growVerOut } from '../animations/grow'; import { slideInLeft, slideOutRight } from '../animations/slide'; -import { DisplayDensityBase, DisplayDensityToken, IDisplayDensityOptions } from '../core/displayDensity'; import { ToggleAnimationSettings } from '../expansion-panel/toggle-animation-component'; import { IgxStepperOrienatation, IGX_STEPPER_COMPONENT, IStepToggledEventArgs, IStepTogglingEventArgs } from './common'; import { @@ -18,6 +19,9 @@ import { IgxStepComponent } from './step/igx-step.component'; import { IgxStepperService } from './stepper.service'; +// TO DO: common interface between IgxCarouselComponentBase and ToggleAnimationPlayer? + + @Component({ selector: 'igx-stepper', templateUrl: 'igx-stepper.component.html', @@ -27,7 +31,7 @@ import { IgxStepperService } from './stepper.service'; { provide: IGX_STEPPER_COMPONENT, useExisting: IgxStepperComponent }, ] }) -export class IgxStepperComponent extends DisplayDensityBase implements OnInit, AfterViewInit, OnDestroy { +export class IgxStepperComponent extends IgxCarouselComponentBase implements OnInit, AfterViewInit, OnDestroy { @ViewChild('horizontalContentContainer') public horizontalContentContainer: ElementRef; @@ -171,7 +175,7 @@ export class IgxStepperComponent extends DisplayDensityBase implements OnInit, A /** @hidden @internal */ @ContentChildren(IgxStepComponent, { descendants: false }) - public steps: QueryList; + private _steps: QueryList; // /** @hidden @internal */ // public disabledChange = new EventEmitter(); @@ -181,12 +185,16 @@ export class IgxStepperComponent extends DisplayDensityBase implements OnInit, A private _orientation: IgxStepperOrienatation | string = IgxStepperOrienatation.Vertical; constructor( + builder: AnimationBuilder, public stepperService: IgxStepperService, - private element: ElementRef, - @Optional() @Inject(DisplayDensityToken) protected _displayDensityOptions?: IDisplayDensityOptions) { - super(_displayDensityOptions); - this.stepperService.register(this); - // this.navService.register(this); + private element: ElementRef) { + super(builder); + this.stepperService.register(this); + // this.navService.register(this); + } + + public get steps(): IgxStepComponent[] { + return this._steps.toArray(); } /** @hidden @internal */ @@ -201,7 +209,6 @@ export class IgxStepperComponent extends DisplayDensityBase implements OnInit, A /** @hidden @internal */ public ngOnInit() { - super.ngOnInit(); // this.disabledChange.pipe(takeUntil(this.destroy$)).subscribe((e) => { // this.navService.update_disabled_cache(e); // }); @@ -225,7 +232,7 @@ export class IgxStepperComponent extends DisplayDensityBase implements OnInit, A /** @hidden @internal */ public ngAfterViewInit() { - this.steps.changes.pipe(takeUntil(this.destroy$)).subscribe(() => { + this._steps.changes.pipe(takeUntil(this.destroy$)).subscribe(() => { this.subToChanges(); }); // this.scrollNodeIntoView(this.navService.activeNode?.header?.nativeElement); @@ -243,6 +250,20 @@ export class IgxStepperComponent extends DisplayDensityBase implements OnInit, A this.destroy$.complete(); } + public dummy() { + this.previousItem = this.stepperService.previousActiveStep; + this.currentItem = this.stepperService.activeStep; + this.triggerAnimations(); + } + + protected getPreviousElement(): HTMLElement { + return this.stepperService.previousActiveStep.horizontalContentContainer.nativeElement; + } + + protected getCurrentElement(): HTMLElement { + return this.stepperService.activeStep.horizontalContentContainer.nativeElement; + } + private subToCollapsing() { this.stepCollapsing.pipe(takeUntil(this.destroy$)).subscribe(event => { if (event.cancel) { diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.directive.ts b/projects/igniteui-angular/src/lib/stepper/igx-stepper.directive.ts index 7dd36d69b03..2875a981c4a 100644 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.directive.ts +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.directive.ts @@ -1,4 +1,4 @@ -import { Directive, ElementRef, HostBinding, Input, TemplateRef } from '@angular/core'; +import { Directive, HostBinding, Input } from '@angular/core'; import { IgxStepperLabelPosition } from './common'; @Directive({ diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts index 73e741d016c..2244fd3e26f 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts @@ -3,8 +3,9 @@ import { AfterViewInit, ChangeDetectorRef, Component, ElementRef, EventEmitter, HostBinding, Inject, Input, OnDestroy, OnInit, Output, TemplateRef, ViewChild } from '@angular/core'; +import { IgxSlideComponentBase } from 'igniteui-angular'; import { takeUntil } from 'rxjs/operators'; -import { DisplayDensity } from '../../core/displayDensity'; +import { Direction } from '../../carousel/carousel-base'; import { ToggleAnimationPlayer, ToggleAnimationSettings } from '../../expansion-panel/toggle-animation-component'; import { IgxStepperOrienatation, IGX_STEPPER_COMPONENT, IStepTogglingEventArgs } from '../common'; import { IgxStepperComponent } from '../igx-stepper.component'; @@ -17,7 +18,7 @@ let NEXT_ID = 0; templateUrl: 'igx-step.component.html', styleUrls: ['igx-step.component.scss'] }) -export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, AfterViewInit, OnDestroy { +export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, AfterViewInit, OnDestroy, IgxSlideComponentBase { /** * Get/Set the `id` of the step component. @@ -146,19 +147,23 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A public horizontalContentContainer: ElementRef; - /** @hidden @internal */ - public get isCompact(): boolean { - return this.stepper?.displayDensity === DisplayDensity.compact; - } + // /** @hidden @internal */ + // public get isCompact(): boolean { + // return this.stepper?.displayDensity === DisplayDensity.compact; + // } - /** @hidden @internal */ - public get isCosy(): boolean { - return this.stepper?.displayDensity === DisplayDensity.cosy; - } + // /** @hidden @internal */ + // public get isCosy(): boolean { + // return this.stepper?.displayDensity === DisplayDensity.cosy; + // } /** @hidden @internal */ public isFocused: boolean; + public direction: Direction = Direction.NONE; + public previous: boolean; + + // private _disabled = false; private _index = NEXT_ID - 1; @@ -279,9 +284,10 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A this.verticalContentContainer ); } else { - this.playOpenAnimation( - this.horizontalContentContainer - ); + // this.playOpenAnimation( + // this.horizontalContentContainer + // ); + this.stepper.dummy(); } } @@ -317,10 +323,6 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A this.playCloseAnimation( this.verticalContentContainer ); - } else { - this.playCloseAnimation( - this.horizontalContentContainer - ); } } } From e35cd835dca6e1240332c38fb9278ae7a55f1b3d Mon Sep 17 00:00:00 2001 From: mmart1n Date: Fri, 10 Sep 2021 18:04:43 +0300 Subject: [PATCH 28/33] refactor(stepper): move expanding logic into StepperService - set player position to be the last player --- .../toggle-animation-component.ts | 3 +- .../src/lib/stepper/igx-stepper.component.ts | 149 ++---------------- .../lib/stepper/step/igx-step.component.ts | 115 ++------------ .../src/lib/stepper/stepper.service.ts | 83 ++++++---- 4 files changed, 80 insertions(+), 270 deletions(-) diff --git a/projects/igniteui-angular/src/lib/expansion-panel/toggle-animation-component.ts b/projects/igniteui-angular/src/lib/expansion-panel/toggle-animation-component.ts index 081f2c97e7c..7a6cf5852f2 100644 --- a/projects/igniteui-angular/src/lib/expansion-panel/toggle-animation-component.ts +++ b/projects/igniteui-angular/src/lib/expansion-panel/toggle-animation-component.ts @@ -133,7 +133,8 @@ export abstract class ToggleAnimationPlayer implements ToggleAnimationOwner, OnD if (opposite) { if (opposite.hasStarted()) { // .getPosition() still returns 0 sometimes, regardless of the fix for https://github.com/angular/angular/issues/18891; - oppositePosition = (opposite as any)._renderer.engine.players[0].getPosition(); + const renderer = (opposite as any)._renderer; + oppositePosition = renderer.engine.players[renderer.engine.players.length - 1].getPosition(); } this.cleanUpPlayer(oppositeType); diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts index 8e9de963f55..b803ed93d4d 100644 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts @@ -90,88 +90,11 @@ export class IgxStepperComponent extends IgxCarouselComponentBase implements OnI this._orientation = value; } - /** Emitted when a node is expanding, before it finishes - * - * ```html - * - * - * ``` - * - *```typescript - * public handleNodeExpanding(event: ITreeNodeTogglingEventArgs) { - * const expandedNode: IgxTreeNode = event.node; - * if (expandedNode.disabled) { - * event.cancel = true; - * } - * } - *``` - */ - @Output() - public stepExpanding = new EventEmitter(); - - /** Emitted when a node is expanded, after it finishes - * - * ```html - * - * - * ``` - * - *```typescript - * public handleNodeExpanded(event: ITreeNodeToggledEventArgs) { - * const expandedNode: IgxTreeNode = event.node; - * console.log("Node is expanded: ", expandedNode.data); - * } - *``` - */ @Output() - public stepExpanded = new EventEmitter(); + public activeStepChanging = new EventEmitter(); - /** Emitted when a node is collapsing, before it finishes - * - * ```html - * - * - * ``` - * - *```typescript - * public handleNodeCollapsing(event: ITreeNodeTogglingEventArgs) { - * const collapsedNode: IgxTreeNode = event.node; - * if (collapsedNode.alwaysOpen) { - * event.cancel = true; - * } - * } - *``` - */ @Output() - public stepCollapsing = new EventEmitter(); - - /** Emitted when a node is collapsed, after it finishes - * - * @example - * ```html - * - * - * ``` - * ```typescript - * public handleNodeCollapsed(event: ITreeNodeToggledEventArgs) { - * const collapsedNode: IgxTreeNode = event.node; - * console.log("Node is collapsed: ", collapsedNode.data); - * } - * ``` - */ - @Output() - public stepCollapsed = new EventEmitter(); - - /** - * Emitted when the active node is changed. - * - * @example - * ``` - * - * ``` - */ - @Output() - public activeStepChanged = new EventEmitter(); + public activeStepChanged = new EventEmitter(); /** @hidden @internal */ @ContentChildren(IgxStepComponent, { descendants: false }) @@ -188,9 +111,9 @@ export class IgxStepperComponent extends IgxCarouselComponentBase implements OnI builder: AnimationBuilder, public stepperService: IgxStepperService, private element: ElementRef) { - super(builder); - this.stepperService.register(this); - // this.navService.register(this); + super(builder); + this.stepperService.register(this); + // this.navService.register(this); } public get steps(): IgxStepComponent[] { @@ -208,27 +131,7 @@ export class IgxStepperComponent extends IgxCarouselComponentBase implements OnI } /** @hidden @internal */ - public ngOnInit() { - // this.disabledChange.pipe(takeUntil(this.destroy$)).subscribe((e) => { - // this.navService.update_disabled_cache(e); - // }); - - - //dali ni trqbva - // this.activeNodeBindingChange.pipe(takeUntil(this.destroy$)).subscribe((node) => { - // this.expandToNode(this.navService.activeNode); - // this.scrollNodeIntoView(node?.header?.nativeElement); - // }); - - - - // this.onDensityChanged.pipe(takeUntil(this.destroy$)).subscribe(() => { - // requestAnimationFrame(() => { - // this.scrollNodeIntoView(this.navService.activeStep?.header.nativeElement); - // }); - // }); - this.subToCollapsing(); - } + public ngOnInit() { } /** @hidden @internal */ public ngAfterViewInit() { @@ -237,9 +140,6 @@ export class IgxStepperComponent extends IgxCarouselComponentBase implements OnI }); // this.scrollNodeIntoView(this.navService.activeNode?.header?.nativeElement); this.subToChanges(); - this.steps.forEach(s => { - s.horizontalContentContainer = this.horizontalContentContainer; - }); } /** @hidden @internal */ @@ -257,42 +157,25 @@ export class IgxStepperComponent extends IgxCarouselComponentBase implements OnI } protected getPreviousElement(): HTMLElement { - return this.stepperService.previousActiveStep.horizontalContentContainer.nativeElement; + return this.stepperService.previousActiveStep?.horizontalContentContainer.nativeElement; } protected getCurrentElement(): HTMLElement { return this.stepperService.activeStep.horizontalContentContainer.nativeElement; } - private subToCollapsing() { - this.stepCollapsing.pipe(takeUntil(this.destroy$)).subscribe(event => { - if (event.cancel) { - return; - } - // this.navService.update_visible_cache(event.node, false); - }); - this.stepExpanding.pipe(takeUntil(this.destroy$)).subscribe(event => { - if (event.cancel) { - return; - } - // this.navService.update_visible_cache(event.node, true); - }); - } - private subToChanges() { this.unsubChildren$.next(); this.steps.forEach(step => { - step.expandedChange.pipe(takeUntil(this.unsubChildren$)).subscribe(nodeState => { - // this.navService.update_visible_cache(node, nodeState); - }); - step.closeAnimationDone.pipe(takeUntil(this.unsubChildren$)).subscribe(() => { - // const targetElement = this.navService.focusedNode?.header.nativeElement; - // this.scrollNodeIntoView(targetElement); - }); - step.openAnimationDone.pipe(takeUntil(this.unsubChildren$)).subscribe(() => { - // const targetElement = this.navService.focusedNode?.header.nativeElement; - // this.scrollNodeIntoView(targetElement); - }); + step.horizontalContentContainer = this.horizontalContentContainer; + // step.closeAnimationDone.pipe(takeUntil(this.unsubChildren$)).subscribe(() => { + // const targetElement = this.navService.focusedNode?.header.nativeElement; + // this.scrollNodeIntoView(targetElement); + // }); + // step.openAnimationDone.pipe(takeUntil(this.unsubChildren$)).subscribe(() => { + // const targetElement = this.navService.focusedNode?.header.nativeElement; + // this.scrollNodeIntoView(targetElement); + // }); }); // this.navService.init_invisible_cache(); } diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts index 2244fd3e26f..a20a4b31546 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts @@ -70,8 +70,6 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A public set active(value: boolean) { if (value) { this.stepperService.expand(this, false); - } else { - this.stepperService.collapse(this); } } @@ -79,24 +77,12 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A return this.stepperService.activeStep === this; } + public get collapsing(): boolean { + return this.stepperService.collapsingSteps.has(this); + } - /** - * Emitted when the node's `expanded` property changes. - * - * ```html - * - * - * - * - * ``` - * - * ```typescript - * const node: IgxTreeNode = this.tree.findNodes(data[0])[0]; - * node.expandedChange.pipe(takeUntil(this.destroy$)).subscribe((e: boolean) => console.log("Node expansion state changed to ", e)) - * ``` - */ @Output() - public expandedChange = new EventEmitter(); + public activeChanged = new EventEmitter(); // /** @hidden @internal */ // public get focused() { @@ -170,7 +156,7 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A constructor( @Inject(IGX_STEPPER_COMPONENT) public stepper: IgxStepperComponent, protected stepperService: IgxStepperService, - protected cdr: ChangeDetectorRef, + public cdr: ChangeDetectorRef, protected builder: AnimationBuilder, private element: ElementRef ) { @@ -199,12 +185,13 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A public ngOnInit() { this.openAnimationDone.pipe(takeUntil(this.destroy$)).subscribe( () => { - this.stepper.stepExpanded.emit({ owner: this.stepper, activeStep: this }); + this.activeChanged.emit(true); + this.stepper.activeStepChanged.emit({ owner: this.stepper, activeStep: this }); } ); this.closeAnimationDone.pipe(takeUntil(this.destroy$)).subscribe(() => { - this.stepper.stepCollapsed.emit({ owner: this.stepper, activeStep: this }); - this.stepperService.collapse(this); + this.stepperService.collapsingSteps.delete(this); + this.activeChanged.emit(false); this.cdr.markForCheck(); }); } @@ -241,93 +228,11 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A */ public onPointerDown(event) { event.stopPropagation(); - if (this.stepperService.activeStep === this) { - return; - } - // this.navService.focusedStep = this; - this.expand(); + this.stepperService.expand(this, true); } public ngOnDestroy() { super.ngOnDestroy(); } - /** - * Expands the node, triggering animation - * - * ```html - * - * My Node - * - * - * ``` - * - * ```typescript - * const myNode: IgxTreeNode = this.tree.findNodes(data[0])[0]; - * myNode.expand(); - * ``` - */ - public expand() { - const args: IStepTogglingEventArgs = { - owner: this.stepper, - activeStep: this, - previousActiveStep: this.stepperService.previousActiveStep, - cancel: false - - }; - this.stepper.stepExpanding.emit(args); - if (!args.cancel) { - this.stepperService.expand(this, true); - this.cdr.detectChanges(); - if (!this.isHorizontal) { - this.playOpenAnimation( - this.verticalContentContainer - ); - } else { - // this.playOpenAnimation( - // this.horizontalContentContainer - // ); - this.stepper.dummy(); - } - - } - } - - /** - * Collapses the node, triggering animation - * - * ```html - * - * My Node - * - * - * ``` - * - * ```typescript - * const myNode: IgxTreeNode = this.tree.findNodes(data[0])[0]; - * myNode.collapse(); - * ``` - */ - public collapse() { - const args: IStepTogglingEventArgs = { - owner: this.stepper, - activeStep: this, - previousActiveStep: this.stepperService.previousActiveStep, - cancel: false - - }; - this.stepper.stepCollapsing.emit(args); - if (!args.cancel) { - this.stepperService.collapsing(this); - if (!this.isHorizontal) { - this.playCloseAnimation( - this.verticalContentContainer - ); - } - } - } - - public get collapsing() { - return this.stepperService.collapsingSteps.has(this); - } } diff --git a/projects/igniteui-angular/src/lib/stepper/stepper.service.ts b/projects/igniteui-angular/src/lib/stepper/stepper.service.ts index 157b6e8d9d7..90caf96e04a 100644 --- a/projects/igniteui-angular/src/lib/stepper/stepper.service.ts +++ b/projects/igniteui-angular/src/lib/stepper/stepper.service.ts @@ -1,4 +1,5 @@ import { Injectable } from '@angular/core'; +import { IgxStepperOrienatation, IStepTogglingEventArgs } from './common'; import { IgxStepperComponent } from './igx-stepper.component'; import { IgxStepComponent } from './step/igx-step.component'; @@ -20,48 +21,68 @@ export class IgxStepperService { * @returns void */ public expand(step: IgxStepComponent, uiTrigger?: boolean): void { - this.collapsingSteps.delete(step); - if (this.activeStep === step) { return; } - step.expandedChange.emit(true); - this.previousActiveStep = this.activeStep; - this.activeStep = step; + + //TODO: consider emitting cancelable events through API + + let argsCanceled = false; if (uiTrigger) { - this.previousActiveStep?.collapse(); - } else { - if (this.previousActiveStep) { - this.previousActiveStep.active = false; - } + argsCanceled = this.emitActivatingEvent(step); } - } - /** - * Adds a step to the `collapsing` collection - * - * @param step target step - */ - public collapsing(step: IgxStepComponent): void { - this.collapsingSteps.add(step); - } + if (!argsCanceled) { + this.collapsingSteps.delete(step); + + this.previousActiveStep = this.activeStep; + this.activeStep = step; + + if (uiTrigger) { + + this.collapsingSteps.add(this.previousActiveStep); + + if (this.stepper.orientation === IgxStepperOrienatation.Vertical) { + this.previousActiveStep.playCloseAnimation( + this.previousActiveStep.verticalContentContainer + ); + this.activeStep.cdr.detectChanges(); + + this.activeStep.playOpenAnimation( + this.activeStep.verticalContentContainer + ); + } else { + this.activeStep.cdr.detectChanges(); + this.stepper.dummy(); + } + } else { + this.collapsingSteps.delete(this.previousActiveStep); + this.activeStep.cdr.detectChanges(); + this.previousActiveStep?.cdr.detectChanges(); + + this.previousActiveStep?.activeChanged.emit(false); + this.activeStep.activeChanged.emit(true); + + this.stepper.activeStepChanged.emit({ owner: this.stepper, activeStep: this.activeStep }); + } - /** - * Removes the step from the 'expandedSteps' set and emits the step's change event - * - * @param step target step - * @returns void - */ - public collapse(step: IgxStepComponent): void { - this.collapsingSteps.delete(step); - if (this.activeStep === step) { - step.expandedChange.emit(false); - this.previousActiveStep = step; - this.activeStep = null; } + } public register(stepper: IgxStepperComponent) { this.stepper = stepper; } + + private emitActivatingEvent(step: IgxStepComponent): boolean { + const args: IStepTogglingEventArgs = { + owner: this.stepper, + activeStep: step, + previousActiveStep: this.activeStep, + cancel: false + }; + + this.stepper.activeStepChanging.emit(args); + return args.cancel; + } } From 3b811df2d4872dcd3ba44dd254fb8562e583d7d8 Mon Sep 17 00:00:00 2001 From: mmart1n Date: Mon, 13 Sep 2021 16:40:58 +0300 Subject: [PATCH 29/33] feat(stepper): add new properties to the stepper - make step active property two way bindable - add enterAnimationDone and leaveAnimationDone events to carouselBase class --- .../src/lib/carousel/carousel-base.ts | 8 ++ .../lib/stepper/igx-stepper.component.html | 2 +- .../src/lib/stepper/igx-stepper.component.ts | 21 ++- .../lib/stepper/step/igx-step.component.html | 8 +- .../lib/stepper/step/igx-step.component.scss | 26 +++- .../lib/stepper/step/igx-step.component.ts | 120 +++++++++++++++++- .../src/lib/stepper/stepper.service.ts | 68 ++++++---- src/app/stepper/stepper.sample.html | 10 +- src/app/stepper/stepper.sample.ts | 4 +- 9 files changed, 219 insertions(+), 48 deletions(-) diff --git a/projects/igniteui-angular/src/lib/carousel/carousel-base.ts b/projects/igniteui-angular/src/lib/carousel/carousel-base.ts index 87f27b56c83..dd3df35aae6 100644 --- a/projects/igniteui-angular/src/lib/carousel/carousel-base.ts +++ b/projects/igniteui-angular/src/lib/carousel/carousel-base.ts @@ -1,4 +1,5 @@ import { AnimationBuilder, AnimationPlayer, AnimationReferenceMetadata, useAnimation } from '@angular/animations'; +import { EventEmitter } from '@angular/core'; import { fadeIn } from '../animations/fade'; import { slideInLeft } from '../animations/slide'; import { mkenum } from '../core/utils'; @@ -28,6 +29,11 @@ export abstract class IgxCarouselComponentBase { /** @hidden */ public animationType = CarouselAnimationType.slide; + /** @hidden @internal */ + public enterAnimationDone: EventEmitter = new EventEmitter(); + /** @hidden @internal */ + public leaveAnimationDone: EventEmitter = new EventEmitter(); + /** @hidden */ protected currentItem: IgxSlideComponentBase; /** @hidden */ @@ -146,6 +152,7 @@ export abstract class IgxCarouselComponentBase { this.animationPosition = 0; this.newDuration = 0; this.previousItem.previous = false; + this.enterAnimationDone.emit(); }); this.previousItem.previous = true; this.enterAnimationPlayer.play(); @@ -167,6 +174,7 @@ export abstract class IgxCarouselComponentBase { } this.animationPosition = 0; this.newDuration = 0; + this.leaveAnimationDone.emit(); }); this.leaveAnimationPlayer.play(); } diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html index 2f7b2b70d70..ab9463d4635 100644 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html @@ -4,7 +4,7 @@
-
+
diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts index b803ed93d4d..961103b4eac 100644 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts @@ -60,6 +60,17 @@ export class IgxStepperComponent extends IgxCarouselComponentBase implements OnI closeAnimation: growVerOut }; + /** + * Get/Set whether the stepper is linear. + * Only if the active step is valid the user is able to move forward. + * + * ```html + * + * ``` + */ + @Input() + public linear = false; + /** * Get/Set the stepper orientation. * @@ -131,7 +142,15 @@ export class IgxStepperComponent extends IgxCarouselComponentBase implements OnI } /** @hidden @internal */ - public ngOnInit() { } + public ngOnInit() { + this.enterAnimationDone.pipe(takeUntil(this.destroy$)).subscribe(() => { + this.activeStepChanged.emit({ owner: this, activeStep: this.stepperService.activeStep }); + }); + this.leaveAnimationDone.pipe(takeUntil(this.destroy$)).subscribe(() => { + this.stepperService.collapse(this.stepperService.previousActiveStep); + this.stepperService.previousActiveStep.cdr.markForCheck(); + }); + } /** @hidden @internal */ public ngAfterViewInit() { diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html index 1121ab99727..386b88817d4 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html @@ -5,15 +5,17 @@ - +
+ +
-
+
-
+
diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.scss b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.scss index 52efaca5ea6..c4503db6a66 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.scss +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.scss @@ -1,4 +1,28 @@ -.igx-step--content { +.igx-step__header { + border: 2px solid #ccc; + border-radius: 15px; + padding: 16px; +} + +.igx-step__header:hover { + background-color: rgba($color: #ccc, $alpha: 0.5); +} + +.igx-step__header--active { + pointer-events: none; + background-color: rgba($color: green, $alpha: 0.5); +} + +.igx-step__header--disabled { + pointer-events: none; + opacity: 0.5; +} + +.igx-step__header--skip { + opacity: 0.5; +} + +.igx-step__content { display: flex; } diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts index a20a4b31546..510f6f0ed25 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts @@ -7,7 +7,7 @@ import { IgxSlideComponentBase } from 'igniteui-angular'; import { takeUntil } from 'rxjs/operators'; import { Direction } from '../../carousel/carousel-base'; import { ToggleAnimationPlayer, ToggleAnimationSettings } from '../../expansion-panel/toggle-animation-component'; -import { IgxStepperOrienatation, IGX_STEPPER_COMPONENT, IStepTogglingEventArgs } from '../common'; +import { IgxStepperOrienatation, IgxStepperProgressLine, IGX_STEPPER_COMPONENT, IStepTogglingEventArgs } from '../common'; import { IgxStepperComponent } from '../igx-stepper.component'; import { IgxStepperService } from '../stepper.service'; @@ -61,6 +61,100 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A return this._index; } + /** + * Get/Set whether the step should be skipped. It could be activated on click. + * + * ```html + * + * ... + * + * ... + * + * ``` + * + * ```typescript + * this.stepper.steps[1].skip = true; + * ``` + */ + @Input() + public skip = false; + + /** + * Get/Set whether the step is interactable. + * + * ```html + * + * ... + * + * ... + * + * ``` + * + * ```typescript + * this.stepper.steps[1].disabled = true; + * ``` + */ + @Input() + @HostBinding('class.igx-step--disabled') + public disabled = false; + + @Input() + @HostBinding('class.igx-step--complete') + public complete = false; + + /** + * Get/Set whether the step is valid. + * + */ + @Input() + public isValid = true; + + /** @hidden */ + @HostBinding('class.igx-step--invalid') + public get invalidClass(): boolean { + return !this.isValid; + } + + /** + * Get/Set whether the step the progress indicator type. + * + * ```typescript + * this.stepper.steps[1].completedStyle = IgxStepperProgressLine.Dashed; + * ``` + */ + @Input() + public completedStyle = IgxStepperProgressLine.Solid; + + /** @hidden @internal */ + @HostBinding('class.igx-step--solid') + public get solidClass() { + return this.complete && this.completedStyle === IgxStepperProgressLine.Solid; + } + + /** @hidden @internal */ + @HostBinding('class.igx-step--dashed') + public get dashedClass() { + return this.complete && this.completedStyle === IgxStepperProgressLine.Dashed; + } + + /** + * Get/Set whether the step is optional. + * + * ```html + * + * ... + * + * ... + * + * ``` + * + * ```typescript + * this.stepper.steps[1].optional = true; + * ``` + */ + @Input() + public optional = false; + /** * Gets/Sets the active state of the node * @@ -69,7 +163,9 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A @Input() public set active(value: boolean) { if (value) { - this.stepperService.expand(this, false); + this.stepperService.expandThroughApi(this); + } else { + this.stepperService.collapse(this); } } @@ -82,7 +178,7 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A } @Output() - public activeChanged = new EventEmitter(); + public activeChange = new EventEmitter(); // /** @hidden @internal */ // public get focused() { @@ -185,13 +281,11 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A public ngOnInit() { this.openAnimationDone.pipe(takeUntil(this.destroy$)).subscribe( () => { - this.activeChanged.emit(true); this.stepper.activeStepChanged.emit({ owner: this.stepper, activeStep: this }); } ); this.closeAnimationDone.pipe(takeUntil(this.destroy$)).subscribe(() => { - this.stepperService.collapsingSteps.delete(this); - this.activeChanged.emit(false); + this.stepperService.collapse(this); this.cdr.markForCheck(); }); } @@ -199,6 +293,18 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A /** @hidden @internal */ public ngAfterViewInit() { } + public getStepHeaderClasses() { + if(this.active) { + return 'igx-step__header--active'; + } + if (this.disabled) { + return 'igx-step__header--disabled'; + } + if (this.skip) { + return 'igx-step__header--skip'; + } + } + // /** // * @hidden @internal // * Sets the focus to the node's
child, if present @@ -228,7 +334,7 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A */ public onPointerDown(event) { event.stopPropagation(); - this.stepperService.expand(this, true); + this.stepperService.expand(this); } public ngOnDestroy() { diff --git a/projects/igniteui-angular/src/lib/stepper/stepper.service.ts b/projects/igniteui-angular/src/lib/stepper/stepper.service.ts index 90caf96e04a..a972d4da90e 100644 --- a/projects/igniteui-angular/src/lib/stepper/stepper.service.ts +++ b/projects/igniteui-angular/src/lib/stepper/stepper.service.ts @@ -20,54 +20,68 @@ export class IgxStepperService { * @param uiTrigger is the event triggered by a ui interraction (so we know if we should animate) * @returns void */ - public expand(step: IgxStepComponent, uiTrigger?: boolean): void { + public expand(step: IgxStepComponent): void { if (this.activeStep === step) { return; } //TODO: consider emitting cancelable events through API - let argsCanceled = false; - if (uiTrigger) { - argsCanceled = this.emitActivatingEvent(step); - } + const argsCanceled = this.emitActivatingEvent(step); if (!argsCanceled) { this.collapsingSteps.delete(step); this.previousActiveStep = this.activeStep; this.activeStep = step; + this.activeStep.activeChange.emit(true); - if (uiTrigger) { - - this.collapsingSteps.add(this.previousActiveStep); + this.collapsingSteps.add(this.previousActiveStep); - if (this.stepper.orientation === IgxStepperOrienatation.Vertical) { - this.previousActiveStep.playCloseAnimation( - this.previousActiveStep.verticalContentContainer - ); - this.activeStep.cdr.detectChanges(); + if (this.stepper.orientation === IgxStepperOrienatation.Vertical) { + this.previousActiveStep.playCloseAnimation( + this.previousActiveStep.verticalContentContainer + ); + this.activeStep.cdr.detectChanges(); - this.activeStep.playOpenAnimation( - this.activeStep.verticalContentContainer - ); - } else { - this.activeStep.cdr.detectChanges(); - this.stepper.dummy(); - } + this.activeStep.playOpenAnimation( + this.activeStep.verticalContentContainer + ); } else { - this.collapsingSteps.delete(this.previousActiveStep); this.activeStep.cdr.detectChanges(); - this.previousActiveStep?.cdr.detectChanges(); - - this.previousActiveStep?.activeChanged.emit(false); - this.activeStep.activeChanged.emit(true); - - this.stepper.activeStepChanged.emit({ owner: this.stepper, activeStep: this.activeStep }); + this.stepper.dummy(); } } + } + + public expandThroughApi(step: IgxStepComponent) { + if (this.activeStep === step) { + return; + } + this.collapsingSteps.clear(); + + this.previousActiveStep = this.activeStep; + this.activeStep = step; + + // TODO: Should the user call detectChanges manually? + this.activeStep.cdr.detectChanges(); + this.previousActiveStep?.cdr.detectChanges(); + + this.activeStep.activeChange.emit(true); + this.previousActiveStep?.activeChange.emit(false); + + // TODO: Should the activeStepChanged be emitted when activating node through API + // this.stepper.activeStepChanged.emit({ owner: this.stepper, activeStep: this.activeStep }); + } + + public collapse(step: IgxStepComponent) { + if (this.activeStep === step) { + return; + } + step.activeChange.emit(false); + this.collapsingSteps.delete(step); } public register(stepper: IgxStepperComponent) { diff --git a/src/app/stepper/stepper.sample.html b/src/app/stepper/stepper.sample.html index 49ace62858e..2ce874d1782 100644 --- a/src/app/stepper/stepper.sample.html +++ b/src/app/stepper/stepper.sample.html @@ -8,26 +8,26 @@
- - + + done
Test me daddy
- + calendar_today - + alarm - + check_circle diff --git a/src/app/stepper/stepper.sample.ts b/src/app/stepper/stepper.sample.ts index 99c4f4e709a..9c93f2a8ebc 100644 --- a/src/app/stepper/stepper.sample.ts +++ b/src/app/stepper/stepper.sample.ts @@ -1,7 +1,5 @@ import { AfterViewInit, Component, ViewChild } from '@angular/core'; -import { - IgxStepperLabelPosition, IgxStepperOrienatation, IgxStepperProgressLine, IgxStepType -} from 'projects/igniteui-angular/src/lib/stepper/common'; +import { IgxStepperOrienatation } from 'projects/igniteui-angular/src/lib/stepper/common'; import { IgxStepperComponent } from 'projects/igniteui-angular/src/lib/stepper/igx-stepper.component'; @Component({ From ee5015b22c1b7fced3ee8e037ef2fb73b5584e59 Mon Sep 17 00:00:00 2001 From: mmart1n Date: Wed, 15 Sep 2021 12:52:16 +0300 Subject: [PATCH 30/33] refactor(stepper): properly handle horizontal subsequent animations --- .../src/lib/carousel/carousel-base.ts | 1 + .../lib/stepper/igx-stepper.component.html | 12 ++--- .../lib/stepper/igx-stepper.component.scss | 29 ++++++++++++ .../src/lib/stepper/igx-stepper.component.ts | 44 ++++++++++--------- .../lib/stepper/step/igx-step.component.html | 10 ++--- .../lib/stepper/step/igx-step.component.scss | 12 +---- .../lib/stepper/step/igx-step.component.ts | 24 ++++++---- .../src/lib/stepper/stepper.service.ts | 6 +-- 8 files changed, 83 insertions(+), 55 deletions(-) diff --git a/projects/igniteui-angular/src/lib/carousel/carousel-base.ts b/projects/igniteui-angular/src/lib/carousel/carousel-base.ts index dd3df35aae6..398edca89bd 100644 --- a/projects/igniteui-angular/src/lib/carousel/carousel-base.ts +++ b/projects/igniteui-angular/src/lib/carousel/carousel-base.ts @@ -80,6 +80,7 @@ export abstract class IgxCarouselComponentBase { private resetAnimations() { if (this.animationStarted(this.leaveAnimationPlayer)) { this.leaveAnimationPlayer.reset(); + this.leaveAnimationDone.emit(); } if (this.animationStarted(this.enterAnimationPlayer)) { diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html index ab9463d4635..b70f08ff368 100644 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html @@ -1,13 +1,9 @@ -
-
-
- - - -
+
+ + +
- diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.scss b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.scss index 6c6c0be2496..a55ec7a707f 100644 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.scss +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.scss @@ -13,3 +13,32 @@ flex-direction: column; gap: 20px; } + +.horizontal-container { + overflow: hidden; + position: relative; + flex-grow: 1; + display: block; + height: 200px; + + ::ng-deep { + .igx-step__content { + display: block; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: 100%; + height: 100%; + overflow-x: hidden; + overflow-y: auto; + z-index: -1; + } + + .igx-step__content--active { + position: relative; + z-index: 1; + } + } +} diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts index 961103b4eac..9cba5cbf945 100644 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts @@ -2,7 +2,7 @@ import { AnimationBuilder } from '@angular/animations'; import { CommonModule } from '@angular/common'; import { AfterViewInit, Component, HostBinding, OnDestroy, OnInit, - Input, Output, EventEmitter, ContentChildren, QueryList, ElementRef, NgModule, ViewChild + Input, Output, EventEmitter, ContentChildren, QueryList, ElementRef, NgModule, ChangeDetectorRef } from '@angular/core'; import { IgxCarouselComponentBase } from 'igniteui-angular'; import { Subject } from 'rxjs'; @@ -33,8 +33,6 @@ import { IgxStepperService } from './stepper.service'; }) export class IgxStepperComponent extends IgxCarouselComponentBase implements OnInit, AfterViewInit, OnDestroy { - @ViewChild('horizontalContentContainer') public horizontalContentContainer: ElementRef; - @HostBinding('class.igx-stepper') public cssClass = 'igx-stepper'; @@ -98,6 +96,8 @@ export class IgxStepperComponent extends IgxCarouselComponentBase implements OnI closeAnimation: growVerOut }; } + // TODO: activeChange event is not emitted for the collapsing steps + this.stepperService.collapsingSteps.clear(); this._orientation = value; } @@ -128,7 +128,7 @@ export class IgxStepperComponent extends IgxCarouselComponentBase implements OnI } public get steps(): IgxStepComponent[] { - return this._steps.toArray(); + return this._steps?.toArray() || []; } /** @hidden @internal */ @@ -147,8 +147,12 @@ export class IgxStepperComponent extends IgxCarouselComponentBase implements OnI this.activeStepChanged.emit({ owner: this, activeStep: this.stepperService.activeStep }); }); this.leaveAnimationDone.pipe(takeUntil(this.destroy$)).subscribe(() => { - this.stepperService.collapse(this.stepperService.previousActiveStep); - this.stepperService.previousActiveStep.cdr.markForCheck(); + if (this.stepperService.collapsingSteps.size === 1) { + this.stepperService.collapse(this.stepperService.previousActiveStep); + } else { + Array.from(this.stepperService.collapsingSteps).slice(0, this.stepperService.collapsingSteps.size - 1) + .forEach(step => this.stepperService.collapse(step)); + } }); } @@ -169,33 +173,33 @@ export class IgxStepperComponent extends IgxCarouselComponentBase implements OnI this.destroy$.complete(); } - public dummy() { + public playHorizontalAnimations() { this.previousItem = this.stepperService.previousActiveStep; this.currentItem = this.stepperService.activeStep; this.triggerAnimations(); } protected getPreviousElement(): HTMLElement { - return this.stepperService.previousActiveStep?.horizontalContentContainer.nativeElement; + return this.stepperService.previousActiveStep?.contentContainer.nativeElement; } protected getCurrentElement(): HTMLElement { - return this.stepperService.activeStep.horizontalContentContainer.nativeElement; + return this.stepperService.activeStep.contentContainer.nativeElement; } private subToChanges() { this.unsubChildren$.next(); - this.steps.forEach(step => { - step.horizontalContentContainer = this.horizontalContentContainer; - // step.closeAnimationDone.pipe(takeUntil(this.unsubChildren$)).subscribe(() => { - // const targetElement = this.navService.focusedNode?.header.nativeElement; - // this.scrollNodeIntoView(targetElement); - // }); - // step.openAnimationDone.pipe(takeUntil(this.unsubChildren$)).subscribe(() => { - // const targetElement = this.navService.focusedNode?.header.nativeElement; - // this.scrollNodeIntoView(targetElement); - // }); - }); + // this.steps.forEach(step => { + // step.horizontalContentContainer = this.horizontalContentContainer; + // step.closeAnimationDone.pipe(takeUntil(this.unsubChildren$)).subscribe(() => { + // const targetElement = this.navService.focusedNode?.header.nativeElement; + // this.scrollNodeIntoView(targetElement); + // }); + // step.openAnimationDone.pipe(takeUntil(this.unsubChildren$)).subscribe(() => { + // const targetElement = this.navService.focusedNode?.header.nativeElement; + // this.scrollNodeIntoView(targetElement); + // }); + // }); // this.navService.init_invisible_cache(); } diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html index 386b88817d4..c95634083de 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html @@ -5,17 +5,17 @@ -
- +
+
-
+
-
+ -
+ diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.scss b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.scss index c4503db6a66..9a1e53332ae 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.scss +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.scss @@ -10,7 +10,7 @@ .igx-step__header--active { pointer-events: none; - background-color: rgba($color: green, $alpha: 0.5); + background-color: rgba($color: green, $alpha: 0.5); } .igx-step__header--disabled { @@ -22,10 +22,6 @@ opacity: 0.5; } -.igx-step__content { - display: flex; -} - // .igx-step::after { // content: '\21E2'; // color: white; @@ -34,9 +30,3 @@ // left: 100%; // z-index: 1; // } - -// :host ::ng-deep { -// .igx-step__content { -// display: flex; -// } -// } diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts index 510f6f0ed25..de9b076da9f 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts @@ -7,7 +7,7 @@ import { IgxSlideComponentBase } from 'igniteui-angular'; import { takeUntil } from 'rxjs/operators'; import { Direction } from '../../carousel/carousel-base'; import { ToggleAnimationPlayer, ToggleAnimationSettings } from '../../expansion-panel/toggle-animation-component'; -import { IgxStepperOrienatation, IgxStepperProgressLine, IGX_STEPPER_COMPONENT, IStepTogglingEventArgs } from '../common'; +import { IgxStepperOrienatation, IgxStepperProgressLine, IGX_STEPPER_COMPONENT } from '../common'; import { IgxStepperComponent } from '../igx-stepper.component'; import { IgxStepperService } from '../stepper.service'; @@ -221,13 +221,12 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A * @hidden * @internal */ - @ViewChild('contentTemplate',) + @ViewChild('contentTemplate', { static: true }) public contentTemplate: TemplateRef; - @ViewChild('verticalContentContainer', { read: ElementRef }) - public verticalContentContainer: ElementRef; + @ViewChild('contentContainer') + public contentContainer: ElementRef; - public horizontalContentContainer: ElementRef; // /** @hidden @internal */ // public get isCompact(): boolean { @@ -242,7 +241,16 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A /** @hidden @internal */ public isFocused: boolean; - public direction: Direction = Direction.NONE; + public get direction(): Direction { + if (this.index === 0) { + return Direction.PREV; + } + return this.stepperService.previousActiveStep + && this.stepperService.previousActiveStep.index > this.index + ? Direction.PREV + : Direction.NEXT; + } + public previous: boolean; @@ -293,8 +301,8 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A /** @hidden @internal */ public ngAfterViewInit() { } - public getStepHeaderClasses() { - if(this.active) { + public get stepHeaderClasses() { + if (this.active) { return 'igx-step__header--active'; } if (this.disabled) { diff --git a/projects/igniteui-angular/src/lib/stepper/stepper.service.ts b/projects/igniteui-angular/src/lib/stepper/stepper.service.ts index a972d4da90e..ebb0c4a08ec 100644 --- a/projects/igniteui-angular/src/lib/stepper/stepper.service.ts +++ b/projects/igniteui-angular/src/lib/stepper/stepper.service.ts @@ -40,16 +40,16 @@ export class IgxStepperService { if (this.stepper.orientation === IgxStepperOrienatation.Vertical) { this.previousActiveStep.playCloseAnimation( - this.previousActiveStep.verticalContentContainer + this.previousActiveStep.contentContainer ); this.activeStep.cdr.detectChanges(); this.activeStep.playOpenAnimation( - this.activeStep.verticalContentContainer + this.activeStep.contentContainer ); } else { this.activeStep.cdr.detectChanges(); - this.stepper.dummy(); + this.stepper.playHorizontalAnimations(); } } From 8dfb01eff9c29ae1b5415db16c2b3e57b7421dad Mon Sep 17 00:00:00 2001 From: mmart1n Date: Wed, 15 Sep 2021 16:37:34 +0300 Subject: [PATCH 31/33] refactor(stepper): layout and class names --- .../src/lib/stepper/igx-stepper.component.html | 4 ++-- .../src/lib/stepper/igx-stepper.component.ts | 5 +++++ .../src/lib/stepper/step/igx-step.component.html | 2 +- .../src/lib/stepper/step/igx-step.component.ts | 11 +++++++++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html index b70f08ff368..2f160fb8c13 100644 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.html @@ -1,8 +1,8 @@ -
+
-
+
diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts index 9cba5cbf945..98b6f1cbe76 100644 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts @@ -36,6 +36,11 @@ export class IgxStepperComponent extends IgxCarouselComponentBase implements OnI @HostBinding('class.igx-stepper') public cssClass = 'igx-stepper'; + @HostBinding('class.igx-stepper--horizontal') + public get directionClass() { + return this.orientation === IgxStepperOrienatation.Horizontal; + } + /** Get/Set the animation settings that branches should use when expanding/collpasing. * * ```html diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html index c95634083de..f067083bdc6 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html @@ -5,7 +5,7 @@ -
+
diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts index de9b076da9f..63a89a79764 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts @@ -301,6 +301,14 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A /** @hidden @internal */ public ngAfterViewInit() { } + public get contentClasses() { + if (this.isHorizontal) { + return { 'igx-stepper__body-content': true, 'igx-stepper__body-content--active': this.active }; + } else { + return 'igx-step__content'; + } + } + public get stepHeaderClasses() { if (this.active) { return 'igx-step__header--active'; @@ -311,6 +319,9 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A if (this.skip) { return 'igx-step__header--skip'; } + if (this.optional) { + return 'igx-step__header--optional'; + } } // /** From 8f8dcdf0ee1d53cd88a6885ba0161ce1b4f458d9 Mon Sep 17 00:00:00 2001 From: MPopov Date: Wed, 15 Sep 2021 11:08:10 +0300 Subject: [PATCH 32/33] feat(stepper): applying initial styles --- .../stepper/_stepper-component.scss | 77 +++++++++++++++++ .../components/stepper/_stepper-theme.scss | 85 +++++++++++++++++++ .../src/lib/core/styles/themes/_core.scss | 1 + .../src/lib/core/styles/themes/_index.scss | 5 ++ .../styles/themes/schemas/dark/_index.scss | 9 ++ .../styles/themes/schemas/dark/_stepper.scss | 37 ++++++++ .../styles/themes/schemas/light/_index.scss | 6 ++ .../styles/themes/schemas/light/_stepper.scss | 51 +++++++++++ .../lib/stepper/igx-stepper.component.scss | 44 ---------- .../src/lib/stepper/igx-stepper.component.ts | 1 - .../lib/stepper/step/igx-step.component.scss | 32 ------- .../lib/stepper/step/igx-step.component.ts | 11 ++- src/app/stepper/stepper.sample.html | 16 ++-- src/app/stepper/stepper.sample.scss | 5 ++ 14 files changed, 289 insertions(+), 91 deletions(-) create mode 100644 projects/igniteui-angular/src/lib/core/styles/components/stepper/_stepper-component.scss create mode 100644 projects/igniteui-angular/src/lib/core/styles/components/stepper/_stepper-theme.scss create mode 100644 projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_stepper.scss create mode 100644 projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_stepper.scss delete mode 100644 projects/igniteui-angular/src/lib/stepper/igx-stepper.component.scss delete mode 100644 projects/igniteui-angular/src/lib/stepper/step/igx-step.component.scss diff --git a/projects/igniteui-angular/src/lib/core/styles/components/stepper/_stepper-component.scss b/projects/igniteui-angular/src/lib/core/styles/components/stepper/_stepper-component.scss new file mode 100644 index 00000000000..134b20337be --- /dev/null +++ b/projects/igniteui-angular/src/lib/core/styles/components/stepper/_stepper-component.scss @@ -0,0 +1,77 @@ +//// +/// @group components +/// @author
Marin Popov +/// @requires {mixin} bem-block +/// @requires {mixin} bem-elem +/// @requires {mixin} bem-mod +//// +@include b(igx-stepper) { + $block: bem--selector-to-string(&); + @include register-component(igx-stepper); + + @extend %stepper-display !optional; + + @include e(header) { + display: flex; + flex-direction: column; + gap: 20px; + width: 100%; + } + + @include e(body) { + display: flex; + flex-direction: row; + overflow: hidden; + position: relative + } + + @include e(body-contnet) { + display: block; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: 100%; + height: 100%; + overflow-y: auto; + overflow-x: hidden; + z-index: -1; + } + + @include e(body-contnet, $m: active) { + z-index: 1; + position: relative; + } +} + +// TODO THIS SHOULD GO ON THE HOST ELEMENT +.igx-stepper__header--horizontal { + flex-direction: row; + justify-content: space-between; +} + +// content +.igx-stepper__header-step-content { + border: 2px solid #ccc; + border-radius: 15px; + padding: 16px; +} + +.igx-stepper__header-step-content:hover { + background-color: rgba($color: #ccc, $alpha: .5); +} + +.igx-stepper__header-step-content--active { + pointer-events: none; + background-color: rgba($color: green, $alpha: .5); +} + +.igx-stepper__header-step-content--disabled { + pointer-events: none; + opacity: .5; +} + +.igx-stepper__header-step-content--skip { + opacity: .5; +} diff --git a/projects/igniteui-angular/src/lib/core/styles/components/stepper/_stepper-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/stepper/_stepper-theme.scss new file mode 100644 index 00000000000..e24cfffc6f4 --- /dev/null +++ b/projects/igniteui-angular/src/lib/core/styles/components/stepper/_stepper-theme.scss @@ -0,0 +1,85 @@ +@use 'sass:math'; +//// +/// @group themes +/// @access public +/// @author Marin Popov +//// + +/// @param {Map} $palette [null] - The palette used as basis for styling the component. +/// @param {Map} $schema [$light-schema] - The schema used as basis for styling the component. + +/// @requires $default-palette +/// @requires $light-schema +/// @requires apply-palette +/// @requires extend + +/// @example scss Set custom track and thumb on colors +/// $my-stepper-theme: igx-stepper-theme(); +/// @include igx-stepper($my-stepper-theme); +@function igx-stepper-theme( + $palette: null, + $schema: $light-schema, + $title-color: null, + $subtitle-color: null, + $incomplete-color: null, + $complete-color: null, + $error-color: null, + $optional-color: null, + $current-color: null, + $disabled-color: null, +) { + $name: 'igx-switch'; + $switch-schema: (); + + @if map-has-key($schema, $name) { + $switch-schema: map-get($schema, $name); + } @else { + $switch-schema: $schema; + } + + $theme: apply-palette($switch-schema, $palette); + + @return extend($theme, ( + name: $name, + palette: $palette, + )); +} + +/// @param {Map} $theme - The theme used to style the component. +/// @requires {mixin} igx-css-vars +/// @requires em +/// @requires --var +@mixin igx-stepper($theme) { + @include igx-css-vars($theme); + + $variant: map-get($theme, variant); + + $left: if-ltr(left, right); + $right: if-ltr(right, left); + + %stepper-display { + display: flex; + width: 100%; + overflow: hidden; + } +} + +/// Adds typography styles for the igx-stepper component. +/// Uses the 'subtitle-1' category from the typographic scale. +/// @group typography +/// @param {Map} $type-scale - A typographic scale as produced by igx-type-scale. +/// @param {Map} $categories [(label: 'subtitle-1')] - The categories from the typographic scale used for type styles. +/// @requires {mixin} igx-type-style +@mixin igx-switch-typography( + $type-scale, + $categories: (label: 'subtitle-1') +) { + $label: map-get($categories, 'label'); + + %switch-label { + @include igx-type-style($type-scale, $label) { + margin-top: 0; + margin-bottom: 0; + } + } +} diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/_core.scss b/projects/igniteui-angular/src/lib/core/styles/themes/_core.scss index 6ee4b013c61..c67a9387807 100644 --- a/projects/igniteui-angular/src/lib/core/styles/themes/_core.scss +++ b/projects/igniteui-angular/src/lib/core/styles/themes/_core.scss @@ -70,6 +70,7 @@ @import '../components/splitter/splitter-component'; @import '../components/snackbar/snackbar-component'; @import '../components/switch/switch-component'; +@import '../components/stepper/stepper-component'; @import '../components/tabs/tabs-component'; @import '../components/toast/toast-component'; @import '../components/tooltip/tooltip-component'; diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/_index.scss b/projects/igniteui-angular/src/lib/core/styles/themes/_index.scss index e9f15f97bba..a179f339930 100644 --- a/projects/igniteui-angular/src/lib/core/styles/themes/_index.scss +++ b/projects/igniteui-angular/src/lib/core/styles/themes/_index.scss @@ -50,6 +50,7 @@ @import '../components/tabs/tabs-theme'; @import '../components/scrollbar/scrollbar-theme'; @import '../components/switch/switch-theme'; +@import '../components/stepper/stepper-theme'; @import '../components/snackbar/snackbar-theme'; @import '../components/slider/slider-theme'; @import '../components/splitter/splitter-theme'; @@ -445,6 +446,10 @@ )); } + @if not(index($exclude, 'igx-stepper')) { + @include igx-stepper(igx-stepper-theme($schema: $schema)); + } + @if not(index($exclude, 'igx-tabs')) { @include igx-tabs(igx-tabs-theme( $schema: $schema, diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_index.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_index.scss index aea995689c5..e12f406a412 100644 --- a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_index.scss +++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_index.scss @@ -55,6 +55,7 @@ @import './sparkline'; @import './splitter'; @import './switch'; +@import './stepper'; @import './tabs'; @import './time-picker'; @import './toast'; @@ -118,6 +119,7 @@ /// @property {Map} sparkline [$_dark-sparkline] /// @property {Map} igx-splitter [$_dark-splitter] /// @property {Map} igx-switch [$_dark-switch] +/// @property {Map} igx-stepper [$_dark-stepper] /// @property {Map} igx-tabs [$_dark-tabs] /// @property {Map} igx-time-picker [$_dark-time-picker] /// @property {Map} igx-toast [$_dark-toast] @@ -177,6 +179,7 @@ $dark-schema: ( sparkline: $_dark-sparkline, igx-splitter: $_dark-splitter, igx-switch: $_dark-switch, + igx-stepper: $_dark-stepper, igx-tabs: $_dark-tabs, igx-time-picker: $_dark-time-picker, igx-toast: $_dark-toast, @@ -246,6 +249,7 @@ $dark-material-schema: $dark-schema; /// @property {Map} sparkline [$_dark-fluent-sparkline], /// @property {Map} igx-splitter [$_dark-fluent-splitter], /// @property {Map} igx-switch [$_dark-fluent-switch], +/// @property {Map} igx-stepper [$_dark-fluent-stepper], /// @property {Map} igx-tabs [$_dark-fluent-tabs], /// @property {Map} igx-time-picker [$_dark-fluent-time-picker], /// @property {Map} igx-toast [$_dark-fluent-toast], @@ -305,6 +309,7 @@ $dark-fluent-schema: ( sparkline: $_dark-fluent-sparkline, igx-splitter: $_dark-fluent-splitter, igx-switch: $_dark-fluent-switch, + igx-stepper: $_dark-fluent-stepper, igx-tabs: $_dark-fluent-tabs, igx-time-picker: $_dark-fluent-time-picker, igx-toast: $_dark-fluent-toast, @@ -369,6 +374,7 @@ $dark-fluent-schema: ( /// @property {Map} sparkline [$_dark-bootstrap-sparkline], /// @property {Map} igx-splitter [$_dark-bootstrap-splitter], /// @property {Map} igx-switch [$_dark-bootstrap-switch], +/// @property {Map} igx-stepper [$_dark-bootstrap-stepper], /// @property {Map} igx-tabs [$_dark-bootstrap-tabs], /// @property {Map} igx-time-picker [$_dark-bootstrap-time-picker], /// @property {Map} igx-toast [$_dark-bootstrap-toast], @@ -428,6 +434,7 @@ $dark-bootstrap-schema: ( sparkline: $_dark-bootstrap-sparkline, igx-splitter: $_dark-bootstrap-splitter, igx-switch: $_dark-bootstrap-switch, + igx-stepper: $_dark-bootstrap-stepper, igx-tabs: $_dark-bootstrap-tabs, igx-time-picker: $_dark-bootstrap-time-picker, igx-toast: $_dark-bootstrap-toast, @@ -492,6 +499,7 @@ $dark-bootstrap-schema: ( /// @property {Map} sparkline [$_dark-indigo-sparkline] /// @property {Map} igx-splitter [$_dark-indigo-splitter] /// @property {Map} igx-switch [$_dark-indigo-switch] +/// @property {Map} igx-stepper [$_dark-indigo-stepper] /// @property {Map} igx-tabs [$_dark-indigo-tabs] /// @property {Map} igx-time-picker [$_dark-indigo-time-picker] /// @property {Map} igx-toast [$_dark-indigo-toast] @@ -551,6 +559,7 @@ $dark-indigo-schema: ( sparkline: $_dark-indigo-sparkline, igx-splitter: $_dark-indigo-splitter, igx-switch: $_dark-indigo-switch, + igx-stepper: $_dark-indigo-stepper, igx-tabs: $_dark-indigo-tabs, igx-time-picker: $_dark-indigo-time-picker, igx-toast: $_dark-indigo-toast, diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_stepper.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_stepper.scss new file mode 100644 index 00000000000..5a60567d499 --- /dev/null +++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_stepper.scss @@ -0,0 +1,37 @@ +@import '../light/stepper'; +//// +/// @group schemas +/// @access public +/// @author Marin Popov +//// + +/// Generates a dark stepper schema. +/// @type {Map} +/// +/// @requires {function} extend +/// @requires $_light-stepper +/// @see $default-palette +$_dark-stepper: extend($_light-stepper); + +/// Generates a dark fluent stepper schema +/// @type {Map} +/// +/// @requires {function} extend +/// @requires $_fluent-stepper +/// @requires $_base-dark-stepper +$_dark-fluent-stepper: extend($_fluent-stepper); + +/// Generates a dark bootstrap stepper schema. +/// @type {Map} +/// +/// @requires {function} extend +/// @requires $_bootstrap-stepper +/// @requires $_base-dark-stepper +$_dark-bootstrap-stepper: extend($_bootstrap-stepper); + +/// Generates a dark indigo stepper schema. +/// @type {Map} +/// +/// @requires {function} extend +/// @requires $_indigo-stepper +$_dark-indigo-stepper: extend($_indigo-stepper); diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_index.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_index.scss index b776bc62c36..f2c9d1acdc8 100644 --- a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_index.scss +++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_index.scss @@ -55,6 +55,7 @@ @import './sparkline'; @import './splitter'; @import './switch'; +@import './stepper'; @import './tabs'; @import './time-picker'; @import './toast'; @@ -118,6 +119,7 @@ /// @property {Map} sparkline [$_light-sparkline] /// @property {Map} igx-splitter [$_light-splitter] /// @property {Map} igx-switch [$_light-switch] +/// @property {Map} igx-stepper [$_light-stepper] /// @property {Map} igx-tabs [$_light-tabs] /// @property {Map} igx-time-picker [$_light-time-picker] /// @property {Map} igx-toast [$_light-toast] @@ -177,6 +179,7 @@ $light-schema: ( sparkline: $_light-sparkline, igx-splitter: $_light-splitter, igx-switch: $_light-switch, + igx-stepper: $_light-stepper, igx-tabs: $_light-tabs, igx-time-picker: $_light-time-picker, igx-toast: $_light-toast, @@ -247,6 +250,7 @@ $light-fluent-schema: ( sparkline: $_fluent-sparkline, igx-splitter: $_fluent-splitter, igx-switch: $_fluent-switch, + igx-stepper: $_fluent-stepper, igx-tabs: $_fluent-tabs, igx-time-picker: $_fluent-time-picker, igx-toast: $_fluent-toast, @@ -312,6 +316,7 @@ $light-bootstrap-schema: ( sparkline: $_bootstrap-sparkline, igx-splitter: $_bootstrap-splitter, igx-switch: $_bootstrap-switch, + igx-stepper: $_bootstrap-stepper, igx-tabs: $_bootstrap-tabs, igx-time-picker: $_bootstrap-time-picker, igx-toast: $_bootstrap-toast, @@ -377,6 +382,7 @@ $light-indigo-schema: ( sparkline: $_indigo-sparkline, igx-splitter: $_indigo-splitter, igx-switch: $_indigo-switch, + igx-stepper: $_indigo-stepper, igx-tabs: $_indigo-tabs, igx-time-picker: $_indigo-time-picker, igx-toast: $_indigo-toast, diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_stepper.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_stepper.scss new file mode 100644 index 00000000000..4933e29b69e --- /dev/null +++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_stepper.scss @@ -0,0 +1,51 @@ +//// +/// @group schemas +/// @access public +/// @author Marin Popov +//// + +/// Generates a light stepper schema. +/// @type {Map} +/// +/// @requires {function} extend +/// @see $default-palette +$_light-stepper: extend( + ( + variant: 'material', + ) +); + +/// Generates a fluent stepper schema. +/// @type {Map} +/// +/// @requires {function} extend +/// @requires {Map} $_light-stepper +$_fluent-stepper: extend( + $_light-stepper + ( + variant: 'fluent', + ) +); + +/// Generates a bootstrap stepper schema. +/// @type {Map} +/// @requires {function} extend +/// @requires {Map} $_light-stepper +$_bootstrap-stepper: extend( + $_light-stepper, + ( + variant: 'bootstrap', + ) +); + +/// Generates an indigo stepper schema. +/// @type {Map} +/// +/// @requires {function} extend +/// @requires $_light-stepper +$_indigo-stepper: extend( + $_light-stepper, + ( + variant: 'indigo-design', + ) +); diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.scss b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.scss deleted file mode 100644 index a55ec7a707f..00000000000 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.scss +++ /dev/null @@ -1,44 +0,0 @@ -.igx-stepper { - display: flex; - width: 100%; - overflow: hidden; -} - -.igx-stepper--horizontal { - flex-direction: row; - justify-content: space-between; -} - -.igx-stepper--vertical { - flex-direction: column; - gap: 20px; -} - -.horizontal-container { - overflow: hidden; - position: relative; - flex-grow: 1; - display: block; - height: 200px; - - ::ng-deep { - .igx-step__content { - display: block; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - width: 100%; - height: 100%; - overflow-x: hidden; - overflow-y: auto; - z-index: -1; - } - - .igx-step__content--active { - position: relative; - z-index: 1; - } - } -} diff --git a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts index 98b6f1cbe76..38806cbe395 100644 --- a/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/igx-stepper.component.ts @@ -25,7 +25,6 @@ import { IgxStepperService } from './stepper.service'; @Component({ selector: 'igx-stepper', templateUrl: 'igx-stepper.component.html', - styleUrls: ['igx-stepper.component.scss'], providers: [ IgxStepperService, { provide: IGX_STEPPER_COMPONENT, useExisting: IgxStepperComponent }, diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.scss b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.scss deleted file mode 100644 index 9a1e53332ae..00000000000 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.scss +++ /dev/null @@ -1,32 +0,0 @@ -.igx-step__header { - border: 2px solid #ccc; - border-radius: 15px; - padding: 16px; -} - -.igx-step__header:hover { - background-color: rgba($color: #ccc, $alpha: 0.5); -} - -.igx-step__header--active { - pointer-events: none; - background-color: rgba($color: green, $alpha: 0.5); -} - -.igx-step__header--disabled { - pointer-events: none; - opacity: 0.5; -} - -.igx-step__header--skip { - opacity: 0.5; -} - -// .igx-step::after { -// content: '\21E2'; -// color: white; -// position: relative; -// top: -50%; -// left: 100%; -// z-index: 1; -// } diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts index 63a89a79764..d9c35c0d106 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts @@ -15,8 +15,7 @@ let NEXT_ID = 0; @Component({ selector: 'igx-step', - templateUrl: 'igx-step.component.html', - styleUrls: ['igx-step.component.scss'] + templateUrl: 'igx-step.component.html' }) export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, AfterViewInit, OnDestroy, IgxSlideComponentBase { @@ -206,8 +205,8 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A // } /** @hidden @internal */ - @HostBinding('class.igx-step') - public cssClass = 'igx-step'; + @HostBinding('class.igx-stepper__header-step') + public cssClass = 'igx-stepper__header-step'; // // TODO: will be used in Drag and Drop implementation // /** @hidden @internal */ @@ -314,10 +313,10 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A return 'igx-step__header--active'; } if (this.disabled) { - return 'igx-step__header--disabled'; + return 'igx-stepper__header-step-content--disabled'; } if (this.skip) { - return 'igx-step__header--skip'; + return 'igx-stepper__header-step-content--skip'; } if (this.optional) { return 'igx-step__header--optional'; diff --git a/src/app/stepper/stepper.sample.html b/src/app/stepper/stepper.sample.html index 2ce874d1782..9e25d090cd6 100644 --- a/src/app/stepper/stepper.sample.html +++ b/src/app/stepper/stepper.sample.html @@ -5,9 +5,6 @@ --> - -
- done @@ -46,8 +43,11 @@
-
- - - - + +
+ + + + +
+ diff --git a/src/app/stepper/stepper.sample.scss b/src/app/stepper/stepper.sample.scss index e69de29bb2d..9d5295a8da6 100644 --- a/src/app/stepper/stepper.sample.scss +++ b/src/app/stepper/stepper.sample.scss @@ -0,0 +1,5 @@ +.sample-actions { + margin-top: 20px; + display: flex; + align-items: center; +} From d9e4a8c9207e469761cb0c6e7cc0cd56b76f7f0a Mon Sep 17 00:00:00 2001 From: MPopov Date: Thu, 16 Sep 2021 13:00:55 +0300 Subject: [PATCH 33/33] feat(stepper): add some initial styles --- .../stepper/_stepper-component.scss | 150 +++++++++++++----- .../components/stepper/_stepper-theme.scss | 1 + .../lib/stepper/step/igx-step.component.html | 7 +- .../lib/stepper/step/igx-step.component.ts | 14 +- 4 files changed, 120 insertions(+), 52 deletions(-) diff --git a/projects/igniteui-angular/src/lib/core/styles/components/stepper/_stepper-component.scss b/projects/igniteui-angular/src/lib/core/styles/components/stepper/_stepper-component.scss index 134b20337be..b6a0ddb1605 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/stepper/_stepper-component.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/stepper/_stepper-component.scss @@ -14,7 +14,6 @@ @include e(header) { display: flex; flex-direction: column; - gap: 20px; width: 100%; } @@ -25,53 +24,124 @@ position: relative } - @include e(body-contnet) { - display: block; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - width: 100%; - height: 100%; - overflow-y: auto; - overflow-x: hidden; - z-index: -1; + @include e(step) { + display: flex; + position: relative; + flex-direction: column; + align-content: center; + justify-content: center; + } + + @include e(step-header) { + padding: rem(16px); + display: flex; + align-content: center; + margin: rem(8px) 0; + + &:hover { + background: rgba(255, 255, 255, .5); + } } - @include e(body-contnet, $m: active) { - z-index: 1; + @include e(step-content) { + margin-left: rem(40px); position: relative; + + &::before { + content: ''; + position: absolute; + top: rem(-8px); + bottom: rem(-8px); + left: rem(-12px); + height: 100%; + width: rem(1px); + background: #999; + } } -} -// TODO THIS SHOULD GO ON THE HOST ELEMENT -.igx-stepper__header--horizontal { - flex-direction: row; - justify-content: space-between; -} + @include e(step, $m: active) { + background: white; + color: #000; + } -// content -.igx-stepper__header-step-content { - border: 2px solid #ccc; - border-radius: 15px; - padding: 16px; -} + @include e(step, $m: disabled) { + background: gray; + opacity: .5; -.igx-stepper__header-step-content:hover { - background-color: rgba($color: #ccc, $alpha: .5); -} + &:hover { + background: gray; + } + } -.igx-stepper__header-step-content--active { - pointer-events: none; - background-color: rgba($color: green, $alpha: .5); -} + @include e(step, $m: skip) { + background: #916418; + } -.igx-stepper__header-step-content--disabled { - pointer-events: none; - opacity: .5; -} + @include m(horizontal) { + @include e(header) { + flex-direction: row; + } + + @include e(step) { + flex-grow: 1; + flex-direction: row; + + &::before, + &::after { + content: ''; + width: auto; + height: 1px; + flex: 1; + align-self: center; + background: #999; + } + + &:last-of-type, + &:first-of-type { + flex-basis: 0; + } -.igx-stepper__header-step-content--skip { - opacity: .5; + &:first-of-type { + &::before { + display: none; + } + } + + &:last-of-type { + &::after { + display: none; + } + } + } + + @include e(step-header) { + justify-content: center; + margin: 0 rem(8px); + } + + @include e(step-content) { + &::before { + display: none; + } + } + + @include e(body-content) { + display: block; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: 100%; + height: 100%; + overflow-y: auto; + overflow-x: hidden; + z-index: -1; + } + + @include e(body-content, $m: active) { + z-index: 1; + position: relative; + } + } } diff --git a/projects/igniteui-angular/src/lib/core/styles/components/stepper/_stepper-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/stepper/_stepper-theme.scss index e24cfffc6f4..e5dd10d8dce 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/stepper/_stepper-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/stepper/_stepper-theme.scss @@ -59,6 +59,7 @@ %stepper-display { display: flex; + flex-direction: column; width: 100%; overflow: hidden; } diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html index f067083bdc6..ddaa96572e3 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.html @@ -1,7 +1,5 @@ -
- -
+
@@ -10,8 +8,7 @@
- -
+
diff --git a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts index d9c35c0d106..b895a6869ef 100644 --- a/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts +++ b/projects/igniteui-angular/src/lib/stepper/step/igx-step.component.ts @@ -205,8 +205,8 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A // } /** @hidden @internal */ - @HostBinding('class.igx-stepper__header-step') - public cssClass = 'igx-stepper__header-step'; + @HostBinding('class.igx-stepper__step') + public cssClass = 'igx-stepper__step'; // // TODO: will be used in Drag and Drop implementation // /** @hidden @internal */ @@ -304,22 +304,22 @@ export class IgxStepComponent extends ToggleAnimationPlayer implements OnInit, A if (this.isHorizontal) { return { 'igx-stepper__body-content': true, 'igx-stepper__body-content--active': this.active }; } else { - return 'igx-step__content'; + return 'igx-stepper__step-content'; } } public get stepHeaderClasses() { if (this.active) { - return 'igx-step__header--active'; + return 'igx-stepper__step--active'; } if (this.disabled) { - return 'igx-stepper__header-step-content--disabled'; + return 'igx-stepper__step--disabled'; } if (this.skip) { - return 'igx-stepper__header-step-content--skip'; + return 'igx-stepper__step--skip'; } if (this.optional) { - return 'igx-step__header--optional'; + return 'igx-stepper__step--optional'; } }