diff --git a/CHANGELOG.md b/CHANGELOG.md
index 56215aa2a22..127d23247d7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,16 @@ All notable changes for each version of this project will be documented in this
### New Features
+- `IgxActionStrip` component added.
+ - Provides a template area for one or more actions. In its simplest form the Action Strip
+ is an overlay of any container and shows additional content over that container.
+
+ ```html
+
+
+
+ ```
+
- `igxSplitter` component added.
- Allows rendering a vertical or horizontal splitter with multiple splitter panes with templatable content.
Panes can be resized or collapsed/expanded via the UI. Splitter orientation is defined via the `type` input.
diff --git a/projects/igniteui-angular/src/lib/action-strip/README.md b/projects/igniteui-angular/src/lib/action-strip/README.md
new file mode 100644
index 00000000000..68fbe1aa475
--- /dev/null
+++ b/projects/igniteui-angular/src/lib/action-strip/README.md
@@ -0,0 +1,78 @@
+# igx-action-strip
+
+The **igx-action-strip** provides a template area for one or more actions.
+In its simplest form the Action Strip is an overlay of any container and shows additional content over that container.
+A walk-through of how to get started can be found [here](https://www.infragistics.com/products/ignite-ui-angular/angular/components/action_strip.html)
+
+# Usage
+The Action Strip can be initialized in any HTML element that can contain elements. This parent element should be with a relative position as the action strip is trying to overlay it. Interactions with the parent and its content are available while the action strip is shown.
+```html
+
+
+
+```
+
+# Grid Action Components
+Action strip provides functionality and UI for IgxGrid. All that can be utilized with grid action components. These components inherit `IgxGridActionsBaseDirective` and when creating a custom grid action component, this component should also inherit `IgxGridActionsBaseDirective`.
+
+```html
+
+
+
+
+```
+
+# IgxActionStripMenuItem
+
+The Action Strip can show items as menu. This is achieved with `igxActionStripMenuItem` directive applied to its content. Action strip will render three-dot button that toggles a drop down. And the content will be those items that are marked with `igxActionStripMenuItem` directive.
+
+```html
+
+ Copy
+ Paste
+ Edit
+
+```
+# API Summary
+
+## Inputs
+`IgxActionStripComponent`
+
+ | Name | Description | Type | Default value |
+ |-----------------|---------------------------------------------------|-----------------------------|---------------|
+ | hidden | An @Input property that sets the visibility of the Action Strip. | boolean | `false` |
+ | context | Sets the context of an action strip. The context should be an instance of a @Component, that has element property. This element will be the placeholder of the action strip. | any | |
+
+`IgxGridActionsBaseDirective` ( `IgxGridPinningActionsComponent`, `IgxGridEditingActionsComponent`)
+
+ | Name | Description | Type | Default value |
+ |-----------------|---------------------------------------------------|-----------------------------|---------------|
+ | grid | Set an instance of the grid for which to display the actions. | any | |
+ | context | Sets the context of an action strip. The context is expected to be grid cell or grid row | any | |
+
+## Outputs
+|Name|Description|Cancelable|Parameters|
+|--|--|--|--|
+| onMenuOpening | Emitted before the menu is opened | true | |
+| onMenuOpened | Emitted after the menu is opened | false | |
+
+## Methods
+
+`IgxActionStripComponent`
+
+ | Name | Description | Return type | Parameters |
+ |----------|----------------------------|---------------------------------------------------|----------------------|
+ | show | Showing the Action Strip and appending it the specified context element. | void | context |
+ | hide | Hiding the Action Strip and removing it from its current context element. | void | |
+
+`IgxGridPinningActionsComponent`
+ | Name | Description | Return type | Parameters |
+ |----------|----------------------------|---------------------------------------------------|----------------------|
+ | pin | Pin the row according to the context. | void | |
+ | unpin | Unpin the row according to the context. | void | |
+
+`IgxGridPinningActionsComponent`
+ | Name | Description | Return type | Parameters |
+ |----------|----------------------------|---------------------------------------------------|----------------------|
+ | startEdit | Enter row or cell edit mode depending the grid `rowEdibable` option | void | |
+ | deleteRow | Delete a row according to the context | void | |
\ No newline at end of file
diff --git a/projects/igniteui-angular/src/lib/action-strip/action-strip.component.html b/projects/igniteui-angular/src/lib/action-strip/action-strip.component.html
new file mode 100644
index 00000000000..6fef5a08059
--- /dev/null
+++ b/projects/igniteui-angular/src/lib/action-strip/action-strip.component.html
@@ -0,0 +1,17 @@
+
+
+
0">
+
+ more_vert
+
+
+
+
+
+
+
+
+
+
diff --git a/projects/igniteui-angular/src/lib/action-strip/action-strip.component.spec.ts b/projects/igniteui-angular/src/lib/action-strip/action-strip.component.spec.ts
new file mode 100644
index 00000000000..d7555560cb7
--- /dev/null
+++ b/projects/igniteui-angular/src/lib/action-strip/action-strip.component.spec.ts
@@ -0,0 +1,251 @@
+import { IgxActionStripComponent } from './action-strip.component';
+import { Component, ViewChild, ElementRef, ViewContainerRef } from '@angular/core';
+import { configureTestSuite } from '../test-utils/configure-suite';
+import { TestBed, async } from '@angular/core/testing';
+import { IgxIconModule } from '../icon';
+import { By } from '@angular/platform-browser';
+import { UIInteractions, wait } from '../test-utils/ui-interactions.spec';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { IgxToggleModule } from '../directives/toggle/toggle.directive';
+import { IgxActionStripModule } from './action-strip.module';
+
+const ACTION_STRIP_CONTAINER_CSS = 'igx-action-strip__actions';
+const DROP_DOWN_LIST = 'igx-drop-down__list';
+
+describe('igxActionStrip', () => {
+ let fixture;
+ let actionStrip: IgxActionStripComponent;
+ let actionStripElement: ElementRef;
+ let parentContainer: ElementRef;
+ let innerContainer: ViewContainerRef;
+
+ describe('Unit tests: ', () => {
+ const mockViewContainerRef = jasmine.createSpyObj('ViewContainerRef', ['element']);
+ const mockRenderer2 = jasmine.createSpyObj('Renderer2', ['appendChild', 'removeChild']);
+ const mockContext = jasmine.createSpyObj('context', ['element']);
+ const mockDisplayDensity = jasmine.createSpyObj('IDisplayDensityOptions', ['displayDensity']);
+
+ it('should properly get/set hidden', () => {
+ actionStrip = new IgxActionStripComponent(mockViewContainerRef, mockRenderer2, mockDisplayDensity);
+ expect(actionStrip.hidden).toBeFalsy();
+ actionStrip.hidden = true;
+ expect(actionStrip.hidden).toBeTruthy();
+ });
+
+ it('should properly show and hide using API', () => {
+ actionStrip = new IgxActionStripComponent(mockViewContainerRef, mockRenderer2, mockDisplayDensity);
+ actionStrip.show(mockContext);
+ expect(actionStrip.hidden).toBeFalsy();
+ expect(actionStrip.context).toBe(mockContext);
+ actionStrip.hide();
+ expect(actionStrip.hidden).toBeTruthy();
+ });
+ });
+
+ describe('Initialization and rendering tests: ', () => {
+ configureTestSuite();
+ beforeAll(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [
+ IgxActionStripTestingComponent
+ ],
+ imports: [
+ IgxActionStripModule,
+ IgxIconModule
+ ]
+ }).compileComponents();
+ }));
+ beforeEach(() => {
+ fixture = TestBed.createComponent(IgxActionStripTestingComponent);
+ fixture.detectChanges();
+ actionStrip = fixture.componentInstance.actionStrip;
+ actionStripElement = fixture.componentInstance.actionStripElement;
+ parentContainer = fixture.componentInstance.parentContainer;
+ innerContainer = fixture.componentInstance.innerContainer;
+ });
+ it('should be overlapping its parent container when no context is applied', () => {
+ const parentBoundingRect = parentContainer.nativeElement.getBoundingClientRect();
+ const actionStripBoundingRect = actionStripElement.nativeElement.getBoundingClientRect();
+ expect(parentBoundingRect.top).toBe(actionStripBoundingRect.top);
+ expect(parentBoundingRect.bottom).toBe(actionStripBoundingRect.bottom);
+ expect(parentBoundingRect.left).toBe(actionStripBoundingRect.left);
+ expect(parentBoundingRect.right).toBe(actionStripBoundingRect.right);
+ });
+
+ it('should be overlapping context.element when context is applied', () => {
+ actionStrip.show(innerContainer);
+ fixture.detectChanges();
+ const innerBoundingRect = innerContainer.element.nativeElement.getBoundingClientRect();
+ const actionStripBoundingRect = actionStripElement.nativeElement.getBoundingClientRect();
+ expect(innerBoundingRect.top).toBe(actionStripBoundingRect.top);
+ expect(innerBoundingRect.bottom).toBe(actionStripBoundingRect.bottom);
+ expect(innerBoundingRect.left).toBe(actionStripBoundingRect.left);
+ expect(innerBoundingRect.right).toBe(actionStripBoundingRect.right);
+ });
+
+ it('should allow interacting with the content elements', () => {
+ const asIcon = fixture.debugElement.query(By.css('.asIcon'));
+ asIcon.triggerEventHandler('click', new Event('click'));
+ fixture.detectChanges();
+ expect(fixture.componentInstance.flag).toBeTruthy();
+ });
+
+ it('should not display the action strip when setting it hidden', () => {
+ actionStrip.hidden = true;
+ fixture.detectChanges();
+ const asQuery = fixture.debugElement.query(By.css('igx-action-strip'));
+ expect(asQuery.nativeElement.style.display).toBe('none');
+ });
+ });
+
+ describe('render content as menu', () => {
+ configureTestSuite();
+ beforeAll(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [
+ IgxActionStripMenuTestingComponent,
+ IgxActionStripCombinedMenuTestingComponent
+ ],
+ imports: [
+ IgxActionStripModule,
+ IgxIconModule,
+ NoopAnimationsModule,
+ IgxToggleModule
+ ]
+ }).compileComponents();
+ }));
+
+ it('should render tree-dot button which toggles the content as menu', () => {
+ fixture = TestBed.createComponent(IgxActionStripMenuTestingComponent);
+ fixture.detectChanges();
+ actionStrip = fixture.componentInstance.actionStrip;
+ const actionStripContainer = fixture.debugElement.query(By.css(`.${ACTION_STRIP_CONTAINER_CSS}`));
+ // there should be one rendered child and one hidden dropdown
+ expect(actionStripContainer.nativeElement.children.length).toBe(2);
+ let dropDownList = fixture.debugElement.query(By.css(`.${DROP_DOWN_LIST}`));
+ expect(dropDownList.nativeElement.getAttribute('aria-hidden')).toBe('true');
+ const icon = fixture.debugElement.query(By.css(`igx-icon`));
+ icon.parent.triggerEventHandler('click', new Event('click'));
+ fixture.detectChanges();
+ dropDownList = fixture.debugElement.query(By.css(`.${DROP_DOWN_LIST}`));
+ expect(dropDownList.nativeElement.getAttribute('aria-hidden')).toBe('false');
+ const dropDownItems = dropDownList.queryAll(By.css('igx-drop-down-item'));
+ expect(dropDownItems.length).toBe(3);
+ });
+
+ it('should emit onMenuOpen/onMenuOpening when toggling the menu', () => {
+ pending('implementation');
+ });
+
+ it('should allow combining content outside and inside the menu', () => {
+ fixture = TestBed.createComponent(IgxActionStripCombinedMenuTestingComponent);
+ fixture.detectChanges();
+ actionStrip = fixture.componentInstance.actionStrip;
+ const actionStripContainer = fixture.debugElement.query(By.css(`.${ACTION_STRIP_CONTAINER_CSS}`));
+ // there should be one rendered child and one hidden dropdown and one additional icon
+ expect(actionStripContainer.nativeElement.children.length).toBe(3);
+ let dropDownList = fixture.debugElement.query(By.css(`.${DROP_DOWN_LIST}`));
+ expect(dropDownList.nativeElement.getAttribute('aria-hidden')).toBe('true');
+ const icon = fixture.debugElement.query(By.css(`igx-icon`));
+ icon.parent.triggerEventHandler('click', new Event('click'));
+ fixture.detectChanges();
+ dropDownList = fixture.debugElement.query(By.css(`.${DROP_DOWN_LIST}`));
+ expect(dropDownList.nativeElement.getAttribute('aria-hidden')).toBe('false');
+ const dropDownItems = dropDownList.queryAll(By.css('igx-drop-down-item'));
+ expect(dropDownItems.length).toBe(2);
+ });
+
+ it('should close the menu when hiding action strip', async() => {
+ fixture = TestBed.createComponent(IgxActionStripCombinedMenuTestingComponent);
+ fixture.detectChanges();
+ actionStrip = fixture.componentInstance.actionStrip;
+ // there should be one rendered child and one hidden dropdown and one additional icon
+ const icon = fixture.debugElement.query(By.css(`igx-icon`));
+ icon.parent.triggerEventHandler('click', new Event('click'));
+ fixture.detectChanges();
+ let dropDownList = fixture.debugElement.query(By.css(`.${DROP_DOWN_LIST}`));
+ expect(dropDownList.nativeElement.getAttribute('aria-hidden')).toBe('false');
+ actionStrip.hide();
+ await wait();
+ fixture.detectChanges();
+ dropDownList = fixture.debugElement.query(By.css(`.${DROP_DOWN_LIST}`));
+ expect(dropDownList.nativeElement.getAttribute('aria-hidden')).toBe('true');
+ });
+ });
+});
+
+@Component({
+ template: `
+
+
+
+ Lorem ipsum dolor sit
+
+
+
+ alarm
+
+
+`
+})
+class IgxActionStripTestingComponent {
+ @ViewChild('actionStrip', { read: IgxActionStripComponent, static: true })
+ public actionStrip: IgxActionStripComponent;
+
+ @ViewChild('actionStrip', { read: ElementRef, static: true })
+ public actionStripElement: ElementRef;
+
+ @ViewChild('parent', { static: true })
+ public parentContainer: ElementRef;
+
+ @ViewChild('inner', { read: ViewContainerRef, static: true })
+ public innerContainer: ViewContainerRef;
+
+ public flag = false;
+
+ onIconClick() {
+ this.flag = true;
+ }
+}
+
+@Component({
+ template: `
+
+
+
+ Lorem ipsum dolor sit
+
+
+
+ Mark
+ Favorite
+ Download
+
+
+ `
+})
+class IgxActionStripMenuTestingComponent {
+ @ViewChild('actionStrip', { read: IgxActionStripComponent, static: true })
+ public actionStrip: IgxActionStripComponent;
+}
+
+@Component({
+ template: `
+
+
+
+ Lorem ipsum dolor sit
+
+
+
+ Mark
+ Favorite
+ Download
+
+
+ `
+})
+class IgxActionStripCombinedMenuTestingComponent {
+ @ViewChild('actionStrip', { read: IgxActionStripComponent, static: true })
+ public actionStrip: IgxActionStripComponent;
+}
diff --git a/projects/igniteui-angular/src/lib/action-strip/action-strip.component.ts b/projects/igniteui-angular/src/lib/action-strip/action-strip.component.ts
new file mode 100644
index 00000000000..6d16977d709
--- /dev/null
+++ b/projects/igniteui-angular/src/lib/action-strip/action-strip.component.ts
@@ -0,0 +1,200 @@
+import {
+ Component,
+ Directive,
+ HostBinding,
+ Input,
+ Renderer2,
+ ViewContainerRef,
+ Optional,
+ Inject,
+ ContentChildren,
+ QueryList,
+ ViewChild,
+ TemplateRef
+} from '@angular/core';
+import { DisplayDensityBase, DisplayDensityToken, IDisplayDensityOptions } from '../core/density';
+import { IgxDropDownComponent } from '../drop-down';
+import { CloseScrollStrategy, OverlaySettings } from '../services';
+
+@Directive({
+ selector: '[igxActionStripMenuItem]'
+})
+export class IgxActionStripMenuItemDirective {
+ constructor(
+ public templateRef: TemplateRef
+ ) { }
+}
+
+/**
+ * Action Strip provides templatable area for one or more actions.
+ *
+ * @igxModule IgxActionStripModule
+ *
+ * @igxTheme igx-action-strip-theme
+ *
+ * @igxKeywords action, strip, actionStrip, pinning, editing
+ *
+ * @igxGroup Data Entry & Display
+ *
+ * @remarks
+ * The Ignite UI Action Strip is a container, overlaying its parent container,
+ * and displaying action buttons with action applicable to the parent component the strip is instantiated or shown for.
+ *
+ * @example
+ * ```html
+ *
+ *
+ *
+ */
+@Component({
+ selector: 'igx-action-strip',
+ templateUrl: 'action-strip.component.html'
+})
+
+export class IgxActionStripComponent extends DisplayDensityBase {
+ constructor(
+ private _viewContainer: ViewContainerRef,
+ private renderer: Renderer2,
+ @Optional() @Inject(DisplayDensityToken) protected _displayDensityOptions: IDisplayDensityOptions) {
+ super(_displayDensityOptions);
+ }
+
+ /**
+ * Getter for the 'display' property of the current `IgxActionStrip`
+ * @hidden
+ * @internal
+ */
+ @HostBinding('style.display')
+ get display(): string {
+ return this._hidden ? 'none' : 'flex';
+ }
+
+ private _hidden = false;
+
+ /**
+ * An @Input property that set the visibility of the Action Strip.
+ * Could be used to set if the Action Strip will be initially hidden.
+ * @example
+ * ```html
+ *
+ * ```
+ */
+ @Input()
+ public set hidden(value) {
+ this._hidden = value;
+ }
+
+ public get hidden() {
+ return this._hidden;
+ }
+
+ /**
+ * Host `class.igx-action-strip` binding.
+ * @hidden
+ * @internal
+ */
+ @Input('class')
+ hostClass: string;
+
+ /**
+ * Host `attr.class` binding.
+ * @hidden
+ * @internal
+ */
+ @HostBinding('attr.class')
+ get hostClasses(): string {
+ const classes = [this.getComponentDensityClass('igx-action-strip')];
+ // The custom classes should be at the end.
+ if (!classes.includes('igx-action-strip')) {
+ classes.push('igx-action-strip');
+ }
+ classes.push(this.hostClass);
+ return classes.join(' ');
+ }
+
+ /**
+ * Sets the context of an action strip.
+ * The context should be an instance of a @Component, that has element property.
+ * This element will be the placeholder of the action strip.
+ * @example
+ * ```html
+ *
+ * ```
+ */
+ @Input()
+ public context: any;
+ /**
+ * Menu Items ContentChildren inside the Action Strip
+ * @hidden
+ * @internal
+ */
+ @ContentChildren(IgxActionStripMenuItemDirective)
+ public menuItems: QueryList;
+
+ /**
+ * Reference to the menu
+ * @hidden
+ * @internal
+ */
+ @ViewChild('dropdown')
+ private menu: IgxDropDownComponent;
+
+ /**
+ * Showing the Action Strip and appending it the specified context element.
+ * @param context
+ * @example
+ * ```typescript
+ * this.actionStrip.show(row);
+ * ```
+ */
+ public show(context?: any): void {
+ this.hidden = false;
+ if (!context) {
+ return;
+ }
+ // when shown for different context make sure the menu won't stay opened
+ if (this.context !== context) {
+ this.closeMenu();
+ }
+ this.context = context;
+ if (this.context && this.context.element) {
+ this.renderer.appendChild(context.element.nativeElement, this._viewContainer.element.nativeElement);
+ }
+ }
+
+ /**
+ * Hiding the Action Strip and removing it from its current context element.
+ * @example
+ * ```typescript
+ * this.actionStrip.hide();
+ * ```
+ */
+ public hide(): void {
+ this.hidden = true;
+ this.closeMenu();
+ if (this.context && this.context.element) {
+ this.renderer.removeChild(this.context.element.nativeElement, this._viewContainer.element.nativeElement);
+ }
+ }
+
+ /**
+ * Getter for menu overlay settings
+ * @hidden
+ * @internal
+ */
+ get menuOverlaySettings (): OverlaySettings {
+ return { scrollStrategy: new CloseScrollStrategy() };
+ }
+
+ /**
+ * Close the menu if opened
+ * @hidden
+ * @internal
+ */
+ private closeMenu(): void {
+ if (this.menu && !this.menu.collapsed) {
+ this.menu.close();
+ }
+ }
+}
+
diff --git a/projects/igniteui-angular/src/lib/action-strip/action-strip.module.ts b/projects/igniteui-angular/src/lib/action-strip/action-strip.module.ts
new file mode 100644
index 00000000000..478962d5482
--- /dev/null
+++ b/projects/igniteui-angular/src/lib/action-strip/action-strip.module.ts
@@ -0,0 +1,35 @@
+import { NgModule } from '@angular/core';
+import { IgxActionStripComponent, IgxActionStripMenuItemDirective } from './action-strip.component';
+import { IgxGridPinningActionsComponent } from './grid-actions/grid-pinning-actions.component';
+import { IgxGridEditingActionsComponent } from './grid-actions/grid-editing-actions.component';
+import { IgxGridActionsBaseDirective } from './grid-actions/grid-actions-base.directive';
+import { CommonModule } from '@angular/common';
+import { IgxDropDownModule } from '../drop-down/index';
+import { IgxToggleModule } from '../directives/toggle/toggle.directive';
+import { IgxButtonModule } from '../directives/button/button.directive';
+import { IgxIconModule } from '../icon/index';
+import { IgxRippleModule } from '../directives/ripple/ripple.directive';
+
+/**
+ * @hidden
+ */
+@NgModule({
+ declarations: [
+ IgxActionStripComponent,
+ IgxActionStripMenuItemDirective,
+ IgxGridPinningActionsComponent,
+ IgxGridEditingActionsComponent,
+ IgxGridActionsBaseDirective
+ ],
+ entryComponents: [
+ ],
+ exports: [
+ IgxActionStripComponent,
+ IgxActionStripMenuItemDirective,
+ IgxGridPinningActionsComponent,
+ IgxGridEditingActionsComponent,
+ IgxGridActionsBaseDirective
+ ],
+ imports: [CommonModule, IgxDropDownModule, IgxToggleModule, IgxButtonModule, IgxIconModule, IgxRippleModule]
+})
+export class IgxActionStripModule { }
diff --git a/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-actions-base.directive.ts b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-actions-base.directive.ts
new file mode 100644
index 00000000000..ae8bc91924d
--- /dev/null
+++ b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-actions-base.directive.ts
@@ -0,0 +1,29 @@
+import { Directive, Inject } from '@angular/core';
+import { IgxActionStripComponent } from '../action-strip.component';
+import { IgxRowDirective } from '../../grids';
+
+@Directive({
+ selector: '[igxGridActionsBase]'
+})
+export class IgxGridActionsBaseDirective {
+ constructor(@Inject(IgxActionStripComponent) protected strip: IgxActionStripComponent) { }
+
+ /**
+ * Getter to be used in template
+ * @hidden
+ * @internal
+ */
+ get isRowContext(): boolean {
+ return this.isRow(this.strip.context);
+ }
+
+ /**
+ * Check if the param is a row from a grid
+ * @hidden
+ * @internal
+ * @param context
+ */
+ protected isRow(context): context is IgxRowDirective {
+ return context && context instanceof IgxRowDirective;
+ }
+}
diff --git a/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-editing-actions.component.html b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-editing-actions.component.html
new file mode 100644
index 00000000000..23a4c1939b4
--- /dev/null
+++ b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-editing-actions.component.html
@@ -0,0 +1,8 @@
+
+
+ edit
+
+
+ delete
+
+
diff --git a/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-editing-actions.component.spec.ts b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-editing-actions.component.spec.ts
new file mode 100644
index 00000000000..a025c326835
--- /dev/null
+++ b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-editing-actions.component.spec.ts
@@ -0,0 +1,174 @@
+import { Component, ViewChild, OnInit } from '@angular/core';
+import { IgxActionStripComponent } from '../action-strip.component';
+import { configureTestSuite } from '../../test-utils/configure-suite';
+import { TestBed, async } from '@angular/core/testing';
+import { IgxIconModule } from '../../icon';
+import { IgxGridModule, IgxGridComponent } from '../../grids/grid';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { By } from '@angular/platform-browser';
+import { IgxActionStripModule } from '../action-strip.module';
+
+
+describe('igxGridEditingActions #grid ', () => {
+ let fixture;
+ let actionStrip: IgxActionStripComponent;
+ let grid: IgxGridComponent;
+ configureTestSuite();
+ beforeAll(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [
+ IgxActionStripTestingComponent,
+ IgxActionStripPinEditComponent
+ ],
+ imports: [
+ NoopAnimationsModule,
+ IgxActionStripModule,
+ IgxGridModule,
+ IgxIconModule
+ ]
+ }).compileComponents();
+ }));
+ beforeEach(() => {
+ fixture = TestBed.createComponent(IgxActionStripTestingComponent);
+ fixture.detectChanges();
+ actionStrip = fixture.componentInstance.actionStrip;
+ grid = fixture.componentInstance.grid;
+ });
+
+ it('should allow editing and deleting row', () => {
+ let editIcon, deleteIcon;
+ actionStrip.show(grid.rowList.first);
+ fixture.detectChanges();
+ editIcon = fixture.debugElement.queryAll(By.css(`igx-grid-editing-actions igx-icon`))[0];
+ expect(editIcon.nativeElement.innerText).toBe('edit');
+ editIcon.parent.triggerEventHandler('click', new Event('click'));
+ fixture.detectChanges();
+ expect(grid.rowInEditMode).not.toBeNull();
+ expect(grid.rowList.first.inEditMode).toBe(true);
+
+ expect(grid.rowList.first.rowData['ID']).toBe('ALFKI');
+ const dataLenght = grid.dataLength;
+ actionStrip.show(grid.rowList.first);
+ fixture.detectChanges();
+ deleteIcon = fixture.debugElement.queryAll(By.css(`igx-grid-editing-actions igx-icon`))[1];
+ expect(deleteIcon.nativeElement.innerText).toBe('delete');
+ deleteIcon.parent.triggerEventHandler('click', new Event('click'));
+ actionStrip.hide();
+ fixture.detectChanges();
+ expect(grid.rowList.first.rowData['ID']).toBe('ANATR');
+ expect(dataLenght - 1).toBe(grid.dataLength);
+ });
+
+ describe('integration with pinning actions ', () => {
+ beforeEach(() => {
+ fixture = TestBed.createComponent(IgxActionStripPinEditComponent);
+ fixture.detectChanges();
+ actionStrip = fixture.componentInstance.actionStrip;
+ grid = fixture.componentInstance.grid;
+ });
+ it('should disable editing actions on disabled rows', () => {
+ grid.rowList.first.pin();
+ fixture.detectChanges();
+ actionStrip.show(grid.rowList.toArray()[1]);
+ fixture.detectChanges();
+ const editingIcons = fixture.debugElement.queryAll(By.css(`igx-grid-editing-actions button`));
+ const pinningIcons = fixture.debugElement.queryAll(By.css(`igx-grid-pinning-actions button`));
+ expect(editingIcons.length).toBe(2);
+ expect(editingIcons[0].nativeElement.className.indexOf('igx-button--disabled') !== -1).toBeTruthy();
+ expect(editingIcons[1].nativeElement.className.indexOf('igx-button--disabled') !== -1).toBeTruthy();
+ expect(pinningIcons.length).toBe(1);
+ expect(pinningIcons[0].nativeElement.className.indexOf('igx-button--disabled') === -1).toBeTruthy();
+ });
+ });
+});
+
+@Component({
+ template: `
+
+
+
+
+
+
+
+
+`
+})
+class IgxActionStripTestingComponent implements OnInit {
+ @ViewChild('actionStrip', { read: IgxActionStripComponent, static: true })
+ public actionStrip: IgxActionStripComponent;
+
+ @ViewChild('grid', { read: IgxGridComponent, static: true })
+ public grid: IgxGridComponent;
+
+ data: any[];
+ columns: any[];
+
+ ngOnInit() {
+
+ this.columns = [
+ { field: 'ID', width: '200px', hidden: false },
+ { field: 'CompanyName', width: '200px' },
+ { field: 'ContactName', width: '200px', pinned: false },
+ { field: 'ContactTitle', width: '300px', pinned: false },
+ { field: 'Address', width: '250px' },
+ { field: 'City', width: '200px' },
+ { field: 'Region', width: '300px' },
+ { field: 'PostalCode', width: '150px' },
+ { field: 'Phone', width: '200px' },
+ { field: 'Fax', width: '200px' }
+ ];
+
+ this.data = [
+ // tslint:disable:max-line-length
+ { 'ID': 'ALFKI', 'CompanyName': 'Alfreds Futterkiste', 'ContactName': 'Maria Anders', 'ContactTitle': 'Sales Representative', 'Address': 'Obere Str. 57', 'City': 'Berlin', 'Region': null, 'PostalCode': '12209', 'Country': 'Germany', 'Phone': '030-0074321', 'Fax': '030-0076545' },
+ { 'ID': 'ANATR', 'CompanyName': 'Ana Trujillo Emparedados y helados', 'ContactName': 'Ana Trujillo', 'ContactTitle': 'Owner', 'Address': 'Avda. de la Constitución 2222', 'City': 'México D.F.', 'Region': null, 'PostalCode': '05021', 'Country': 'Mexico', 'Phone': '(5) 555-4729', 'Fax': '(5) 555-3745' },
+ { 'ID': 'ANTON', 'CompanyName': 'Antonio Moreno Taquería', 'ContactName': 'Antonio Moreno', 'ContactTitle': 'Owner', 'Address': 'Mataderos 2312', 'City': 'México D.F.', 'Region': null, 'PostalCode': '05023', 'Country': 'Mexico', 'Phone': '(5) 555-3932', 'Fax': null },
+ { 'ID': 'AROUT', 'CompanyName': 'Around the Horn', 'ContactName': 'Thomas Hardy', 'ContactTitle': 'Sales Representative', 'Address': '120 Hanover Sq.', 'City': 'London', 'Region': null, 'PostalCode': 'WA1 1DP', 'Country': 'UK', 'Phone': '(171) 555-7788', 'Fax': '(171) 555-6750' },
+ { 'ID': 'BERGS', 'CompanyName': 'Berglunds snabbköp', 'ContactName': 'Christina Berglund', 'ContactTitle': 'Order Administrator', 'Address': 'Berguvsvägen 8', 'City': 'Luleå', 'Region': null, 'PostalCode': 'S-958 22', 'Country': 'Sweden', 'Phone': '0921-12 34 65', 'Fax': '0921-12 34 67' },
+ { 'ID': 'BLAUS', 'CompanyName': 'Blauer See Delikatessen', 'ContactName': 'Hanna Moos', 'ContactTitle': 'Sales Representative', 'Address': 'Forsterstr. 57', 'City': 'Mannheim', 'Region': null, 'PostalCode': '68306', 'Country': 'Germany', 'Phone': '0621-08460', 'Fax': '0621-08924' },
+ { 'ID': 'BLONP', 'CompanyName': 'Blondesddsl père et fils', 'ContactName': 'Frédérique Citeaux', 'ContactTitle': 'Marketing Manager', 'Address': '24, place Kléber', 'City': 'Strasbourg', 'Region': null, 'PostalCode': '67000', 'Country': 'France', 'Phone': '88.60.15.31', 'Fax': '88.60.15.32' },
+ { 'ID': 'BOLID', 'CompanyName': 'Bólido Comidas preparadas', 'ContactName': 'Martín Sommer', 'ContactTitle': 'Owner', 'Address': 'C/ Araquil, 67', 'City': 'Madrid', 'Region': null, 'PostalCode': '28023', 'Country': 'Spain', 'Phone': '(91) 555 22 82', 'Fax': '(91) 555 91 99' },
+ { 'ID': 'BONAP', 'CompanyName': 'Bon app\'', 'ContactName': 'Laurence Lebihan', 'ContactTitle': 'Owner', 'Address': '12, rue des Bouchers', 'City': 'Marseille', 'Region': null, 'PostalCode': '13008', 'Country': 'France', 'Phone': '91.24.45.40', 'Fax': '91.24.45.41' },
+ { 'ID': 'BOTTM', 'CompanyName': 'Bottom-Dollar Markets', 'ContactName': 'Elizabeth Lincoln', 'ContactTitle': 'Accounting Manager', 'Address': '23 Tsawassen Blvd.', 'City': 'Tsawassen', 'Region': 'BC', 'PostalCode': 'T2F 8M4', 'Country': 'Canada', 'Phone': '(604) 555-4729', 'Fax': '(604) 555-3745' },
+ { 'ID': 'BSBEV', 'CompanyName': 'B\'s Beverages', 'ContactName': 'Victoria Ashworth', 'ContactTitle': 'Sales Representative', 'Address': 'Fauntleroy Circus', 'City': 'London', 'Region': null, 'PostalCode': 'EC2 5NT', 'Country': 'UK', 'Phone': '(171) 555-1212', 'Fax': null },
+ { 'ID': 'CACTU', 'CompanyName': 'Cactus Comidas para llevar', 'ContactName': 'Patricio Simpson', 'ContactTitle': 'Sales Agent', 'Address': 'Cerrito 333', 'City': 'Buenos Aires', 'Region': null, 'PostalCode': '1010', 'Country': 'Argentina', 'Phone': '(1) 135-5555', 'Fax': '(1) 135-4892' },
+ { 'ID': 'CENTC', 'CompanyName': 'Centro comercial Moctezuma', 'ContactName': 'Francisco Chang', 'ContactTitle': 'Marketing Manager', 'Address': 'Sierras de Granada 9993', 'City': 'México D.F.', 'Region': null, 'PostalCode': '05022', 'Country': 'Mexico', 'Phone': '(5) 555-3392', 'Fax': '(5) 555-7293' },
+ { 'ID': 'CHOPS', 'CompanyName': 'Chop-suey Chinese', 'ContactName': 'Yang Wang', 'ContactTitle': 'Owner', 'Address': 'Hauptstr. 29', 'City': 'Bern', 'Region': null, 'PostalCode': '3012', 'Country': 'Switzerland', 'Phone': '0452-076545', 'Fax': null },
+ { 'ID': 'COMMI', 'CompanyName': 'Comércio Mineiro', 'ContactName': 'Pedro Afonso', 'ContactTitle': 'Sales Associate', 'Address': 'Av. dos Lusíadas, 23', 'City': 'Sao Paulo', 'Region': 'SP', 'PostalCode': '05432-043', 'Country': 'Brazil', 'Phone': '(11) 555-7647', 'Fax': null },
+ { 'ID': 'CONSH', 'CompanyName': 'Consolidated Holdings', 'ContactName': 'Elizabeth Brown', 'ContactTitle': 'Sales Representative', 'Address': 'Berkeley Gardens 12 Brewery', 'City': 'London', 'Region': null, 'PostalCode': 'WX1 6LT', 'Country': 'UK', 'Phone': '(171) 555-2282', 'Fax': '(171) 555-9199' },
+ { 'ID': 'DRACD', 'CompanyName': 'Drachenblut Delikatessen', 'ContactName': 'Sven Ottlieb', 'ContactTitle': 'Order Administrator', 'Address': 'Walserweg 21', 'City': 'Aachen', 'Region': null, 'PostalCode': '52066', 'Country': 'Germany', 'Phone': '0241-039123', 'Fax': '0241-059428' },
+ { 'ID': 'DUMON', 'CompanyName': 'Du monde entier', 'ContactName': 'Janine Labrune', 'ContactTitle': 'Owner', 'Address': '67, rue des Cinquante Otages', 'City': 'Nantes', 'Region': null, 'PostalCode': '44000', 'Country': 'France', 'Phone': '40.67.88.88', 'Fax': '40.67.89.89' },
+ { 'ID': 'EASTC', 'CompanyName': 'Eastern Connection', 'ContactName': 'Ann Devon', 'ContactTitle': 'Sales Agent', 'Address': '35 King George', 'City': 'London', 'Region': null, 'PostalCode': 'WX3 6FW', 'Country': 'UK', 'Phone': '(171) 555-0297', 'Fax': '(171) 555-3373' },
+ { 'ID': 'ERNSH', 'CompanyName': 'Ernst Handel', 'ContactName': 'Roland Mendel', 'ContactTitle': 'Sales Manager', 'Address': 'Kirchgasse 6', 'City': 'Graz', 'Region': null, 'PostalCode': '8010', 'Country': 'Austria', 'Phone': '7675-3425', 'Fax': '7675-3426' },
+ { 'ID': 'FAMIA', 'CompanyName': 'Familia Arquibaldo', 'ContactName': 'Aria Cruz', 'ContactTitle': 'Marketing Assistant', 'Address': 'Rua Orós, 92', 'City': 'Sao Paulo', 'Region': 'SP', 'PostalCode': '05442-030', 'Country': 'Brazil', 'Phone': '(11) 555-9857', 'Fax': null },
+ { 'ID': 'FISSA', 'CompanyName': 'FISSA Fabrica Inter. Salchichas S.A.', 'ContactName': 'Diego Roel', 'ContactTitle': 'Accounting Manager', 'Address': 'C/ Moralzarzal, 86', 'City': 'Madrid', 'Region': null, 'PostalCode': '28034', 'Country': 'Spain', 'Phone': '(91) 555 94 44', 'Fax': '(91) 555 55 93' },
+ { 'ID': 'FOLIG', 'CompanyName': 'Folies gourmandes', 'ContactName': 'Martine Rancé', 'ContactTitle': 'Assistant Sales Agent', 'Address': '184, chaussée de Tournai', 'City': 'Lille', 'Region': null, 'PostalCode': '59000', 'Country': 'France', 'Phone': '20.16.10.16', 'Fax': '20.16.10.17' },
+ { 'ID': 'FOLKO', 'CompanyName': 'Folk och fä HB', 'ContactName': 'Maria Larsson', 'ContactTitle': 'Owner', 'Address': 'Åkergatan 24', 'City': 'Bräcke', 'Region': null, 'PostalCode': 'S-844 67', 'Country': 'Sweden', 'Phone': '0695-34 67 21', 'Fax': null },
+ { 'ID': 'FRANK', 'CompanyName': 'Frankenversand', 'ContactName': 'Peter Franken', 'ContactTitle': 'Marketing Manager', 'Address': 'Berliner Platz 43', 'City': 'München', 'Region': null, 'PostalCode': '80805', 'Country': 'Germany', 'Phone': '089-0877310', 'Fax': '089-0877451' },
+ { 'ID': 'FRANR', 'CompanyName': 'France restauration', 'ContactName': 'Carine Schmitt', 'ContactTitle': 'Marketing Manager', 'Address': '54, rue Royale', 'City': 'Nantes', 'Region': null, 'PostalCode': '44000', 'Country': 'France', 'Phone': '40.32.21.21', 'Fax': '40.32.21.20' },
+ { 'ID': 'FRANS', 'CompanyName': 'Franchi S.p.A.', 'ContactName': 'Paolo Accorti', 'ContactTitle': 'Sales Representative', 'Address': 'Via Monte Bianco 34', 'City': 'Torino', 'Region': null, 'PostalCode': '10100', 'Country': 'Italy', 'Phone': '011-4988260', 'Fax': '011-4988261' }
+ ];
+ // tslint:enable:max-line-length
+ }
+}
+
+@Component({
+ template: `
+
+
+
+
+
+
+
+
+
+`
+})
+class IgxActionStripPinEditComponent extends IgxActionStripTestingComponent {
+}
diff --git a/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-editing-actions.component.ts b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-editing-actions.component.ts
new file mode 100644
index 00000000000..fb44913dfcd
--- /dev/null
+++ b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-editing-actions.component.ts
@@ -0,0 +1,74 @@
+import { Component, HostBinding } from '@angular/core';
+import { IgxGridActionsBaseDirective } from './grid-actions-base.directive';
+
+@Component({
+ selector: 'igx-grid-editing-actions',
+ templateUrl: 'grid-editing-actions.component.html',
+ providers: [{ provide: IgxGridActionsBaseDirective, useExisting: IgxGridEditingActionsComponent }]
+})
+
+export class IgxGridEditingActionsComponent extends IgxGridActionsBaseDirective {
+ /**
+ * Host `class.igx-action-strip` binding.
+ * @hidden
+ * @internal
+ */
+ @HostBinding('class.igx-action-strip__editing-actions')
+ public cssClass = 'igx-action-strip__editing-actions';
+
+ /**
+ * Enter row or cell edit mode depending the grid rowEditable option
+ * @example
+ * ```typescript
+ * this.gridEditingActions.startEdit();
+ * ```
+ */
+ public startEdit(event?): void {
+ if (event) {
+ event.stopPropagation();
+ }
+ if (!this.isRow(this.strip.context)) {
+ return;
+ }
+ const row = this.strip.context;
+ const firstEditable = row.cells.filter(cell => cell.editable)[0];
+ const grid = row.grid;
+ // be sure row is in view
+ if (grid.rowList.filter(r => r === row).length !== 0) {
+ grid.crudService.begin(firstEditable);
+ }
+ this.strip.hide();
+ }
+
+ /**
+ * Delete a row according to the context
+ * @example
+ * ```typescript
+ * this.gridEditingActions.deleteRow();
+ * ```
+ */
+ public deleteRow(event?): void {
+ if (event) {
+ event.stopPropagation();
+ }
+ if (!this.isRow(this.strip.context)) {
+ return;
+ }
+ const context = this.strip.context;
+ const grid = context.grid;
+ grid.deleteRow(context.rowID);
+ this.strip.hide();
+ }
+
+ /**
+ * Getter if the row is disabled
+ * @hidden
+ * @internal
+ */
+ get disabled(): boolean {
+ if (!this.isRow(this.strip.context)) {
+ return;
+ }
+ return this.strip.context.disabled;
+ }
+}
diff --git a/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-pinning-actions.component.html b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-pinning-actions.component.html
new file mode 100644
index 00000000000..1e876aff489
--- /dev/null
+++ b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-pinning-actions.component.html
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-pinning-actions.component.spec.ts b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-pinning-actions.component.spec.ts
new file mode 100644
index 00000000000..72ff9ed1052
--- /dev/null
+++ b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-pinning-actions.component.spec.ts
@@ -0,0 +1,136 @@
+import { Component, ViewChild, OnInit } from '@angular/core';
+import { IgxActionStripComponent } from '../action-strip.component';
+import { configureTestSuite } from '../../test-utils/configure-suite';
+import { TestBed, async } from '@angular/core/testing';
+import { IgxIconModule } from '../../icon';
+import { IgxGridModule, IgxGridComponent } from '../../grids/grid';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { By } from '@angular/platform-browser';
+import { IgxActionStripModule } from '../action-strip.module';
+
+
+describe('igxGridPinningActions #grid ', () => {
+ let fixture;
+ let actionStrip: IgxActionStripComponent;
+ let grid: IgxGridComponent;
+ configureTestSuite();
+ beforeAll(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [
+ IgxActionStripTestingComponent
+ ],
+ imports: [
+ NoopAnimationsModule,
+ IgxActionStripModule,
+ IgxGridModule,
+ IgxIconModule
+ ]
+ }).compileComponents();
+ }));
+ beforeEach(() => {
+ fixture = TestBed.createComponent(IgxActionStripTestingComponent);
+ fixture.detectChanges();
+ actionStrip = fixture.componentInstance.actionStrip;
+ grid = fixture.componentInstance.grid;
+ });
+
+ it('should allow pinning and unpinning rows in a grid', () => {
+ let pinIcon, unpinIcon;
+ actionStrip.show(grid.rowList.first);
+ fixture.detectChanges();
+ pinIcon = fixture.debugElement.query(By.css(`igx-icon[name=pin]`));
+ unpinIcon = fixture.debugElement.query(By.css(`igx-icon[name=unpin]`));
+ expect(unpinIcon).toBeNull();
+ pinIcon.parent.triggerEventHandler('click', new Event('click'));
+ actionStrip.hide();
+ fixture.detectChanges();
+ expect(grid.pinnedRows.length).toBe(1);
+
+ actionStrip.show(grid.pinnedRows[0]);
+ fixture.detectChanges();
+ pinIcon = fixture.debugElement.query(By.css(`igx-icon[name=pin]`));
+ unpinIcon = fixture.debugElement.query(By.css(`igx-icon[name=unpin]`));
+ expect(pinIcon).toBe(null);
+ unpinIcon.parent.triggerEventHandler('click', new Event('click'));
+ actionStrip.hide();
+ fixture.detectChanges();
+ expect(grid.pinnedRows.length).toBe(0);
+ });
+
+ it('should allow navigating to disabled row in unpinned area', () => {
+ pending('implementation');
+ });
+});
+
+@Component({
+ template: `
+
+
+
+
+
+
+
+
+`
+})
+class IgxActionStripTestingComponent implements OnInit {
+ @ViewChild('actionStrip', { read: IgxActionStripComponent, static: true })
+ public actionStrip: IgxActionStripComponent;
+
+ @ViewChild('grid', { read: IgxGridComponent, static: true })
+ public grid: IgxGridComponent;
+
+ data: any[];
+ columns: any[];
+
+ ngOnInit() {
+
+ this.columns = [
+ { field: 'ID', width: '200px', hidden: false },
+ { field: 'CompanyName', width: '200px' },
+ { field: 'ContactName', width: '200px', pinned: false },
+ { field: 'ContactTitle', width: '300px', pinned: false },
+ { field: 'Address', width: '250px' },
+ { field: 'City', width: '200px' },
+ { field: 'Region', width: '300px' },
+ { field: 'PostalCode', width: '150px' },
+ { field: 'Phone', width: '200px' },
+ { field: 'Fax', width: '200px' }
+ ];
+
+ this.data = [
+ // tslint:disable:max-line-length
+ { 'ID': 'ALFKI', 'CompanyName': 'Alfreds Futterkiste', 'ContactName': 'Maria Anders', 'ContactTitle': 'Sales Representative', 'Address': 'Obere Str. 57', 'City': 'Berlin', 'Region': null, 'PostalCode': '12209', 'Country': 'Germany', 'Phone': '030-0074321', 'Fax': '030-0076545' },
+ { 'ID': 'ANATR', 'CompanyName': 'Ana Trujillo Emparedados y helados', 'ContactName': 'Ana Trujillo', 'ContactTitle': 'Owner', 'Address': 'Avda. de la Constitución 2222', 'City': 'México D.F.', 'Region': null, 'PostalCode': '05021', 'Country': 'Mexico', 'Phone': '(5) 555-4729', 'Fax': '(5) 555-3745' },
+ { 'ID': 'ANTON', 'CompanyName': 'Antonio Moreno Taquería', 'ContactName': 'Antonio Moreno', 'ContactTitle': 'Owner', 'Address': 'Mataderos 2312', 'City': 'México D.F.', 'Region': null, 'PostalCode': '05023', 'Country': 'Mexico', 'Phone': '(5) 555-3932', 'Fax': null },
+ { 'ID': 'AROUT', 'CompanyName': 'Around the Horn', 'ContactName': 'Thomas Hardy', 'ContactTitle': 'Sales Representative', 'Address': '120 Hanover Sq.', 'City': 'London', 'Region': null, 'PostalCode': 'WA1 1DP', 'Country': 'UK', 'Phone': '(171) 555-7788', 'Fax': '(171) 555-6750' },
+ { 'ID': 'BERGS', 'CompanyName': 'Berglunds snabbköp', 'ContactName': 'Christina Berglund', 'ContactTitle': 'Order Administrator', 'Address': 'Berguvsvägen 8', 'City': 'Luleå', 'Region': null, 'PostalCode': 'S-958 22', 'Country': 'Sweden', 'Phone': '0921-12 34 65', 'Fax': '0921-12 34 67' },
+ { 'ID': 'BLAUS', 'CompanyName': 'Blauer See Delikatessen', 'ContactName': 'Hanna Moos', 'ContactTitle': 'Sales Representative', 'Address': 'Forsterstr. 57', 'City': 'Mannheim', 'Region': null, 'PostalCode': '68306', 'Country': 'Germany', 'Phone': '0621-08460', 'Fax': '0621-08924' },
+ { 'ID': 'BLONP', 'CompanyName': 'Blondesddsl père et fils', 'ContactName': 'Frédérique Citeaux', 'ContactTitle': 'Marketing Manager', 'Address': '24, place Kléber', 'City': 'Strasbourg', 'Region': null, 'PostalCode': '67000', 'Country': 'France', 'Phone': '88.60.15.31', 'Fax': '88.60.15.32' },
+ { 'ID': 'BOLID', 'CompanyName': 'Bólido Comidas preparadas', 'ContactName': 'Martín Sommer', 'ContactTitle': 'Owner', 'Address': 'C/ Araquil, 67', 'City': 'Madrid', 'Region': null, 'PostalCode': '28023', 'Country': 'Spain', 'Phone': '(91) 555 22 82', 'Fax': '(91) 555 91 99' },
+ { 'ID': 'BONAP', 'CompanyName': 'Bon app\'', 'ContactName': 'Laurence Lebihan', 'ContactTitle': 'Owner', 'Address': '12, rue des Bouchers', 'City': 'Marseille', 'Region': null, 'PostalCode': '13008', 'Country': 'France', 'Phone': '91.24.45.40', 'Fax': '91.24.45.41' },
+ { 'ID': 'BOTTM', 'CompanyName': 'Bottom-Dollar Markets', 'ContactName': 'Elizabeth Lincoln', 'ContactTitle': 'Accounting Manager', 'Address': '23 Tsawassen Blvd.', 'City': 'Tsawassen', 'Region': 'BC', 'PostalCode': 'T2F 8M4', 'Country': 'Canada', 'Phone': '(604) 555-4729', 'Fax': '(604) 555-3745' },
+ { 'ID': 'BSBEV', 'CompanyName': 'B\'s Beverages', 'ContactName': 'Victoria Ashworth', 'ContactTitle': 'Sales Representative', 'Address': 'Fauntleroy Circus', 'City': 'London', 'Region': null, 'PostalCode': 'EC2 5NT', 'Country': 'UK', 'Phone': '(171) 555-1212', 'Fax': null },
+ { 'ID': 'CACTU', 'CompanyName': 'Cactus Comidas para llevar', 'ContactName': 'Patricio Simpson', 'ContactTitle': 'Sales Agent', 'Address': 'Cerrito 333', 'City': 'Buenos Aires', 'Region': null, 'PostalCode': '1010', 'Country': 'Argentina', 'Phone': '(1) 135-5555', 'Fax': '(1) 135-4892' },
+ { 'ID': 'CENTC', 'CompanyName': 'Centro comercial Moctezuma', 'ContactName': 'Francisco Chang', 'ContactTitle': 'Marketing Manager', 'Address': 'Sierras de Granada 9993', 'City': 'México D.F.', 'Region': null, 'PostalCode': '05022', 'Country': 'Mexico', 'Phone': '(5) 555-3392', 'Fax': '(5) 555-7293' },
+ { 'ID': 'CHOPS', 'CompanyName': 'Chop-suey Chinese', 'ContactName': 'Yang Wang', 'ContactTitle': 'Owner', 'Address': 'Hauptstr. 29', 'City': 'Bern', 'Region': null, 'PostalCode': '3012', 'Country': 'Switzerland', 'Phone': '0452-076545', 'Fax': null },
+ { 'ID': 'COMMI', 'CompanyName': 'Comércio Mineiro', 'ContactName': 'Pedro Afonso', 'ContactTitle': 'Sales Associate', 'Address': 'Av. dos Lusíadas, 23', 'City': 'Sao Paulo', 'Region': 'SP', 'PostalCode': '05432-043', 'Country': 'Brazil', 'Phone': '(11) 555-7647', 'Fax': null },
+ { 'ID': 'CONSH', 'CompanyName': 'Consolidated Holdings', 'ContactName': 'Elizabeth Brown', 'ContactTitle': 'Sales Representative', 'Address': 'Berkeley Gardens 12 Brewery', 'City': 'London', 'Region': null, 'PostalCode': 'WX1 6LT', 'Country': 'UK', 'Phone': '(171) 555-2282', 'Fax': '(171) 555-9199' },
+ { 'ID': 'DRACD', 'CompanyName': 'Drachenblut Delikatessen', 'ContactName': 'Sven Ottlieb', 'ContactTitle': 'Order Administrator', 'Address': 'Walserweg 21', 'City': 'Aachen', 'Region': null, 'PostalCode': '52066', 'Country': 'Germany', 'Phone': '0241-039123', 'Fax': '0241-059428' },
+ { 'ID': 'DUMON', 'CompanyName': 'Du monde entier', 'ContactName': 'Janine Labrune', 'ContactTitle': 'Owner', 'Address': '67, rue des Cinquante Otages', 'City': 'Nantes', 'Region': null, 'PostalCode': '44000', 'Country': 'France', 'Phone': '40.67.88.88', 'Fax': '40.67.89.89' },
+ { 'ID': 'EASTC', 'CompanyName': 'Eastern Connection', 'ContactName': 'Ann Devon', 'ContactTitle': 'Sales Agent', 'Address': '35 King George', 'City': 'London', 'Region': null, 'PostalCode': 'WX3 6FW', 'Country': 'UK', 'Phone': '(171) 555-0297', 'Fax': '(171) 555-3373' },
+ { 'ID': 'ERNSH', 'CompanyName': 'Ernst Handel', 'ContactName': 'Roland Mendel', 'ContactTitle': 'Sales Manager', 'Address': 'Kirchgasse 6', 'City': 'Graz', 'Region': null, 'PostalCode': '8010', 'Country': 'Austria', 'Phone': '7675-3425', 'Fax': '7675-3426' },
+ { 'ID': 'FAMIA', 'CompanyName': 'Familia Arquibaldo', 'ContactName': 'Aria Cruz', 'ContactTitle': 'Marketing Assistant', 'Address': 'Rua Orós, 92', 'City': 'Sao Paulo', 'Region': 'SP', 'PostalCode': '05442-030', 'Country': 'Brazil', 'Phone': '(11) 555-9857', 'Fax': null },
+ { 'ID': 'FISSA', 'CompanyName': 'FISSA Fabrica Inter. Salchichas S.A.', 'ContactName': 'Diego Roel', 'ContactTitle': 'Accounting Manager', 'Address': 'C/ Moralzarzal, 86', 'City': 'Madrid', 'Region': null, 'PostalCode': '28034', 'Country': 'Spain', 'Phone': '(91) 555 94 44', 'Fax': '(91) 555 55 93' },
+ { 'ID': 'FOLIG', 'CompanyName': 'Folies gourmandes', 'ContactName': 'Martine Rancé', 'ContactTitle': 'Assistant Sales Agent', 'Address': '184, chaussée de Tournai', 'City': 'Lille', 'Region': null, 'PostalCode': '59000', 'Country': 'France', 'Phone': '20.16.10.16', 'Fax': '20.16.10.17' },
+ { 'ID': 'FOLKO', 'CompanyName': 'Folk och fä HB', 'ContactName': 'Maria Larsson', 'ContactTitle': 'Owner', 'Address': 'Åkergatan 24', 'City': 'Bräcke', 'Region': null, 'PostalCode': 'S-844 67', 'Country': 'Sweden', 'Phone': '0695-34 67 21', 'Fax': null },
+ { 'ID': 'FRANK', 'CompanyName': 'Frankenversand', 'ContactName': 'Peter Franken', 'ContactTitle': 'Marketing Manager', 'Address': 'Berliner Platz 43', 'City': 'München', 'Region': null, 'PostalCode': '80805', 'Country': 'Germany', 'Phone': '089-0877310', 'Fax': '089-0877451' },
+ { 'ID': 'FRANR', 'CompanyName': 'France restauration', 'ContactName': 'Carine Schmitt', 'ContactTitle': 'Marketing Manager', 'Address': '54, rue Royale', 'City': 'Nantes', 'Region': null, 'PostalCode': '44000', 'Country': 'France', 'Phone': '40.32.21.21', 'Fax': '40.32.21.20' },
+ { 'ID': 'FRANS', 'CompanyName': 'Franchi S.p.A.', 'ContactName': 'Paolo Accorti', 'ContactTitle': 'Sales Representative', 'Address': 'Via Monte Bianco 34', 'City': 'Torino', 'Region': null, 'PostalCode': '10100', 'Country': 'Italy', 'Phone': '011-4988260', 'Fax': '011-4988261' }
+ ];
+ // tslint:enable:max-line-length
+ }
+}
diff --git a/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-pinning-actions.component.ts b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-pinning-actions.component.ts
new file mode 100644
index 00000000000..fd439018c52
--- /dev/null
+++ b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-pinning-actions.component.ts
@@ -0,0 +1,88 @@
+import { Component, HostBinding } from '@angular/core';
+import { IgxGridActionsBaseDirective } from './grid-actions-base.directive';
+
+@Component({
+ selector: 'igx-grid-pinning-actions',
+ templateUrl: 'grid-pinning-actions.component.html',
+ providers: [{ provide: IgxGridActionsBaseDirective, useExisting: IgxGridPinningActionsComponent }]
+})
+
+export class IgxGridPinningActionsComponent extends IgxGridActionsBaseDirective {
+ /**
+ * Host `class.igx-action-strip` binding.
+ * @hidden
+ * @internal
+ */
+ @HostBinding('class.igx-action-strip__pining-actions')
+ public cssClass = 'igx-action-strip__pining-actions';
+
+ private iconsRendered = false;
+
+ /**
+ * Getter to know if the row is pinned
+ * @hidden
+ * @internal
+ */
+ get pinned(): boolean {
+ if (!this.isRow(this.strip.context)) {
+ return;
+ }
+ const context = this.strip.context;
+ if (context && !this.iconsRendered) {
+ this.renderIcons();
+ this.iconsRendered = true;
+ }
+ return context && context.pinned;
+ }
+
+ /**
+ * Pin the row according to the context.
+ * @example
+ * ```typescript
+ * this.gridPinningActions.pin();
+ * ```
+ */
+ public pin(event?): void {
+ if (event) {
+ event.stopPropagation();
+ }
+ if (!this.isRow(this.strip.context)) {
+ return;
+ }
+ const row = this.strip.context;
+ const grid = row.grid;
+ grid.pinRow(row.rowID);
+ this.strip.hide();
+ }
+
+ /**
+ * Unpin the row according to the context.
+ * @example
+ * ```typescript
+ * this.gridPinningActions.unpin();
+ * ```
+ */
+ public unpin(event?): void {
+ if (event) {
+ event.stopPropagation();
+ }
+ if (!this.isRow(this.strip.context)) {
+ return;
+ }
+ const row = this.strip.context;
+ const grid = row.grid;
+ grid.unpinRow(row.rowID);
+ this.strip.hide();
+ }
+
+ private renderIcons(): void {
+ if (!this.isRow(this.strip.context)) {
+ return;
+ }
+ const context = this.strip.context;
+ const grid = context.grid;
+ if (grid) {
+ grid.filteringService.registerSVGIcons();
+ }
+ }
+}
diff --git a/projects/igniteui-angular/src/lib/action-strip/index.ts b/projects/igniteui-angular/src/lib/action-strip/index.ts
new file mode 100644
index 00000000000..34ddbdee7b1
--- /dev/null
+++ b/projects/igniteui-angular/src/lib/action-strip/index.ts
@@ -0,0 +1,5 @@
+export { IgxGridActionsBaseDirective } from './grid-actions/grid-actions-base.directive';
+export { IgxGridEditingActionsComponent } from './grid-actions/grid-editing-actions.component';
+export { IgxGridPinningActionsComponent } from './grid-actions/grid-pinning-actions.component';
+export { IgxActionStripComponent } from './action-strip.component';
+export * from './action-strip.module';
diff --git a/projects/igniteui-angular/src/lib/core/styles/components/action-strip/_action-strip-component.scss b/projects/igniteui-angular/src/lib/core/styles/components/action-strip/_action-strip-component.scss
new file mode 100644
index 00000000000..cfb6f14bb5c
--- /dev/null
+++ b/projects/igniteui-angular/src/lib/core/styles/components/action-strip/_action-strip-component.scss
@@ -0,0 +1,38 @@
+////
+/// @group components
+/// @author Simeon Simeonoff
+/// @requires {mixin} bem-block
+/// @requires {mixin} bem-elem
+/// @requires {mixin} bem-mod
+////
+@include b(igx-action-strip) {
+ // Register the component in the component registry
+ $this: bem--selector-to-string(&);
+ @include register-component(str-slice($this, 2, -1));
+
+ @extend %igx-action-strip-display !optional;
+
+ @include m(cosy) {
+ @extend %igx-action-strip--cosy !optional;
+ }
+
+ @include m(compact) {
+ @extend %igx-action-strip--compact !optional;
+ }
+
+ @include e(actions) {
+ @extend %igx-action-strip__actions !optional;
+ }
+
+ @include e(delete) {
+ @extend %igx-action-strip__delete !optional;
+ }
+
+ @include e(editing-actions) {
+ @extend %igx-action-strip__editing-actions !optional;
+ }
+
+ @include e(pining-actions) {
+ @extend %igx-action-strip__pining-actions !optional;
+ }
+}
diff --git a/projects/igniteui-angular/src/lib/core/styles/components/action-strip/_action-strip-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/action-strip/_action-strip-theme.scss
new file mode 100644
index 00000000000..d3e1e030196
--- /dev/null
+++ b/projects/igniteui-angular/src/lib/core/styles/components/action-strip/_action-strip-theme.scss
@@ -0,0 +1,172 @@
+////
+/// @group themes
+/// @access public
+/// @author Simeon Simeonoff
+/// @author Marin Popov
+////
+///
+/// If only background color is specified, text/icon color will be assigned automatically to a contrasting color.
+/// @param {Map} $palette [$default-palette] - The palette used as basis for styling the component.
+/// @param {Map} $schema [$light-schema] - The schema used as basis for styling the component.
+///
+/// @param {Color} $color [null] - The color used for the actions icons.
+/// @param {Color} $background [null] - The color used for the action strip component content background.
+/// @param {Color} $actions-background [null] - The color used for the actions background.
+/// @param {Color} $delete-action [null] - The color used for the delete icon in action strip component.
+/// @param {actions-border-radius} $actions-border-radius [null] - The border radius used for actions container inside action strip component.
+///
+/// @requires extend
+/// @requires round-borders
+/// @requires apply-palette
+/// @requires text-contrast
+///
+/// @example scss Change the background and icon colors in action strip
+/// $my-action-strip-theme: igx-action-strip-theme($background: black);
+/// // Pass the theme to the igx-action-strip component mixin
+/// @include igx-action-strip($my-action-strip-theme);
+@function igx-action-strip-theme(
+ $palette: $default-palette,
+ $schema: $light-schema,
+
+ $background: null,
+ $actions-background: null,
+ $color: null,
+ $delete-action: null,
+ $actions-border-radius: null,
+) {
+ $name: 'igx-action-strip';
+ $action-strip-schema: ();
+
+ @if map-has-key($schema, $name) {
+ $action-strip-schema: map-get($schema, $name);
+ } @else {
+ $action-strip-schema: $schema;
+ }
+
+ $theme: apply-palette($action-strip-schema, $palette);
+
+ $actions-border-radius: round-borders(
+ if($actions-border-radius, $actions-border-radius, map-get($action-strip-schema, 'actions-border-radius')), 0, 24px
+ );
+
+ @if not($color) and $actions-background {
+ $color: text-contrast($actions-background);
+ }
+
+ @return extend($theme, (
+ name: $name,
+ palette: $palette,
+ background: $background,
+ actions-background: $actions-background,
+ color: $color,
+ delete-action: $delete-action,
+ actions-border-radius: $actions-border-radius,
+ ));
+}
+
+/// @param {Map} $theme - The theme used to style the component.
+/// @requires {mixin} igx-root-css-vars
+/// @requires rem
+/// @requires --var
+@mixin igx-action-strip($theme) {
+ @include igx-root-css-vars($theme);
+
+ $padding: (
+ comfortable: 0 rem(24px),
+ cosy: 0 rem(16px),
+ compact: 0 rem(12px)
+ );
+
+ $left: if-ltr(left, right);
+ $right: if-ltr(right, left);
+
+ %igx-action-strip-display {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+ top: 0;
+ #{$left}: 0;
+ background: --var($theme, 'background');
+ color: inherit;
+ padding: map-get($padding, 'comfortable');
+ z-index: 9999;
+ }
+
+ %action-icons-density {
+ [igxButton='icon'] {
+ width: rem(28px);
+ height: rem(28px);
+
+ igx-icon {
+ width: rem(14px);
+ height: rem(14px);
+ font-size: rem(14px);
+ }
+ }
+ }
+
+ %igx-action-strip--cosy{
+ padding: map-get($padding, 'cosy');
+ @extend %action-icons-density;
+ }
+
+ %igx-action-strip--compact{
+ padding: map-get($padding, 'compact');
+ @extend %action-icons-density;
+ }
+
+ %igx-action-strip__editing-actions,
+ %igx-action-strip__pining-actions {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ %igx-action-strip__actions {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ pointer-events: all;
+ position: relative;
+ color: --var($theme, 'color');
+ border-radius: --var($theme, 'actions-border-radius');
+ background: --var($theme, 'actions-background');
+ max-height: 36px;
+
+ &:last-child {
+ margin-#{$right}: 0;
+ }
+
+ igx-icon {
+ color: --var($theme, 'color');
+ }
+ }
+
+ %igx-action-strip__pining-actions {
+ margin-#{$right}: rem(4px);
+
+ &:last-child {
+ margin-#{$right}: 0;
+ }
+ }
+
+ %igx-action-strip__editing-actions {
+ > [igxButton] {
+ margin-#{$left}: rem(4px);
+
+ &:first-of-type {
+ margin-#{$left}: 0;
+ }
+ }
+ }
+
+ %igx-action-strip__delete {
+ igx-icon {
+ color: --var($theme, 'delete-action');
+ }
+ }
+}
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 8e335642c48..08dbbda9a39 100644
--- a/projects/igniteui-angular/src/lib/core/styles/themes/_core.scss
+++ b/projects/igniteui-angular/src/lib/core/styles/themes/_core.scss
@@ -20,6 +20,7 @@
@import '../components/ripple/ripple-component';
// Component composition styles
+@import '../components/action-strip/action-strip-component';
@import '../components/avatar/avatar-component';
@import '../components/badge/badge-component';
@import '../components/bottom-nav/bottom-nav-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 bdacac534b4..c241bf2a1ea 100644
--- a/projects/igniteui-angular/src/lib/core/styles/themes/_index.scss
+++ b/projects/igniteui-angular/src/lib/core/styles/themes/_index.scss
@@ -7,6 +7,7 @@
@import 'core';
// Import all component mixins
+@import '../components/action-strip/action-strip-theme';
@import '../components/avatar/avatar-theme';
@import '../components/badge/badge-theme';
@import '../components/bottom-nav/bottom-nav-theme';
@@ -119,6 +120,10 @@
@include igx-avatar(igx-avatar-theme($palette, $schema));
}
+ @if not(index($exclude, 'igx-action-strip')) {
+ @include igx-action-strip(igx-action-strip-theme($palette, $schema));
+ }
+
@if not(index($exclude, 'igx-badge')) {
@include igx-badge(igx-badge-theme(
$palette,
diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_action-strip.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_action-strip.scss
new file mode 100644
index 00000000000..8e1aa29efba
--- /dev/null
+++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_action-strip.scss
@@ -0,0 +1,46 @@
+@import '../light/action-strip';
+////
+/// @group schemas
+/// @access private
+/// @author Marin Popov
+////
+///
+/// Generates a dark action-strip schema.
+/// @type {Map}
+/// @property {Map} actions-background [igx-color: ('grays', 200), hexrgba: #000, rgba: .8]- actions container background.
+/// @see $default-palette
+$_dark-action-strip: extend(
+ $_light-action-strip,
+ (
+ variant: 'material',
+
+ actions-background: (
+ igx-color: ('grays', 200),
+ hexrgba: #222,
+ rgba: .8
+ ),
+ )
+);
+
+/// Generates a dark fluent action strip schema.
+/// @type {Map}
+/// @requires {function} extend
+/// @requires $_dark-action-strip
+$_dark-fluent-action-strip: extend(
+ $_dark-action-strip,
+ (
+ variant: 'fluent',
+ )
+);
+
+/// Generates a dark bootstrap action strip schema.
+/// @type {Map}
+/// @requires {function} extend
+/// @requires $_dark-action-strip
+$_dark-bootstrap-action-strip: extend(
+ $_dark-action-strip,
+ (
+ variant: 'bootstrap',
+ )
+);
+
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 a16012b71f8..4fecf244869 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
@@ -3,6 +3,7 @@
/// @access public
/// @author Simeon Simeonoff
////
+@import './action-strip';
@import './avatar';
@import './badge';
@import './banner';
@@ -91,6 +92,7 @@
/// @property {Map} igx-tooltip [$_dark-tooltip]
$dark-schema: (
igx-avatar: $_dark-avatar,
+ igx-action-strip: $_dark-action-strip,
igx-badge: $_dark-badge,
igx-banner: $_dark-banner,
igx-bottom-nav: $_dark-bottom-nav,
@@ -180,6 +182,7 @@ $dark-schema: (
/// @property {map} igx-tooltip [$_dark-fluent-tooltip]
$dark-fluent-schema: (
igx-avatar: $_dark-fluent-avatar,
+ igx-action-strip: $_dark-fluent-action-strip,
igx-badge: $_dark-fluent-badge,
igx-banner: $_dark-fluent-banner,
igx-bottom-nav: $_dark-fluent-bottom-nav,
@@ -269,6 +272,7 @@ $dark-fluent-schema: (
/// @property {map} igx-tooltip [$_dark-bootstrap-tooltip]
$dark-bootstrap-schema: (
igx-avatar: $_dark-bootstrap-avatar,
+ igx-action-strip: $_dark-bootstrap-action-strip,
igx-badge: $_dark-bootstrap-badge,
igx-banner: $_dark-bootstrap-banner,
igx-bottom-nav: $_dark-bootstrap-bottom-nav,
diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_action-strip.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_action-strip.scss
new file mode 100644
index 00000000000..aa07a47a20f
--- /dev/null
+++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_action-strip.scss
@@ -0,0 +1,64 @@
+@import '../shape/action-strip';
+////
+/// @group schemas
+/// @access private
+/// @author Marin Popov
+////
+///
+/// Generates a light action-strip schema.
+/// @type {Map}
+/// @prop {Color} $color [currentColor] - The color used for the actions icons.
+/// @prop {Map} background [igx-color: ('grays', 100] - The color used for the action strip component content background.
+/// @prop {Map} actions-background [igx-color: ('grays', 200), hexrgba: #fff, rgba: .9] - The color used for actions background.
+/// @prop {Map} delete-action [igx-color: ('error')] - The color used for the delete icon in action strip component.
+/// @prop {Number} border-radius [1] - The border radius fraction, between 0-1 to be used for action strip actions container.
+/// @see $default-palette
+$_light-action-strip: extend(
+ $_default-shape-action-strip,
+ (
+ variant: 'material',
+
+ actions-background: (
+ igx-color: ('grays', 200),
+ hexrgba: #fff,
+ rgba: .9
+ ),
+
+ background: (
+ igx-color: ('grays', 100)
+ ),
+
+ color: currentColor,
+
+ delete-action: (
+ igx-color: ('error')
+ ),
+ )
+);
+
+/// Generates a fluent action strip schema.
+/// @type {Map}
+/// @prop {Number} border-radius [0] - The border radius fraction, between 0-1 to be used for action strip actions container..
+/// @requires {function} extend
+/// @requires $_light-action-strip
+$_fluent-action-strip: extend(
+ $_light-action-strip,
+ $_fluent-shape-action-strip,
+ (
+ variant: 'fluent',
+ )
+);
+
+/// Generates a bootstrap action strip schema.
+/// @type {Map}
+/// @prop {Number} border-radius [4px] - The border radius fraction, between 0-1 to be used for action strip actions container.
+/// @requires {function} extend
+/// @requires $_light-action-strip
+$_bootstrap-action-strip: extend(
+ $_light-action-strip,
+ $_bootstrap-shape-action-strip,
+ (
+ variant: 'bootstrap',
+ )
+);
+
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 4f67c8e036e..f1268d367e6 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
@@ -5,6 +5,7 @@
////
@import './avatar';
+@import './action-strip';
@import './badge';
@import './banner';
@import './bottom-nav';
@@ -49,6 +50,7 @@
/// The default light schema for all components.
/// @type {Map}
/// @property {Map} igx-avatar [$_light-avatar]
+/// @property {Map} igx-action-strip [$_light-action-strip]
/// @property {Map} igx-badge [$_light-badge]
/// @property {Map} igx-banner [$_light-banner]
/// @property {Map} igx-bottom-nav [$_light-bottom-nav]
@@ -92,6 +94,7 @@
/// @property {Map} igx-tooltip [$_light-tooltip]
$light-schema: (
igx-avatar: $_light-avatar,
+ igx-action-strip: $_light-action-strip,
igx-badge: $_light-badge,
igx-banner: $_light-banner,
igx-bottom-nav: $_light-bottom-nav,
@@ -137,6 +140,7 @@ $light-schema: (
$light-fluent-schema: (
igx-avatar: $_fluent-avatar,
+ igx-action-strip: $_fluent-action-strip,
igx-badge: $_fluent-badge,
igx-banner: $_fluent-banner,
igx-bottom-nav: $_fluent-bottom-nav,
@@ -182,6 +186,7 @@ $light-fluent-schema: (
$light-bootstrap-schema: (
igx-avatar: $_bootstrap-avatar,
+ igx-action-strip: $_bootstrap-action-strip,
igx-badge: $_bootstrap-badge,
igx-banner: $_bootstrap-banner,
igx-bottom-nav: $_bootstrap-bottom-nav,
diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/round-light/_index.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/round-light/_index.scss
index 216666d5f84..86aed45de2e 100644
--- a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/round-light/_index.scss
+++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/round-light/_index.scss
@@ -4,6 +4,7 @@
/// @author Simeon Simeonoff
////
+@import '../light/action-strip';
@import '../light/avatar';
@import '../light/badge';
@import '../light/banner';
@@ -46,6 +47,7 @@
/// The default light schema for all components.
/// @type {Map}
+/// @property {Map} igx-action-strip [$_light-action-strip]
/// @property {Map} igx-avatar [$_light-avatar]
/// @property {Map} igx-badge [$_light-badge]
/// @property {Map} igx-banner [$_light-banner]
@@ -88,6 +90,7 @@
/// @property {Map} igx-tooltip [$_light-tooltip]
$light-round-schema: (
+ igx-action-strip: extend($_light-action-strip, $_round-shape-avatar),
igx-avatar: extend($_light-avatar, $_round-shape-avatar),
igx-badge: extend($_light-badge, $_round-shape-badge),
igx-banner: extend($_light-banner, $_round-shape-banner),
diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/shape/_action-strip.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/shape/_action-strip.scss
new file mode 100644
index 00000000000..82ffddf2187
--- /dev/null
+++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/shape/_action-strip.scss
@@ -0,0 +1,28 @@
+////
+/// @group schemas
+/// @access private
+/// @author Marin Popov
+////
+$_default-shape-action-strip: (
+ actions-border-radius: 1
+);
+
+/// @type Map
+$_round-shape-action-strip: (
+ actions-border-radius: 1
+);
+
+/// @type Map
+$_square-shape-action-strip: (
+ actions-border-radius: 0
+);
+
+/// @type Map
+$_fluent-shape-action-strip: (
+ actions-border-radius: 1
+);
+
+/// @type Map
+$_bootstrap-shape-action-strip: (
+ actions-border-radius: 4px
+);
diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/square-light/_index.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/square-light/_index.scss
index 52bfc490d58..6d092fed57d 100644
--- a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/square-light/_index.scss
+++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/square-light/_index.scss
@@ -4,6 +4,7 @@
/// @author Simeon Simeonoff
////
+@import '../light/action-strip';
@import '../light/avatar';
@import '../light/badge';
@import '../light/banner';
@@ -46,6 +47,7 @@
/// The default light schema for all components.
/// @type {Map}
+/// @property {Map} igx-action-strip [$_light-action-strip]
/// @property {Map} igx-avatar [$_light-avatar]
/// @property {Map} igx-badge [$_light-badge]
/// @property {Map} igx-banner [$_light-banner]
@@ -87,6 +89,7 @@
/// @property {Map} igx-toast [$_light-toast]
/// @property {Map} igx-tooltip [$_light-tooltip]
$light-square-schema: (
+ igx-action-strip: extend($_light-action-strip, $_square-shape-action-strip),
igx-avatar: extend($_light-avatar, $_square-shape-avatar),
igx-badge: extend($_light-badge, $_square-shape-badge),
igx-banner: extend($_light-banner, $_square-shape-banner),
diff --git a/projects/igniteui-angular/src/public_api.ts b/projects/igniteui-angular/src/public_api.ts
index 3b8919b4596..7adf85086ba 100644
--- a/projects/igniteui-angular/src/public_api.ts
+++ b/projects/igniteui-angular/src/public_api.ts
@@ -52,6 +52,7 @@ export * from './lib/data-operations/data-util';
/**
* Components
*/
+export * from './lib/action-strip/index';
export * from './lib/avatar/avatar.component';
export * from './lib/badge/badge.component';
export * from './lib/banner/banner.component';
diff --git a/src/app/action-strip/action-strip.sample.html b/src/app/action-strip/action-strip.sample.html
new file mode 100644
index 00000000000..d6ae725ffea
--- /dev/null
+++ b/src/app/action-strip/action-strip.sample.html
@@ -0,0 +1,93 @@
+
+
+ The Action Strip provide templatable area for one or more actions.
+
+
+
+
+
Display Density
+ Compact
+ Cosy
+ Comfortable
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+ sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+
+ alarm
+
+
+
+
+
+
+
+
+
Grid Pinning Action
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Grid Pinning and Editing Actions
+
+
+
+
+ {{val}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Actions in menu
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/action-strip/action-strip.sample.scss b/src/app/action-strip/action-strip.sample.scss
new file mode 100644
index 00000000000..8c29db4e7fd
--- /dev/null
+++ b/src/app/action-strip/action-strip.sample.scss
@@ -0,0 +1,31 @@
+.parent {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 16px;
+ width: 400px;
+ height: 200px;
+ background-color: #f9f9f9;
+ position: relative;
+}
+
+.my-action-strip {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+ backdrop-filter: blur(2px);
+}
+
+.cell-template {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ width:100%;
+ height: 100%;
+}
+
+h5 {
+ margin-bottom: 10px;
+}
diff --git a/src/app/action-strip/action-strip.sample.ts b/src/app/action-strip/action-strip.sample.ts
new file mode 100644
index 00000000000..c081f4e482b
--- /dev/null
+++ b/src/app/action-strip/action-strip.sample.ts
@@ -0,0 +1,100 @@
+import {Component, ViewChild} from '@angular/core';
+import {IgxActionStripComponent, IgxGridComponent, DisplayDensity} from 'igniteui-angular';
+
+@Component({
+ selector: 'app-action-strip-sample',
+ styleUrls: ['action-strip.sample.scss'],
+ templateUrl: `action-strip.sample.html`
+})
+export class ActionStripSampleComponent {
+ @ViewChild('actionstrip') actionStrip: IgxActionStripComponent;
+ @ViewChild('actionstrip1') actionStrip1: IgxActionStripComponent;
+ @ViewChild('grid1', { static: true }) grid1: IgxGridComponent;
+ public result: string;
+ public isVisible = false;
+ private counter = 0;
+ public comfortable = DisplayDensity.comfortable;
+ public cosy = DisplayDensity.cosy;
+ public compact = DisplayDensity.compact;
+ public displayDensity = this.comfortable;
+
+ doSomeAction() {
+ this.result = `Clicked ${this.counter++} times`;
+ }
+
+ showActions() {
+ this.isVisible = true;
+ }
+
+ hideActions() {
+ this.isVisible = false;
+ }
+
+ onMouseOver(event, grid, actionStrip) {
+ if (event.target.nodeName.toLowerCase() === "igx-grid-cell") {
+ const rowIndex = parseInt(event.target.attributes["data-rowindex"].value, 10);
+ const row = grid.getRowByIndex(rowIndex);
+ actionStrip.show(row);
+ }
+ }
+
+ onMouseLeave(actionstrip, event?) {
+ if (!event || event.relatedTarget.nodeName.toLowerCase() !== "igx-drop-down-item") {
+ actionstrip.hide();
+ }
+ }
+
+ setDensity(density: DisplayDensity) {
+ this.displayDensity = density;
+ }
+
+ data: any[];
+ columns: any[];
+
+ ngOnInit(): void {
+ this.columns = [
+ { field: 'ID', width: '200px', hidden: false },
+ { field: 'CompanyName', width: '200px' },
+ { field: 'ContactName', width: '200px', pinned: false },
+ { field: 'ContactTitle', width: '300px', pinned: false },
+ { field: 'Address', width: '250px' },
+ { field: 'City', width: '200px' },
+ { field: 'Region', width: '300px' },
+ { field: 'PostalCode', width: '150px' },
+ { field: 'Phone', width: '200px' },
+ { field: 'Fax', width: '200px' }
+ ];
+
+ this.data = [
+ // tslint:disable:max-line-length
+ { 'ID': 'ALFKI', 'CompanyName': 'Alfreds Futterkiste', 'ContactName': 'Maria Anders', 'ContactTitle': 'Sales Representative', 'Address': 'Obere Str. 57', 'City': 'Berlin', 'Region': null, 'PostalCode': '12209', 'Country': 'Germany', 'Phone': '030-0074321', 'Fax': '030-0076545' },
+ { 'ID': 'ANATR', 'CompanyName': 'Ana Trujillo Emparedados y helados', 'ContactName': 'Ana Trujillo', 'ContactTitle': 'Owner', 'Address': 'Avda. de la Constitución 2222', 'City': 'México D.F.', 'Region': null, 'PostalCode': '05021', 'Country': 'Mexico', 'Phone': '(5) 555-4729', 'Fax': '(5) 555-3745' },
+ { 'ID': 'ANTON', 'CompanyName': 'Antonio Moreno Taquería', 'ContactName': 'Antonio Moreno', 'ContactTitle': 'Owner', 'Address': 'Mataderos 2312', 'City': 'México D.F.', 'Region': null, 'PostalCode': '05023', 'Country': 'Mexico', 'Phone': '(5) 555-3932', 'Fax': null },
+ { 'ID': 'AROUT', 'CompanyName': 'Around the Horn', 'ContactName': 'Thomas Hardy', 'ContactTitle': 'Sales Representative', 'Address': '120 Hanover Sq.', 'City': 'London', 'Region': null, 'PostalCode': 'WA1 1DP', 'Country': 'UK', 'Phone': '(171) 555-7788', 'Fax': '(171) 555-6750' },
+ { 'ID': 'BERGS', 'CompanyName': 'Berglunds snabbköp', 'ContactName': 'Christina Berglund', 'ContactTitle': 'Order Administrator', 'Address': 'Berguvsvägen 8', 'City': 'Luleå', 'Region': null, 'PostalCode': 'S-958 22', 'Country': 'Sweden', 'Phone': '0921-12 34 65', 'Fax': '0921-12 34 67' },
+ { 'ID': 'BLAUS', 'CompanyName': 'Blauer See Delikatessen', 'ContactName': 'Hanna Moos', 'ContactTitle': 'Sales Representative', 'Address': 'Forsterstr. 57', 'City': 'Mannheim', 'Region': null, 'PostalCode': '68306', 'Country': 'Germany', 'Phone': '0621-08460', 'Fax': '0621-08924' },
+ { 'ID': 'BLONP', 'CompanyName': 'Blondesddsl père et fils', 'ContactName': 'Frédérique Citeaux', 'ContactTitle': 'Marketing Manager', 'Address': '24, place Kléber', 'City': 'Strasbourg', 'Region': null, 'PostalCode': '67000', 'Country': 'France', 'Phone': '88.60.15.31', 'Fax': '88.60.15.32' },
+ { 'ID': 'BOLID', 'CompanyName': 'Bólido Comidas preparadas', 'ContactName': 'Martín Sommer', 'ContactTitle': 'Owner', 'Address': 'C/ Araquil, 67', 'City': 'Madrid', 'Region': null, 'PostalCode': '28023', 'Country': 'Spain', 'Phone': '(91) 555 22 82', 'Fax': '(91) 555 91 99' },
+ { 'ID': 'BONAP', 'CompanyName': 'Bon app\'', 'ContactName': 'Laurence Lebihan', 'ContactTitle': 'Owner', 'Address': '12, rue des Bouchers', 'City': 'Marseille', 'Region': null, 'PostalCode': '13008', 'Country': 'France', 'Phone': '91.24.45.40', 'Fax': '91.24.45.41' },
+ { 'ID': 'BOTTM', 'CompanyName': 'Bottom-Dollar Markets', 'ContactName': 'Elizabeth Lincoln', 'ContactTitle': 'Accounting Manager', 'Address': '23 Tsawassen Blvd.', 'City': 'Tsawassen', 'Region': 'BC', 'PostalCode': 'T2F 8M4', 'Country': 'Canada', 'Phone': '(604) 555-4729', 'Fax': '(604) 555-3745' },
+ { 'ID': 'BSBEV', 'CompanyName': 'B\'s Beverages', 'ContactName': 'Victoria Ashworth', 'ContactTitle': 'Sales Representative', 'Address': 'Fauntleroy Circus', 'City': 'London', 'Region': null, 'PostalCode': 'EC2 5NT', 'Country': 'UK', 'Phone': '(171) 555-1212', 'Fax': null },
+ { 'ID': 'CACTU', 'CompanyName': 'Cactus Comidas para llevar', 'ContactName': 'Patricio Simpson', 'ContactTitle': 'Sales Agent', 'Address': 'Cerrito 333', 'City': 'Buenos Aires', 'Region': null, 'PostalCode': '1010', 'Country': 'Argentina', 'Phone': '(1) 135-5555', 'Fax': '(1) 135-4892' },
+ { 'ID': 'CENTC', 'CompanyName': 'Centro comercial Moctezuma', 'ContactName': 'Francisco Chang', 'ContactTitle': 'Marketing Manager', 'Address': 'Sierras de Granada 9993', 'City': 'México D.F.', 'Region': null, 'PostalCode': '05022', 'Country': 'Mexico', 'Phone': '(5) 555-3392', 'Fax': '(5) 555-7293' },
+ { 'ID': 'CHOPS', 'CompanyName': 'Chop-suey Chinese', 'ContactName': 'Yang Wang', 'ContactTitle': 'Owner', 'Address': 'Hauptstr. 29', 'City': 'Bern', 'Region': null, 'PostalCode': '3012', 'Country': 'Switzerland', 'Phone': '0452-076545', 'Fax': null },
+ { 'ID': 'COMMI', 'CompanyName': 'Comércio Mineiro', 'ContactName': 'Pedro Afonso', 'ContactTitle': 'Sales Associate', 'Address': 'Av. dos Lusíadas, 23', 'City': 'Sao Paulo', 'Region': 'SP', 'PostalCode': '05432-043', 'Country': 'Brazil', 'Phone': '(11) 555-7647', 'Fax': null },
+ { 'ID': 'CONSH', 'CompanyName': 'Consolidated Holdings', 'ContactName': 'Elizabeth Brown', 'ContactTitle': 'Sales Representative', 'Address': 'Berkeley Gardens 12 Brewery', 'City': 'London', 'Region': null, 'PostalCode': 'WX1 6LT', 'Country': 'UK', 'Phone': '(171) 555-2282', 'Fax': '(171) 555-9199' },
+ { 'ID': 'DRACD', 'CompanyName': 'Drachenblut Delikatessen', 'ContactName': 'Sven Ottlieb', 'ContactTitle': 'Order Administrator', 'Address': 'Walserweg 21', 'City': 'Aachen', 'Region': null, 'PostalCode': '52066', 'Country': 'Germany', 'Phone': '0241-039123', 'Fax': '0241-059428' },
+ { 'ID': 'DUMON', 'CompanyName': 'Du monde entier', 'ContactName': 'Janine Labrune', 'ContactTitle': 'Owner', 'Address': '67, rue des Cinquante Otages', 'City': 'Nantes', 'Region': null, 'PostalCode': '44000', 'Country': 'France', 'Phone': '40.67.88.88', 'Fax': '40.67.89.89' },
+ { 'ID': 'EASTC', 'CompanyName': 'Eastern Connection', 'ContactName': 'Ann Devon', 'ContactTitle': 'Sales Agent', 'Address': '35 King George', 'City': 'London', 'Region': null, 'PostalCode': 'WX3 6FW', 'Country': 'UK', 'Phone': '(171) 555-0297', 'Fax': '(171) 555-3373' },
+ { 'ID': 'ERNSH', 'CompanyName': 'Ernst Handel', 'ContactName': 'Roland Mendel', 'ContactTitle': 'Sales Manager', 'Address': 'Kirchgasse 6', 'City': 'Graz', 'Region': null, 'PostalCode': '8010', 'Country': 'Austria', 'Phone': '7675-3425', 'Fax': '7675-3426' },
+ { 'ID': 'FAMIA', 'CompanyName': 'Familia Arquibaldo', 'ContactName': 'Aria Cruz', 'ContactTitle': 'Marketing Assistant', 'Address': 'Rua Orós, 92', 'City': 'Sao Paulo', 'Region': 'SP', 'PostalCode': '05442-030', 'Country': 'Brazil', 'Phone': '(11) 555-9857', 'Fax': null },
+ { 'ID': 'FISSA', 'CompanyName': 'FISSA Fabrica Inter. Salchichas S.A.', 'ContactName': 'Diego Roel', 'ContactTitle': 'Accounting Manager', 'Address': 'C/ Moralzarzal, 86', 'City': 'Madrid', 'Region': null, 'PostalCode': '28034', 'Country': 'Spain', 'Phone': '(91) 555 94 44', 'Fax': '(91) 555 55 93' },
+ { 'ID': 'FOLIG', 'CompanyName': 'Folies gourmandes', 'ContactName': 'Martine Rancé', 'ContactTitle': 'Assistant Sales Agent', 'Address': '184, chaussée de Tournai', 'City': 'Lille', 'Region': null, 'PostalCode': '59000', 'Country': 'France', 'Phone': '20.16.10.16', 'Fax': '20.16.10.17' },
+ { 'ID': 'FOLKO', 'CompanyName': 'Folk och fä HB', 'ContactName': 'Maria Larsson', 'ContactTitle': 'Owner', 'Address': 'Åkergatan 24', 'City': 'Bräcke', 'Region': null, 'PostalCode': 'S-844 67', 'Country': 'Sweden', 'Phone': '0695-34 67 21', 'Fax': null },
+ { 'ID': 'FRANK', 'CompanyName': 'Frankenversand', 'ContactName': 'Peter Franken', 'ContactTitle': 'Marketing Manager', 'Address': 'Berliner Platz 43', 'City': 'München', 'Region': null, 'PostalCode': '80805', 'Country': 'Germany', 'Phone': '089-0877310', 'Fax': '089-0877451' },
+ { 'ID': 'FRANR', 'CompanyName': 'France restauration', 'ContactName': 'Carine Schmitt', 'ContactTitle': 'Marketing Manager', 'Address': '54, rue Royale', 'City': 'Nantes', 'Region': null, 'PostalCode': '44000', 'Country': 'France', 'Phone': '40.32.21.21', 'Fax': '40.32.21.20' },
+ { 'ID': 'FRANS', 'CompanyName': 'Franchi S.p.A.', 'ContactName': 'Paolo Accorti', 'ContactTitle': 'Sales Representative', 'Address': 'Via Monte Bianco 34', 'City': 'Torino', 'Region': null, 'PostalCode': '10100', 'Country': 'Italy', 'Phone': '011-4988260', 'Fax': '011-4988261' }
+ ];
+ // tslint:enable:max-line-length
+ }
+}
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 1f00f07d7c6..9df69e49855 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -28,6 +28,11 @@ export class AppComponent implements OnInit {
};
componentLinks = [
+ {
+ link: '/action-strip',
+ icon: 'view_list',
+ name: 'Action Strip'
+ },
{
link: '/autocomplete',
icon: 'view_list',
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 2b06d172844..be626bb9a99 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -6,12 +6,13 @@ import { NgModule } from '@angular/core';
import {
IgxIconModule, IgxGridModule, IgxExcelExporterService, IgxCsvExporterService, IgxOverlayService,
IgxDragDropModule, IgxDividerModule, IgxTreeGridModule, IgxHierarchicalGridModule, IgxInputGroupModule,
- IgxIconService, DisplayDensityToken, DisplayDensity, IgxDateTimeEditorModule, IgxButtonModule
+ IgxIconService, DisplayDensityToken, DisplayDensity, IgxDateTimeEditorModule, IgxButtonModule, IgxActionStripModule
} from 'igniteui-angular';
import { IgxColumnHidingModule } from 'igniteui-angular';
import { SharedModule } from './shared/shared.module';
import { routing } from './routing';
+import { ActionStripSampleComponent } from './action-strip/action-strip.sample';
import { AppComponent } from './app.component';
import { AvatartSampleComponent } from './avatar/avatar.sample';
import { PageHeaderComponent } from './pageHeading/pageHeading.component';
@@ -122,6 +123,7 @@ import { ReactiveFormSampleComponent } from './reactive-from/reactive-form-sampl
import { GridRowPinningSampleComponent } from './grid-row-pinning/grid-row-pinning.sample';
const components = [
+ ActionStripSampleComponent,
AppComponent,
AutocompletePipeContains,
AutocompleteGroupPipeContains,
@@ -245,6 +247,7 @@ const components = [
HttpClientModule,
IgxIconModule,
IgxInputGroupModule,
+ IgxActionStripModule,
IgxGridModule,
IgxTreeGridModule,
IgxHierarchicalGridModule,
diff --git a/src/app/app.routing.ts b/src/app/app.routing.ts
index 0f13bb8b87a..5bd1b38595d 100644
--- a/src/app/app.routing.ts
+++ b/src/app/app.routing.ts
@@ -70,6 +70,7 @@ import { AboutComponent } from './grid-state/about.component';
import { GridMasterDetailSampleComponent } from './grid-master-detail/grid-master-detail.sample';
import { DateTimeEditorSampleComponent } from './date-time-editor/date-time-editor.sample';
import { GridRowPinningSampleComponent } from './grid-row-pinning/grid-row-pinning.sample';
+import { ActionStripSampleComponent } from './action-strip/action-strip.sample';
const appRoutes = [
{
@@ -77,6 +78,10 @@ const appRoutes = [
pathMatch: 'full',
redirectTo: '/avatar'
},
+ {
+ path: 'action-strip',
+ component: ActionStripSampleComponent
+ },
{
path: 'autocomplete',
component: AutocompleteSampleComponent
diff --git a/src/app/grid-column-pinning/grid-column-pinning.sample.css b/src/app/grid-column-pinning/grid-column-pinning.sample.css
index 10e8c0afa67..20cb9c4232a 100644
--- a/src/app/grid-column-pinning/grid-column-pinning.sample.css
+++ b/src/app/grid-column-pinning/grid-column-pinning.sample.css
@@ -6,3 +6,17 @@
[igxButton]+[igxButton] {
margin-left: 8px;
}
+
+.pin-icon {
+ text-align: center;
+}
+
+.igx-action-strip {
+ background-color: #00000080;
+}
+
+.actions {
+ margin: auto;
+ width: fit-content;
+ padding: 8px;
+}
\ No newline at end of file
diff --git a/src/app/grid-column-pinning/grid-column-pinning.sample.html b/src/app/grid-column-pinning/grid-column-pinning.sample.html
index 846dbba84f8..44a5f432ced 100644
--- a/src/app/grid-column-pinning/grid-column-pinning.sample.html
+++ b/src/app/grid-column-pinning/grid-column-pinning.sample.html
@@ -36,4 +36,4 @@
-
+
\ No newline at end of file
diff --git a/src/app/grid-column-pinning/grid-column-pinning.sample.ts b/src/app/grid-column-pinning/grid-column-pinning.sample.ts
index b722af11047..e22ff32cdb7 100644
--- a/src/app/grid-column-pinning/grid-column-pinning.sample.ts
+++ b/src/app/grid-column-pinning/grid-column-pinning.sample.ts
@@ -1,5 +1,5 @@
import { Component, OnInit, ViewChild } from '@angular/core';
-import { IgxGridComponent, ColumnPinningPosition, RowPinningPosition, GridSelectionMode } from 'igniteui-angular';
+import { IgxGridComponent, ColumnPinningPosition, RowPinningPosition, GridSelectionMode, IgxGridRowComponent } from 'igniteui-angular';
import { IPinningConfig } from 'projects/igniteui-angular/src/lib/grids/common/grid.interface';
@Component({
@@ -115,4 +115,10 @@ export class GridColumnPinningSampleComponent implements OnInit {
this.selectionMode = this.selectionMode === GridSelectionMode.none ? GridSelectionMode.multiple : GridSelectionMode.none;
}
+ doSomeAction(row?: IgxGridRowComponent) {
+ !this.grid1.isRecordPinned(row.rowData) ?
+ this.grid1.pinRow(row.rowData) :
+ this.grid1.unpinRow(row.rowData)
+ }
+
}
diff --git a/src/app/routing.ts b/src/app/routing.ts
index 413ce8b5ef8..bf6d9cd0b8f 100644
--- a/src/app/routing.ts
+++ b/src/app/routing.ts
@@ -97,6 +97,7 @@ import { GridMasterDetailSampleComponent } from './grid-master-detail/grid-maste
import { DateTimeEditorSampleComponent } from './date-time-editor/date-time-editor.sample';
import { GridRowPinningSampleComponent } from './grid-row-pinning/grid-row-pinning.sample';
import { ReactiveFormSampleComponent } from './reactive-from/reactive-form-sample.component';
+import { ActionStripSampleComponent } from './action-strip/action-strip.sample';
const appRoutes = [
{
@@ -104,6 +105,10 @@ const appRoutes = [
pathMatch: 'full',
redirectTo: '/avatar'
},
+ {
+ path: 'action-strip',
+ component: ActionStripSampleComponent
+ },
{
path: 'autocomplete',
component: AutocompleteSampleComponent
diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts
index 990f2026a79..2f5e27275ff 100644
--- a/src/app/shared/shared.module.ts
+++ b/src/app/shared/shared.module.ts
@@ -1,5 +1,6 @@
import { NgModule } from '@angular/core';
import {
+ IgxActionStripModule,
IgxAutocompleteModule,
IgxAvatarModule,
IgxBadgeModule,
@@ -43,6 +44,7 @@ import {
const igniteModules = [
+ IgxActionStripModule,
IgxAutocompleteModule,
IgxAvatarModule,
IgxBadgeModule,