diff --git a/apps/code-examples/src/app/app.component.html b/apps/code-examples/src/app/app.component.html
index a5b4552fdc..719285f526 100644
--- a/apps/code-examples/src/app/app.component.html
+++ b/apps/code-examples/src/app/app.component.html
@@ -34,6 +34,11 @@
Data Entry Grid with Data Manager
+
+
+ Data Entry Grid with inline help
+
+
Data Grid (basic)
@@ -57,6 +62,11 @@
Data Grid with top scrollbar
+
+
+ Data Grid with inline help
+
+
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo-context-menu.component.html b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo-context-menu.component.html
new file mode 100644
index 0000000000..4449c58976
--- /dev/null
+++ b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo-context-menu.component.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo-context-menu.component.ts b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo-context-menu.component.ts
new file mode 100644
index 0000000000..83aa1aa499
--- /dev/null
+++ b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo-context-menu.component.ts
@@ -0,0 +1,27 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+
+import { ICellRendererAngularComp } from 'ag-grid-angular';
+import { ICellRendererParams } from 'ag-grid-community';
+
+@Component({
+ selector: 'app-data-entry-grid-docs-demo-context-menu',
+ templateUrl: './data-entry-grid-docs-demo-context-menu.component.html',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class SkyDataEntryGridContextMenuComponent
+ implements ICellRendererAngularComp
+{
+ #name = '';
+
+ public agInit(params: ICellRendererParams): void {
+ this.#name = params.data && params.data.#name;
+ }
+
+ public refresh(): boolean {
+ return false;
+ }
+
+ public actionClicked(action: string): void {
+ alert(`${action} clicked for ${this.#name}`);
+ }
+}
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo-data.ts b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo-data.ts
new file mode 100644
index 0000000000..dd9a923dd9
--- /dev/null
+++ b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo-data.ts
@@ -0,0 +1,156 @@
+export interface SkyAutocompleteOption {
+ id: string;
+ name: string;
+}
+
+export const SKY_DEPARTMENTS = [
+ {
+ id: '1',
+ name: 'Marketing',
+ },
+ {
+ id: '2',
+ name: 'Sales',
+ },
+ {
+ id: '3',
+ name: 'Engineering',
+ },
+ {
+ id: '4',
+ name: 'Customer Support',
+ },
+];
+
+export const SKY_JOB_TITLES: { [name: string]: SkyAutocompleteOption[] } = {
+ Marketing: [
+ {
+ id: '1',
+ name: 'Social Media Coordinator',
+ },
+ {
+ id: '2',
+ name: 'Blog Manager',
+ },
+ {
+ id: '3',
+ name: 'Events Manager',
+ },
+ ],
+ Sales: [
+ {
+ id: '4',
+ name: 'Business Development Representative',
+ },
+ {
+ id: '5',
+ name: 'Account Executive',
+ },
+ ],
+ Engineering: [
+ {
+ id: '6',
+ name: 'Software Engineer',
+ },
+ {
+ id: '7',
+ name: 'Senior Software Engineer',
+ },
+ {
+ id: '8',
+ name: 'Principal Software Engineer',
+ },
+ {
+ id: '9',
+ name: 'UX Designer',
+ },
+ {
+ id: '10',
+ name: 'Product Manager',
+ },
+ ],
+ 'Customer Support': [
+ {
+ id: '11',
+ name: 'Customer Support Representative',
+ },
+ {
+ id: '12',
+ name: 'Account Manager',
+ },
+ {
+ id: '13',
+ name: 'Customer Support Specialist',
+ },
+ ],
+};
+
+export interface SkyAgGridDemoRow {
+ selected: boolean;
+ name: string;
+ age: number;
+ startDate: Date;
+ endDate?: Date;
+ department: SkyAutocompleteOption;
+ jobTitle?: SkyAutocompleteOption;
+}
+
+export const SKY_AG_GRID_DEMO_DATA = [
+ {
+ selected: true,
+ name: 'Billy Bob',
+ age: 55,
+ startDate: new Date('12/1/1994'),
+ department: SKY_DEPARTMENTS[3],
+ jobTitle: SKY_JOB_TITLES['Customer Support'][1],
+ },
+ {
+ selected: false,
+ name: 'Jane Deere',
+ age: 33,
+ startDate: new Date('7/15/2009'),
+ department: SKY_DEPARTMENTS[2],
+ jobTitle: SKY_JOB_TITLES['Engineering'][2],
+ },
+ {
+ selected: false,
+ name: 'John Doe',
+ age: 38,
+ startDate: new Date('9/1/2017'),
+ endDate: new Date('9/30/2017'),
+ department: SKY_DEPARTMENTS[1],
+ },
+ {
+ selected: false,
+ name: 'David Smith',
+ age: 51,
+ startDate: new Date('1/1/2012'),
+ endDate: new Date('6/15/2018'),
+ department: SKY_DEPARTMENTS[2],
+ jobTitle: SKY_JOB_TITLES['Engineering'][4],
+ },
+ {
+ selected: true,
+ name: 'Emily Johnson',
+ age: 41,
+ startDate: new Date('1/15/2014'),
+ department: SKY_DEPARTMENTS[0],
+ jobTitle: SKY_JOB_TITLES['Marketing'][2],
+ },
+ {
+ selected: false,
+ name: 'Nicole Davidson',
+ age: 22,
+ startDate: new Date('11/1/2019'),
+ department: SKY_DEPARTMENTS[2],
+ jobTitle: SKY_JOB_TITLES['Engineering'][0],
+ },
+ {
+ selected: false,
+ name: 'Carl Roberts',
+ age: 23,
+ startDate: new Date('11/1/2019'),
+ department: SKY_DEPARTMENTS[2],
+ jobTitle: SKY_JOB_TITLES['Engineering'][3],
+ },
+];
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo-edit-modal-context.ts b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo-edit-modal-context.ts
new file mode 100644
index 0000000000..7023f91acd
--- /dev/null
+++ b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo-edit-modal-context.ts
@@ -0,0 +1,5 @@
+import { SkyAgGridDemoRow } from './data-entry-grid-docs-demo-data';
+
+export class SkyDataEntryGridEditModalContext {
+ public gridData: SkyAgGridDemoRow[] = [];
+}
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo-edit-modal.component.html b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo-edit-modal.component.html
new file mode 100644
index 0000000000..1336ac6d46
--- /dev/null
+++ b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo-edit-modal.component.html
@@ -0,0 +1,31 @@
+
+ Edit employee information
+
+
+
+
+
+
+
+
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo-edit-modal.component.ts b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo-edit-modal.component.ts
new file mode 100644
index 0000000000..22291be956
--- /dev/null
+++ b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo-edit-modal.component.ts
@@ -0,0 +1,213 @@
+import {
+ ChangeDetectionStrategy,
+ ChangeDetectorRef,
+ Component,
+} from '@angular/core';
+import {
+ SkyAgGridAutocompleteProperties,
+ SkyAgGridDatepickerProperties,
+ SkyAgGridService,
+ SkyCellType,
+} from '@skyux/ag-grid';
+import { SkyAutocompleteSelectionChange } from '@skyux/lookup';
+import { SkyModalInstance } from '@skyux/modals';
+
+import {
+ ColDef,
+ GridApi,
+ GridOptions,
+ GridReadyEvent,
+ ICellEditorParams,
+ NewValueParams,
+ RowNode,
+} from 'ag-grid-community';
+
+import {
+ SKY_DEPARTMENTS,
+ SKY_JOB_TITLES,
+ SkyAgGridDemoRow,
+} from './data-entry-grid-docs-demo-data';
+import { SkyDataEntryGridEditModalContext } from './data-entry-grid-docs-demo-edit-modal-context';
+
+@Component({
+ selector: 'app-data-entry-grid-docs-demo-edit-modal',
+ templateUrl: './data-entry-grid-docs-demo-edit-modal.component.html',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class SkyDataEntryGridEditModalComponent {
+ public columnDefs: ColDef[];
+ public gridData: SkyAgGridDemoRow[];
+ public gridOptions: GridOptions;
+
+ #gridApi: GridApi | undefined;
+ #agGridService: SkyAgGridService;
+ #changeDetector: ChangeDetectorRef;
+
+ constructor(
+ public context: SkyDataEntryGridEditModalContext,
+ public instance: SkyModalInstance,
+ agGridService: SkyAgGridService,
+ changeDetector: ChangeDetectorRef
+ ) {
+ this.#agGridService = agGridService;
+ this.#changeDetector = changeDetector;
+
+ this.columnDefs = [
+ {
+ field: 'name',
+ headerName: 'Name',
+ type: SkyCellType.Text,
+ cellRendererParams: {
+ skyComponentProperties: {
+ validator: (value): boolean => String(value).length <= 10,
+ validatorMessage: `Value exceeds maximum length`,
+ },
+ },
+ cellEditorParams: {
+ skyComponentProperties: {
+ maxlength: 10,
+ },
+ },
+ editable: true,
+ },
+ {
+ field: 'age',
+ headerName: 'Age',
+ type: SkyCellType.Number,
+ cellRendererParams: {
+ skyComponentProperties: {
+ validator: (value) => value >= 18,
+ validatorMessage: `Age must be 18+`,
+ },
+ },
+ maxWidth: 60,
+ cellEditorParams: {
+ skyComponentProperties: {
+ min: 18,
+ },
+ },
+ editable: true,
+ },
+ {
+ field: 'startDate',
+ headerName: 'Start date',
+ type: SkyCellType.Date,
+ sort: 'asc',
+ },
+ {
+ field: 'endDate',
+ headerName: 'End date',
+ type: SkyCellType.Date,
+ editable: true,
+ cellEditorParams: (
+ params: ICellEditorParams
+ ): { skyComponentProperties: SkyAgGridDatepickerProperties } => {
+ return { skyComponentProperties: { minDate: params.data.startDate } };
+ },
+ },
+ {
+ field: 'department',
+ headerName: 'Department',
+ type: SkyCellType.Autocomplete,
+ editable: true,
+ cellEditorParams: (
+ params: ICellEditorParams
+ ): { skyComponentProperties: SkyAgGridAutocompleteProperties } => {
+ return {
+ skyComponentProperties: {
+ data: SKY_DEPARTMENTS,
+ selectionChange: (
+ change: SkyAutocompleteSelectionChange
+ ): void => {
+ this.#departmentSelectionChange(change, params.node);
+ },
+ },
+ };
+ },
+ onCellValueChanged: (event: NewValueParams): void => {
+ if (event.newValue !== event.oldValue) {
+ this.#clearJobTitle(event.node);
+ }
+ },
+ },
+ {
+ field: 'jobTitle',
+ headerName: 'Title',
+ type: SkyCellType.Autocomplete,
+ editable: true,
+ cellEditorParams: (
+ params: ICellEditorParams
+ ): { skyComponentProperties: SkyAgGridAutocompleteProperties } => {
+ const selectedDepartment: string =
+ params.data &&
+ params.data.department &&
+ params.data.department.name;
+ const editParams: {
+ skyComponentProperties: SkyAgGridAutocompleteProperties;
+ } = { skyComponentProperties: { data: [] } };
+
+ if (selectedDepartment) {
+ editParams.skyComponentProperties.data =
+ SKY_JOB_TITLES[selectedDepartment];
+ }
+ return editParams;
+ },
+ },
+ {
+ colId: 'validationCurrency',
+ field: 'validationCurrency',
+ headerName: 'Validation currency',
+ type: [SkyCellType.CurrencyValidator],
+ editable: true,
+ },
+ {
+ colId: 'validationDate',
+ field: 'validationDate',
+ headerName: 'Validation date',
+ type: [SkyCellType.Date, SkyCellType.Validator],
+ cellRendererParams: {
+ skyComponentProperties: {
+ validator: (value: Date) =>
+ !!value && value > new Date(1985, 9, 26),
+ validatorMessage: 'Please enter a future date',
+ },
+ },
+ editable: true,
+ },
+ ];
+ this.gridData = this.context.gridData;
+ this.gridOptions = {
+ columnDefs: this.columnDefs,
+ onGridReady: (gridReadyEvent) => this.onGridReady(gridReadyEvent),
+ };
+ this.gridOptions = this.#agGridService.getEditableGridOptions({
+ gridOptions: this.gridOptions,
+ });
+ this.#changeDetector.markForCheck();
+ }
+
+ public onGridReady(gridReadyEvent: GridReadyEvent): void {
+ this.#gridApi = gridReadyEvent.api;
+ this.#gridApi.sizeColumnsToFit();
+ this.#changeDetector.markForCheck();
+ }
+
+ #departmentSelectionChange(
+ change: SkyAutocompleteSelectionChange,
+ node: RowNode
+ ): void {
+ if (change.selectedItem && change.selectedItem !== node.data.department) {
+ this.#clearJobTitle(node);
+ }
+ }
+
+ #clearJobTitle(node: RowNode | null): void {
+ if (node) {
+ node.data.jobTitle = undefined;
+ this.#changeDetector.markForCheck();
+ if (this.#gridApi) {
+ this.#gridApi.refreshCells({ rowNodes: [node] });
+ }
+ }
+ }
+}
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo.component.html b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo.component.html
new file mode 100644
index 0000000000..40ded45897
--- /dev/null
+++ b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo.component.html
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo.component.ts b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo.component.ts
new file mode 100644
index 0000000000..a78c08e32c
--- /dev/null
+++ b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo.component.ts
@@ -0,0 +1,219 @@
+import {
+ ChangeDetectionStrategy,
+ ChangeDetectorRef,
+ Component,
+} from '@angular/core';
+import { SkyAgGridService, SkyCellType } from '@skyux/ag-grid';
+import { SkyModalCloseArgs, SkyModalService } from '@skyux/modals';
+
+import {
+ ColDef,
+ GridApi,
+ GridOptions,
+ GridReadyEvent,
+ ValueFormatterParams,
+} from 'ag-grid-community';
+
+import { SkyDataEntryGridContextMenuComponent } from './data-entry-grid-docs-demo-context-menu.component';
+import { SKY_AG_GRID_DEMO_DATA } from './data-entry-grid-docs-demo-data';
+import { SkyDataEntryGridEditModalContext } from './data-entry-grid-docs-demo-edit-modal-context';
+import { SkyDataEntryGridEditModalComponent } from './data-entry-grid-docs-demo-edit-modal.component';
+import { InlineHelpComponent } from './inline-help.component';
+
+@Component({
+ selector: 'app-data-entry-grid-docs-demo',
+ templateUrl: './data-entry-grid-docs-demo.component.html',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class SkyDataEntryGridDemoComponent {
+ public gridData = SKY_AG_GRID_DEMO_DATA;
+ public columnDefs: ColDef[] = [
+ {
+ field: 'selected',
+ type: SkyCellType.RowSelector,
+ },
+ {
+ colId: 'context',
+ headerName: '',
+ maxWidth: 50,
+ sortable: false,
+ cellRenderer: SkyDataEntryGridContextMenuComponent,
+ },
+ {
+ field: 'name',
+ headerName: 'Name',
+ type: SkyCellType.Text,
+ cellRendererParams: {
+ skyComponentProperties: {
+ validator: (value): boolean => String(value).length <= 10,
+ validatorMessage: `Value exceeds maximum length`,
+ },
+ },
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
+ },
+ {
+ field: 'age',
+ headerName: 'Age',
+ type: SkyCellType.Number,
+ cellRendererParams: {
+ skyComponentProperties: {
+ validator: (value) => value >= 18,
+ validatorMessage: `Age must be 18+`,
+ },
+ },
+ maxWidth: 60,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
+ },
+ {
+ field: 'startDate',
+ headerName: 'Start date',
+ type: SkyCellType.Date,
+ sort: 'asc',
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
+ },
+ {
+ field: 'endDate',
+ headerName: 'End date',
+ type: SkyCellType.Date,
+ valueFormatter: this.#endDateFormatter,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
+ },
+ {
+ field: 'department',
+ headerName: 'Department',
+ type: SkyCellType.Autocomplete,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
+ },
+ {
+ field: 'jobTitle',
+ headerName: 'Title',
+ type: SkyCellType.Autocomplete,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
+ },
+ {
+ colId: 'validationCurrency',
+ field: 'validationCurrency',
+ headerName: 'Validation currency',
+ type: [SkyCellType.CurrencyValidator],
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
+ },
+ {
+ colId: 'validationDate',
+ field: 'validationDate',
+ headerName: 'Validation date',
+ type: [SkyCellType.Date, SkyCellType.Validator],
+ cellRendererParams: {
+ skyComponentProperties: {
+ validator: (value: Date) => !!value && value > new Date(1985, 9, 26),
+ validatorMessage: 'Please enter a future date',
+ },
+ },
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
+ },
+ ];
+
+ public gridApi: GridApi | undefined;
+ public gridOptions: GridOptions;
+ public searchText = '';
+ public noRowsTemplate = `No results found.
`;
+
+ #agGridService: SkyAgGridService;
+ #modalService: SkyModalService;
+ #changeDetection: ChangeDetectorRef;
+
+ constructor(
+ agGridService: SkyAgGridService,
+ modalService: SkyModalService,
+ changeDetection: ChangeDetectorRef
+ ) {
+ this.#agGridService = agGridService;
+ this.#modalService = modalService;
+ this.#changeDetection = changeDetection;
+
+ this.gridOptions = {
+ columnDefs: this.columnDefs,
+ onGridReady: (gridReadyEvent) => this.onGridReady(gridReadyEvent),
+ };
+
+ this.gridOptions = this.#agGridService.getGridOptions({
+ gridOptions: this.gridOptions,
+ });
+ this.#changeDetection.markForCheck();
+ }
+
+ public onGridReady(gridReadyEvent: GridReadyEvent): void {
+ this.gridApi = gridReadyEvent.api;
+ this.gridApi.sizeColumnsToFit();
+ this.#changeDetection.markForCheck();
+ }
+
+ public openModal(): void {
+ const context = new SkyDataEntryGridEditModalContext();
+ context.gridData = this.gridData;
+
+ const options = {
+ providers: [
+ { provide: SkyDataEntryGridEditModalContext, useValue: context },
+ ],
+ ariaDescribedBy: 'docs-edit-grid-modal-content',
+ size: 'large',
+ };
+
+ const modalInstance = this.#modalService.open(
+ SkyDataEntryGridEditModalComponent,
+ options
+ );
+
+ modalInstance.closed.subscribe((result: SkyModalCloseArgs) => {
+ if (result.reason === 'cancel' || result.reason === 'close') {
+ alert('Edits canceled!');
+ } else {
+ this.gridData = result.data;
+ if (this.gridApi) {
+ this.gridApi.refreshCells();
+ }
+ alert('Saving data!');
+ }
+ });
+ }
+
+ public searchApplied(searchText: string | void): void {
+ if (searchText) {
+ this.searchText = searchText;
+ } else {
+ this.searchText = '';
+ }
+ if (this.gridApi) {
+ this.gridApi.setQuickFilter(this.searchText);
+ const displayedRowCount = this.gridApi.getDisplayedRowCount();
+ if (displayedRowCount > 0) {
+ this.gridApi.hideOverlay();
+ } else {
+ this.gridApi.showNoRowsOverlay();
+ }
+ }
+ }
+
+ #endDateFormatter(params: ValueFormatterParams): string {
+ const dateConfig = { year: 'numeric', month: '2-digit', day: '2-digit' };
+ return params.value
+ ? params.value.toLocaleDateString('en-us', dateConfig)
+ : 'N/A';
+ }
+}
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo.module.ts b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo.module.ts
new file mode 100644
index 0000000000..dcb6c41ce1
--- /dev/null
+++ b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo.module.ts
@@ -0,0 +1,34 @@
+import { NgModule } from '@angular/core';
+import { SkyAgGridModule } from '@skyux/ag-grid';
+import { SkyHelpInlineModule } from '@skyux/indicators';
+import { SkyToolbarModule } from '@skyux/layout';
+import { SkySearchModule } from '@skyux/lookup';
+import { SkyModalModule } from '@skyux/modals';
+import { SkyDropdownModule } from '@skyux/popovers';
+
+import { AgGridModule } from 'ag-grid-angular';
+
+import { SkyDataEntryGridContextMenuComponent } from './data-entry-grid-docs-demo-context-menu.component';
+import { SkyDataEntryGridEditModalComponent } from './data-entry-grid-docs-demo-edit-modal.component';
+import { SkyDataEntryGridDemoComponent } from './data-entry-grid-docs-demo.component';
+import { InlineHelpComponent } from './inline-help.component';
+
+@NgModule({
+ declarations: [
+ SkyDataEntryGridContextMenuComponent,
+ SkyDataEntryGridDemoComponent,
+ SkyDataEntryGridEditModalComponent,
+ InlineHelpComponent,
+ ],
+ imports: [
+ SkyToolbarModule,
+ SkySearchModule,
+ AgGridModule,
+ SkyAgGridModule,
+ SkyModalModule,
+ SkyDropdownModule,
+ SkyHelpInlineModule,
+ ],
+ exports: [SkyDataEntryGridDemoComponent],
+})
+export class SkyDataEntryGridDocsDemoModule {}
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/inline-help.component.html b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/inline-help.component.html
new file mode 100644
index 0000000000..bd7eeb3e98
--- /dev/null
+++ b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/inline-help.component.html
@@ -0,0 +1,4 @@
+
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/inline-help.component.ts b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/inline-help.component.ts
new file mode 100644
index 0000000000..59eb31ed05
--- /dev/null
+++ b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/inline-help.component.ts
@@ -0,0 +1,26 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { SkyAgGridHeaderInfo } from '@skyux/ag-grid';
+
+@Component({
+ selector: 'app-inline-help',
+ templateUrl: './inline-help.component.html',
+ styles: [
+ `
+ :host {
+ display: block;
+ }
+ `,
+ ],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class InlineHelpComponent {
+ readonly #displayName: string;
+
+ constructor(headerInfo: SkyAgGridHeaderInfo) {
+ this.#displayName = headerInfo.displayName;
+ }
+
+ public onHelpClick(): void {
+ alert(`Help was clicked for ${this.#displayName}.`);
+ }
+}
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-grid/inline-help/data-grid-demo-data.ts b/apps/code-examples/src/app/code-examples/ag-grid/data-grid/inline-help/data-grid-demo-data.ts
new file mode 100644
index 0000000000..2ddd015cbf
--- /dev/null
+++ b/apps/code-examples/src/app/code-examples/ag-grid/data-grid/inline-help/data-grid-demo-data.ts
@@ -0,0 +1,149 @@
+export interface SkyAutocompleteOption {
+ id: string;
+ name: string;
+}
+
+export const SKY_DEPARTMENTS = [
+ {
+ id: '1',
+ name: 'Marketing',
+ },
+ {
+ id: '2',
+ name: 'Sales',
+ },
+ {
+ id: '3',
+ name: 'Engineering',
+ },
+ {
+ id: '4',
+ name: 'Customer Support',
+ },
+];
+
+export const SKY_JOB_TITLES: { [name: string]: SkyAutocompleteOption[] } = {
+ Marketing: [
+ {
+ id: '1',
+ name: 'Social Media Coordinator',
+ },
+ {
+ id: '2',
+ name: 'Blog Manager',
+ },
+ {
+ id: '3',
+ name: 'Events Manager',
+ },
+ ],
+ Sales: [
+ {
+ id: '4',
+ name: 'Business Development Representative',
+ },
+ {
+ id: '5',
+ name: 'Account Executive',
+ },
+ ],
+ Engineering: [
+ {
+ id: '6',
+ name: 'Software Engineer',
+ },
+ {
+ id: '7',
+ name: 'Senior Software Engineer',
+ },
+ {
+ id: '8',
+ name: 'Principal Software Engineer',
+ },
+ {
+ id: '9',
+ name: 'UX Designer',
+ },
+ {
+ id: '10',
+ name: 'Product Manager',
+ },
+ ],
+ 'Customer Support': [
+ {
+ id: '11',
+ name: 'Customer Support Representative',
+ },
+ {
+ id: '12',
+ name: 'Account Manager',
+ },
+ {
+ id: '13',
+ name: 'Customer Support Specialist',
+ },
+ ],
+};
+
+export interface SkyAgGridDemoRow {
+ selected: boolean;
+ name: string;
+ age: number;
+ startDate: Date;
+ endDate?: Date;
+ department: SkyAutocompleteOption;
+ jobTitle?: SkyAutocompleteOption;
+}
+
+export const SKY_AG_GRID_DEMO_DATA = [
+ {
+ name: 'Billy Bob',
+ age: 55,
+ startDate: new Date('12/1/1994'),
+ department: SKY_DEPARTMENTS[3],
+ jobTitle: SKY_JOB_TITLES['Customer Support'][1],
+ },
+ {
+ name: 'Jane Deere',
+ age: 33,
+ startDate: new Date('7/15/2009'),
+ department: SKY_DEPARTMENTS[2],
+ jobTitle: SKY_JOB_TITLES['Engineering'][2],
+ },
+ {
+ name: 'John Doe',
+ age: 38,
+ startDate: new Date('9/1/2017'),
+ endDate: new Date('9/30/2017'),
+ department: SKY_DEPARTMENTS[1],
+ },
+ {
+ name: 'David Smith',
+ age: 51,
+ startDate: new Date('1/1/2012'),
+ endDate: new Date('6/15/2018'),
+ department: SKY_DEPARTMENTS[2],
+ jobTitle: SKY_JOB_TITLES['Engineering'][4],
+ },
+ {
+ name: 'Emily Johnson',
+ age: 41,
+ startDate: new Date('1/15/2014'),
+ department: SKY_DEPARTMENTS[0],
+ jobTitle: SKY_JOB_TITLES['Marketing'][2],
+ },
+ {
+ name: 'Nicole Davidson',
+ age: 22,
+ startDate: new Date('11/1/2019'),
+ department: SKY_DEPARTMENTS[2],
+ jobTitle: SKY_JOB_TITLES['Engineering'][0],
+ },
+ {
+ name: 'Carl Roberts',
+ age: 23,
+ startDate: new Date('11/1/2019'),
+ department: SKY_DEPARTMENTS[2],
+ jobTitle: SKY_JOB_TITLES['Engineering'][3],
+ },
+];
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-grid/inline-help/data-grid-demo.component.html b/apps/code-examples/src/app/code-examples/ag-grid/data-grid/inline-help/data-grid-demo.component.html
new file mode 100644
index 0000000000..423eeac270
--- /dev/null
+++ b/apps/code-examples/src/app/code-examples/ag-grid/data-grid/inline-help/data-grid-demo.component.html
@@ -0,0 +1,22 @@
+
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-grid/inline-help/data-grid-demo.component.ts b/apps/code-examples/src/app/code-examples/ag-grid/data-grid/inline-help/data-grid-demo.component.ts
new file mode 100644
index 0000000000..a1eb7b7a94
--- /dev/null
+++ b/apps/code-examples/src/app/code-examples/ag-grid/data-grid/inline-help/data-grid-demo.component.ts
@@ -0,0 +1,136 @@
+import {
+ ChangeDetectionStrategy,
+ ChangeDetectorRef,
+ Component,
+} from '@angular/core';
+import { SkyAgGridService, SkyCellType } from '@skyux/ag-grid';
+
+import {
+ ColDef,
+ GridApi,
+ GridOptions,
+ GridReadyEvent,
+ ValueFormatterParams,
+} from 'ag-grid-community';
+
+import { SKY_AG_GRID_DEMO_DATA } from './data-grid-demo-data';
+import { InlineHelpComponent } from './inline-help.component';
+
+@Component({
+ selector: 'app-data-grid-demo',
+ templateUrl: './data-grid-demo.component.html',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class DataGridDemoComponent {
+ public columnDefs: ColDef[] = [
+ {
+ field: 'selected',
+ type: SkyCellType.RowSelector,
+ },
+ {
+ field: 'name',
+ headerName: 'Name',
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
+ },
+ {
+ field: 'age',
+ headerName: 'Age',
+ type: SkyCellType.Number,
+ maxWidth: 60,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
+ },
+ {
+ field: 'startDate',
+ headerName: 'Start date',
+ type: SkyCellType.Date,
+ sort: 'asc',
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
+ },
+ {
+ field: 'endDate',
+ headerName: 'End date',
+ type: SkyCellType.Date,
+ valueFormatter: this.#endDateFormatter,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
+ },
+ {
+ field: 'department',
+ headerName: 'Department',
+ type: SkyCellType.Autocomplete,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
+ },
+ {
+ field: 'jobTitle',
+ headerName: 'Title',
+ type: SkyCellType.Autocomplete,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
+ },
+ ];
+
+ public gridApi: GridApi | undefined;
+ public gridData = SKY_AG_GRID_DEMO_DATA;
+ public gridOptions: GridOptions;
+ public searchText = '';
+ public noRowsTemplate: string;
+
+ #agGridService: SkyAgGridService;
+ #changeDetector: ChangeDetectorRef;
+
+ constructor(
+ agGridService: SkyAgGridService,
+ changeDetector: ChangeDetectorRef
+ ) {
+ this.#agGridService = agGridService;
+ this.#changeDetector = changeDetector;
+ this.noRowsTemplate = `No results found.
`;
+ this.gridOptions = this.#agGridService.getGridOptions({
+ gridOptions: {
+ columnDefs: this.columnDefs,
+ onGridReady: this.onGridReady.bind(this),
+ },
+ });
+ this.#changeDetector.markForCheck();
+ }
+
+ public onGridReady(gridReadyEvent: GridReadyEvent): void {
+ this.gridApi = gridReadyEvent.api;
+ this.gridApi.sizeColumnsToFit();
+ this.#changeDetector.markForCheck();
+ }
+
+ public searchApplied(searchText: string | void): void {
+ if (searchText) {
+ this.searchText = searchText;
+ } else {
+ this.searchText = '';
+ }
+ if (this.gridApi) {
+ this.gridApi.setQuickFilter(this.searchText);
+ const displayedRowCount = this.gridApi.getDisplayedRowCount();
+ if (displayedRowCount > 0) {
+ this.gridApi.hideOverlay();
+ } else {
+ this.gridApi.showNoRowsOverlay();
+ }
+ }
+ }
+
+ #endDateFormatter(params: ValueFormatterParams): string {
+ const dateConfig = { year: 'numeric', month: '2-digit', day: '2-digit' };
+ return params.value
+ ? params.value.toLocaleDateString('en-us', dateConfig)
+ : 'N/A';
+ }
+}
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-grid/inline-help/data-grid-demo.module.ts b/apps/code-examples/src/app/code-examples/ag-grid/data-grid/inline-help/data-grid-demo.module.ts
new file mode 100644
index 0000000000..cb35a2616c
--- /dev/null
+++ b/apps/code-examples/src/app/code-examples/ag-grid/data-grid/inline-help/data-grid-demo.module.ts
@@ -0,0 +1,31 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { SkyAgGridModule } from '@skyux/ag-grid';
+import {
+ SkyDataManagerModule,
+ SkyDataManagerService,
+} from '@skyux/data-manager';
+import { SkyHelpInlineModule } from '@skyux/indicators';
+import { SkyToolbarModule } from '@skyux/layout';
+import { SkySearchModule } from '@skyux/lookup';
+
+import { AgGridModule } from 'ag-grid-angular';
+
+import { DataGridDemoComponent } from './data-grid-demo.component';
+import { InlineHelpComponent } from './inline-help.component';
+
+@NgModule({
+ declarations: [DataGridDemoComponent, InlineHelpComponent],
+ exports: [DataGridDemoComponent],
+ imports: [
+ CommonModule,
+ SkyToolbarModule,
+ SkySearchModule,
+ SkyDataManagerModule,
+ SkyAgGridModule,
+ AgGridModule,
+ SkyHelpInlineModule,
+ ],
+ providers: [SkyDataManagerService],
+})
+export class DataGridDemoModule {}
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-grid/inline-help/inline-help.component.html b/apps/code-examples/src/app/code-examples/ag-grid/data-grid/inline-help/inline-help.component.html
new file mode 100644
index 0000000000..bd7eeb3e98
--- /dev/null
+++ b/apps/code-examples/src/app/code-examples/ag-grid/data-grid/inline-help/inline-help.component.html
@@ -0,0 +1,4 @@
+
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-grid/inline-help/inline-help.component.ts b/apps/code-examples/src/app/code-examples/ag-grid/data-grid/inline-help/inline-help.component.ts
new file mode 100644
index 0000000000..59eb31ed05
--- /dev/null
+++ b/apps/code-examples/src/app/code-examples/ag-grid/data-grid/inline-help/inline-help.component.ts
@@ -0,0 +1,26 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { SkyAgGridHeaderInfo } from '@skyux/ag-grid';
+
+@Component({
+ selector: 'app-inline-help',
+ templateUrl: './inline-help.component.html',
+ styles: [
+ `
+ :host {
+ display: block;
+ }
+ `,
+ ],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class InlineHelpComponent {
+ readonly #displayName: string;
+
+ constructor(headerInfo: SkyAgGridHeaderInfo) {
+ this.#displayName = headerInfo.displayName;
+ }
+
+ public onHelpClick(): void {
+ alert(`Help was clicked for ${this.#displayName}.`);
+ }
+}
diff --git a/apps/code-examples/src/app/features/ag-grid.module.ts b/apps/code-examples/src/app/features/ag-grid.module.ts
index b51839aa63..44eda9435f 100644
--- a/apps/code-examples/src/app/features/ag-grid.module.ts
+++ b/apps/code-examples/src/app/features/ag-grid.module.ts
@@ -5,6 +5,8 @@ import { SkyDataEntryGridDemoComponent as DataEntryGridBasicDataEntryGridDocsDem
import { SkyDataEntryGridDocsDemoModule as DataEntryGridBasicDataEntryGridDocsDemoModule } from '../code-examples/ag-grid/data-entry-grid/basic/data-entry-grid-docs-demo.module';
import { SkyDataManagerDataEntryGridDemoComponent as DataEntryGridDataManagerAddedDataManagerDataEntryGridDocsDemoComponent } from '../code-examples/ag-grid/data-entry-grid/data-manager-added/data-manager-data-entry-grid-docs-demo.component';
import { SkyDataManagerDataEntryGridDocsDemoModule as DataEntryGridDataManagerAddedDataManagerDataEntryGridDocsDemoModule } from '../code-examples/ag-grid/data-entry-grid/data-manager-added/data-manager-data-entry-grid-docs-demo.module';
+import { SkyDataEntryGridDemoComponent as DataEntryGridInlineHelpDataEntryGridDocsDemoComponent } from '../code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo.component';
+import { SkyDataEntryGridDocsDemoModule as DataEntryGridInlineHelpDataEntryGridDocsDemoModule } from '../code-examples/ag-grid/data-entry-grid/inline-help/data-entry-grid-docs-demo.module';
import { SkyBasicMultiselectDataGridDemoComponent as DataGridBasicMultiselectDataGridDocsDemoComponent } from '../code-examples/ag-grid/data-grid/basic-multiselect/basic-multiselect-data-grid-docs-demo.component';
import { SkyBasicMultiselectDataGridDocsDemoModule } from '../code-examples/ag-grid/data-grid/basic-multiselect/basic-multiselect-data-grid-docs-demo.module';
import { SkyBasicDataGridDemoComponent as DataGridBasicDataGridDocsDemoComponent } from '../code-examples/ag-grid/data-grid/basic/basic-data-grid-docs-demo.component';
@@ -13,6 +15,8 @@ import { SkyDataManagerMultiselectDataGridDemoComponent as DataGridDataManagerAd
import { SkyDataManagerMultiselectDataGridDocsDemoModule } from '../code-examples/ag-grid/data-grid/data-manager-multiselect/data-manager-multiselect-data-grid-docs-demo.module';
import { SkyDataManagerDataGridDemoComponent as DataGridDataManagerAddedDataManagerDataGridDocsDemoComponent } from '../code-examples/ag-grid/data-grid/data-manager/data-manager-data-grid-docs-demo.component';
import { SkyDataManagerDataGridDocsDemoModule } from '../code-examples/ag-grid/data-grid/data-manager/data-manager-data-grid-docs-demo.module';
+import { DataGridDemoComponent as InlineHelpDataGridDemoComponent } from '../code-examples/ag-grid/data-grid/inline-help/data-grid-demo.component';
+import { DataGridDemoModule as InlineHelpDataGridDemoModule } from '../code-examples/ag-grid/data-grid/inline-help/data-grid-demo.module';
import { SkyTopScrollDataGridDemoComponent } from '../code-examples/ag-grid/data-grid/top-scroll/top-scroll-data-grid-demo.component';
import { SkyTopScrollDataGridDemoModule } from '../code-examples/ag-grid/data-grid/top-scroll/top-scroll-data-grid-demo.module';
@@ -26,6 +30,10 @@ const routes: Routes = [
component:
DataEntryGridDataManagerAddedDataManagerDataEntryGridDocsDemoComponent,
},
+ {
+ path: 'data-entry-grid/inline-help',
+ component: DataEntryGridInlineHelpDataEntryGridDocsDemoComponent,
+ },
{
path: 'data-grid/basic',
component: DataGridBasicDataGridDocsDemoComponent,
@@ -47,6 +55,10 @@ const routes: Routes = [
path: 'data-grid/top-scroll',
component: SkyTopScrollDataGridDemoComponent,
},
+ {
+ path: 'data-grid/inline-help',
+ component: InlineHelpDataGridDemoComponent,
+ },
];
@NgModule({
@@ -59,7 +71,9 @@ export class AgGridFeatureRoutingModule {}
imports: [
DataEntryGridBasicDataEntryGridDocsDemoModule,
DataEntryGridDataManagerAddedDataManagerDataEntryGridDocsDemoModule,
+ DataEntryGridInlineHelpDataEntryGridDocsDemoModule,
DataGridBasicBasicDataGridDocsDemoModule,
+ InlineHelpDataGridDemoModule,
SkyBasicMultiselectDataGridDocsDemoModule,
SkyDataManagerDataGridDocsDemoModule,
SkyDataManagerMultiselectDataGridDocsDemoModule,
diff --git a/apps/e2e/ag-grid-storybook-e2e/src/e2e/ag-grid-stories.component.cy.ts b/apps/e2e/ag-grid-storybook-e2e/src/e2e/ag-grid-stories.component.cy.ts
index 172d4ff8e4..a6bbc38600 100644
--- a/apps/e2e/ag-grid-storybook-e2e/src/e2e/ag-grid-stories.component.cy.ts
+++ b/apps/e2e/ag-grid-storybook-e2e/src/e2e/ag-grid-stories.component.cy.ts
@@ -34,6 +34,22 @@ describe(`ag-grid-storybook`, () => {
.should('contain.text', 'Expected a number between 1 and 18.')
.end()
+ // Expect inline help buttons to be visible in three grids.
+ .get('#row-delete [col-id="name"] button.sky-help-inline')
+ .should('exist')
+ .should('be.visible')
+ .end()
+
+ .get('#back-to-top [col-id="name"] button.sky-help-inline')
+ .should('exist')
+ .should('be.visible')
+ .end()
+
+ .get('#validation [col-id="name"] button.sky-help-inline')
+ .should('exist')
+ .should('be.visible')
+ .end()
+
.get('#root')
.should('exist')
.should('be.visible')
diff --git a/apps/e2e/ag-grid-storybook-e2e/src/e2e/data-entry-grid.component.cy.ts b/apps/e2e/ag-grid-storybook-e2e/src/e2e/data-entry-grid.component.cy.ts
index c49bb0a469..c4af7f38f5 100644
--- a/apps/e2e/ag-grid-storybook-e2e/src/e2e/data-entry-grid.component.cy.ts
+++ b/apps/e2e/ag-grid-storybook-e2e/src/e2e/data-entry-grid.component.cy.ts
@@ -23,20 +23,20 @@ describe('ag-grid-storybook', () => {
.end()
// Activate a date field without the calendar.
- .get('#editDate div[row-id="aparilu01"] > div[col-id="birthday"]')
+ .get('#editDate div[row-id="bankser01"] > div[col-id="birthday"]')
.should('be.visible')
.click()
.end()
// Activate a date field.
.get(
- '#editDateWithCalendar div[row-id="berrayo01"] > div[col-id="birthday"]'
+ '#editDateWithCalendar div[row-id="blylebe01"] > div[col-id="birthday"]'
)
.should('be.visible')
.click()
.end()
- // Open the calendar.
+ // Open the calendar and verify 04/06/1951 is selected.
.get(
'#editDateWithCalendar .ag-popup-editor button[aria-label="Select date"]'
)
@@ -45,7 +45,23 @@ describe('ag-grid-storybook', () => {
.end()
.get('.ag-custom-component-popup .sky-datepicker-btn-selected')
.should('be.visible')
- .should('contain.text', '12')
+ .should('contain.text', '06')
+ .end()
+
+ // Expect inline help buttons to be visible in three grids.
+ .get('#editDateWithCalendar [col-id="name"] button.sky-help-inline')
+ .should('exist')
+ .should('be.visible')
+ .end()
+
+ .get('#editDate [col-id="name"] button.sky-help-inline')
+ .should('exist')
+ .should('be.visible')
+ .end()
+
+ .get('#editLookup [col-id="name"] button.sky-help-inline')
+ .should('exist')
+ .should('be.visible')
.end()
// Screenshot the three grids with active editors.
@@ -80,7 +96,7 @@ describe('ag-grid-storybook', () => {
.waitForFaAndBbFonts()
// Activate a text field.
- .get('#editText div[row-id="bankser01"] > div[col-id="name"]')
+ .get('#editText div[row-id="benchjo01"] > div[col-id="name"]')
.should('be.visible')
.click()
.end()
diff --git a/apps/e2e/ag-grid-storybook/src/app/ag-grid/ag-grid-stories.component.ts b/apps/e2e/ag-grid-storybook/src/app/ag-grid/ag-grid-stories.component.ts
index 150718e1c2..f2c3a54418 100644
--- a/apps/e2e/ag-grid-storybook/src/app/ag-grid/ag-grid-stories.component.ts
+++ b/apps/e2e/ag-grid-storybook/src/app/ag-grid/ag-grid-stories.component.ts
@@ -210,7 +210,7 @@ export class AgGridStoriesComponent
// Scroll down to show the back-to-top button.
this.#doc
.querySelector(
- '#back-to-top .sky-ag-grid-row-hunteca01 [col-id="name"]'
+ '#back-to-top .sky-ag-grid-row-johnsra05 [col-id="name"]'
)
.scrollIntoView();
@@ -226,7 +226,7 @@ export class AgGridStoriesComponent
// Trigger validation popover to show up.
this.#doc
.querySelector(
- '#validation [row-index="0"] [col-id="seasons_played"]'
+ '#validation .sky-ag-grid-row-martipe02 [col-id="seasons_played"]'
)
.dispatchEvent(new KeyboardEvent('keyup', { key: 'ArrowUp' }));
diff --git a/apps/e2e/ag-grid-storybook/src/app/ag-grid/ag-grid-stories.module.ts b/apps/e2e/ag-grid-storybook/src/app/ag-grid/ag-grid-stories.module.ts
index 01b554875d..728d8f4513 100644
--- a/apps/e2e/ag-grid-storybook/src/app/ag-grid/ag-grid-stories.module.ts
+++ b/apps/e2e/ag-grid-storybook/src/app/ag-grid/ag-grid-stories.module.ts
@@ -10,6 +10,8 @@ import { SkyThemeModule, SkyThemeService } from '@skyux/theme';
import { AgGridModule } from 'ag-grid-angular';
+import { InlineHelpModule } from '../shared/inline-help/inline-help.module';
+
import { AgGridStoriesComponent } from './ag-grid-stories.component';
import { ContextMenuComponent } from './context-menu.component';
@@ -21,6 +23,7 @@ const routes: Routes = [{ path: '', component: AgGridStoriesComponent }];
RouterModule.forChild(routes),
SkyAgGridModule,
AgGridModule,
+ InlineHelpModule,
SkyDropdownModule,
SkyBackToTopModule,
SkyThemeModule,
diff --git a/apps/e2e/ag-grid-storybook/src/app/data-entry-grid/data-entry-grid.component.ts b/apps/e2e/ag-grid-storybook/src/app/data-entry-grid/data-entry-grid.component.ts
index a37d7f857c..31d2b3e5c3 100644
--- a/apps/e2e/ag-grid-storybook/src/app/data-entry-grid/data-entry-grid.component.ts
+++ b/apps/e2e/ag-grid-storybook/src/app/data-entry-grid/data-entry-grid.component.ts
@@ -20,6 +20,7 @@ import { BehaviorSubject, Observable, Subscription, combineLatest } from 'rxjs';
import { delay, filter, map } from 'rxjs/operators';
import { columnDefinitions, data } from '../shared/baseball-players-data';
+import { InlineHelpComponent } from '../shared/inline-help/inline-help.component';
type DataSet = { id: string; data: any[] };
@@ -130,6 +131,12 @@ export class DataEntryGridComponent
columnDefs = columnDefinitions
.slice(tripleCrownIndex, tripleCrownIndex + 3)
.map((col) => {
+ if (col.field === 'mvp') {
+ col.headerComponentParams = {
+ inlineHelpComponent: InlineHelpComponent,
+ };
+ col.initialSort = 'desc';
+ }
return {
...col,
editable: true,
diff --git a/apps/e2e/ag-grid-storybook/src/app/data-manager/data-manager.module.ts b/apps/e2e/ag-grid-storybook/src/app/data-manager/data-manager.module.ts
index a46f038abd..aad4a801b4 100644
--- a/apps/e2e/ag-grid-storybook/src/app/data-manager/data-manager.module.ts
+++ b/apps/e2e/ag-grid-storybook/src/app/data-manager/data-manager.module.ts
@@ -11,6 +11,8 @@ import { SkyCheckboxModule, SkyRadioModule } from '@skyux/forms';
import { AgGridModule } from 'ag-grid-angular';
+import { InlineHelpModule } from '../shared/inline-help/inline-help.module';
+
import { DataManagerComponent } from './data-manager.component';
const routes: Routes = [{ path: '', component: DataManagerComponent }];
@@ -25,6 +27,7 @@ const routes: Routes = [{ path: '', component: DataManagerComponent }];
SkyRadioModule,
ReactiveFormsModule,
AgGridModule,
+ InlineHelpModule,
],
exports: [DataManagerComponent],
providers: [SkyDataManagerService],
diff --git a/apps/e2e/ag-grid-storybook/src/app/shared/baseball-players-data.ts b/apps/e2e/ag-grid-storybook/src/app/shared/baseball-players-data.ts
index 8b6e8b9a49..1535e234d9 100644
--- a/apps/e2e/ag-grid-storybook/src/app/shared/baseball-players-data.ts
+++ b/apps/e2e/ag-grid-storybook/src/app/shared/baseball-players-data.ts
@@ -2,6 +2,8 @@ import { SkyCellType } from '@skyux/ag-grid';
import { ColDef } from 'ag-grid-community';
+import { InlineHelpComponent } from './inline-help/inline-help.component';
+
export const columnDefinitions: ColDef[] = [
{
field: 'id',
@@ -16,6 +18,10 @@ export const columnDefinitions: ColDef[] = [
sortable: true,
type: SkyCellType.Text,
minWidth: 200,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
+ initialSort: 'asc',
},
{
field: 'birthday',
@@ -24,6 +30,9 @@ export const columnDefinitions: ColDef[] = [
sortable: true,
type: SkyCellType.Date,
minWidth: 300,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
},
...[
['seasons_played', 'Seasons Played'],
diff --git a/apps/e2e/ag-grid-storybook/src/app/shared/inline-help/inline-help.component.html b/apps/e2e/ag-grid-storybook/src/app/shared/inline-help/inline-help.component.html
new file mode 100644
index 0000000000..bd7eeb3e98
--- /dev/null
+++ b/apps/e2e/ag-grid-storybook/src/app/shared/inline-help/inline-help.component.html
@@ -0,0 +1,4 @@
+
diff --git a/apps/e2e/ag-grid-storybook/src/app/shared/inline-help/inline-help.component.ts b/apps/e2e/ag-grid-storybook/src/app/shared/inline-help/inline-help.component.ts
new file mode 100644
index 0000000000..07931e84af
--- /dev/null
+++ b/apps/e2e/ag-grid-storybook/src/app/shared/inline-help/inline-help.component.ts
@@ -0,0 +1,26 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { SkyAgGridHeaderInfo } from '@skyux/ag-grid';
+
+@Component({
+ selector: 'app-inline-help',
+ templateUrl: './inline-help.component.html',
+ styles: [
+ `
+ :host {
+ display: block;
+ }
+ `,
+ ],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class InlineHelpComponent {
+ readonly #displayName: string;
+
+ constructor({ displayName }: SkyAgGridHeaderInfo) {
+ this.#displayName = displayName;
+ }
+
+ public onHelpClick(): void {
+ alert(`Help was clicked for ${this.#displayName}.`);
+ }
+}
diff --git a/apps/e2e/ag-grid-storybook/src/app/shared/inline-help/inline-help.module.ts b/apps/e2e/ag-grid-storybook/src/app/shared/inline-help/inline-help.module.ts
new file mode 100644
index 0000000000..9678f4007f
--- /dev/null
+++ b/apps/e2e/ag-grid-storybook/src/app/shared/inline-help/inline-help.module.ts
@@ -0,0 +1,12 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { SkyHelpInlineModule } from '@skyux/indicators';
+
+import { InlineHelpComponent } from './inline-help.component';
+
+@NgModule({
+ declarations: [InlineHelpComponent],
+ exports: [InlineHelpComponent],
+ imports: [CommonModule, SkyHelpInlineModule],
+})
+export class InlineHelpModule {}
diff --git a/apps/playground/src/app/components/ag-grid/data-manager-large/data-manager-large.component.html b/apps/playground/src/app/components/ag-grid/data-manager-large/data-manager-large.component.html
index 52dbcf88c9..220d4c3a81 100644
--- a/apps/playground/src/app/components/ag-grid/data-manager-large/data-manager-large.component.html
+++ b/apps/playground/src/app/components/ag-grid/data-manager-large/data-manager-large.component.html
@@ -7,6 +7,11 @@
icon="arrows-h"
label="Top scroll"
>
+
{
this.isActive$.next(false);
this.enableTopScroll = value.enableTopScroll;
+ this.useColumnGroups = value.useColumnGroups;
this.domLayout = value.domLayout;
this.applyGridOptions();
setTimeout(() => this.isActive$.next(true));
@@ -126,7 +133,12 @@ export class DataManagerLargeComponent implements OnInit {
private applyGridOptions() {
this.gridOptions = this.agGridService.getGridOptions({
gridOptions: {
- columnDefs: columnDefinitions,
+ defaultColGroupDef: {
+ columnGroupShow: 'open',
+ },
+ columnDefs: this.useColumnGroups
+ ? columnDefinitionsGrouped
+ : columnDefinitions,
columnTypes: {
custom_link: {
cellRendererFramework: CustomLinkComponent,
diff --git a/apps/playground/src/app/components/ag-grid/data-manager-large/data-manager-large.module.ts b/apps/playground/src/app/components/ag-grid/data-manager-large/data-manager-large.module.ts
index 3da59b346c..8c71e4f0cb 100644
--- a/apps/playground/src/app/components/ag-grid/data-manager-large/data-manager-large.module.ts
+++ b/apps/playground/src/app/components/ag-grid/data-manager-large/data-manager-large.module.ts
@@ -8,17 +8,24 @@ import {
SkyDataManagerService,
} from '@skyux/data-manager';
import { SkyCheckboxModule, SkyRadioModule } from '@skyux/forms';
-import { SkyIconModule } from '@skyux/indicators';
+import { SkyHelpInlineModule, SkyIconModule } from '@skyux/indicators';
import { AgGridModule } from 'ag-grid-angular';
import { CustomLinkComponent } from './custom-link/custom-link.component';
import { DataManagerLargeRoutingModule } from './data-manager-large-routing.module';
import { DataManagerLargeComponent } from './data-manager-large.component';
+import { GroupInlineHelpComponent } from './inline-help/group-inline-help.component';
+import { InlineHelpComponent } from './inline-help/inline-help.component';
import { LocalStorageConfigService } from './local-storage-config.service';
@NgModule({
- declarations: [DataManagerLargeComponent, CustomLinkComponent],
+ declarations: [
+ DataManagerLargeComponent,
+ CustomLinkComponent,
+ GroupInlineHelpComponent,
+ InlineHelpComponent,
+ ],
imports: [
AgGridModule,
CommonModule,
@@ -29,6 +36,7 @@ import { LocalStorageConfigService } from './local-storage-config.service';
SkyIconModule,
SkyRadioModule,
ReactiveFormsModule,
+ SkyHelpInlineModule,
],
providers: [
SkyDataManagerService,
diff --git a/apps/playground/src/app/components/ag-grid/data-manager-large/data-set-large.ts b/apps/playground/src/app/components/ag-grid/data-manager-large/data-set-large.ts
index 8fb382944b..c97bf5fffb 100644
--- a/apps/playground/src/app/components/ag-grid/data-manager-large/data-set-large.ts
+++ b/apps/playground/src/app/components/ag-grid/data-manager-large/data-set-large.ts
@@ -1,7 +1,10 @@
// Source: https://github.com/metmuseum/openaccess
import { SkyCellType } from '@skyux/ag-grid';
-import { ColDef } from 'ag-grid-community';
+import { ColDef, ColGroupDef } from 'ag-grid-community';
+
+import { GroupInlineHelpComponent } from './inline-help/group-inline-help.component';
+import { InlineHelpComponent } from './inline-help/inline-help.component';
export const columnDefinitions: ColDef[] = [
{
@@ -14,6 +17,9 @@ export const columnDefinitions: ColDef[] = [
headerName: 'Object Number',
type: [],
sortable: true,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
},
{
field: 'is_highlight',
@@ -32,24 +38,36 @@ export const columnDefinitions: ColDef[] = [
headerName: 'Is Public Domain',
type: [],
sortable: true,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
},
{
field: 'object_id',
headerName: 'Object ID',
type: [],
sortable: true,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
},
{
field: 'gallery_number',
headerName: 'Gallery Number',
type: [],
sortable: true,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
},
{
field: 'department',
headerName: 'Department',
type: [],
sortable: true,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
},
{
field: 'accessionyear',
@@ -62,12 +80,18 @@ export const columnDefinitions: ColDef[] = [
headerName: 'Object Name',
type: [],
sortable: true,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
},
{
field: 'title',
headerName: 'Title',
type: [],
sortable: true,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
},
{
field: 'culture',
@@ -122,12 +146,18 @@ export const columnDefinitions: ColDef[] = [
headerName: 'Artist Display Name',
type: [],
sortable: true,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
},
{
field: 'artist_display_bio',
headerName: 'Artist Display Bio',
type: [],
sortable: true,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
},
{
field: 'artist_suffix',
@@ -182,6 +212,9 @@ export const columnDefinitions: ColDef[] = [
headerName: 'Object Date',
type: [],
sortable: true,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
},
{
field: 'object_begin_date',
@@ -302,6 +335,9 @@ export const columnDefinitions: ColDef[] = [
headerName: 'Object Wikidata URL',
type: ['custom_link'],
sortable: true,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
},
{
field: 'metadata_date',
@@ -335,6 +371,237 @@ export const columnDefinitions: ColDef[] = [
},
];
+export const columnDefinitionsGrouped: ColGroupDef[] = [
+ {
+ headerName: 'Object Information',
+ headerGroupComponentParams: {
+ inlineHelpComponent: GroupInlineHelpComponent,
+ },
+ children: [
+ {
+ field: 'object_name',
+ headerName: 'Object Name',
+ type: [],
+ sortable: true,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
+ },
+ {
+ field: 'department',
+ headerName: 'Department',
+ type: [],
+ sortable: true,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
+ },
+ {
+ field: 'is_public_domain',
+ headerName: 'Is Public Domain',
+ type: [],
+ sortable: true,
+ columnGroupShow: 'open',
+ },
+ ],
+ },
+ {
+ headerName: 'Titular Information',
+ headerGroupComponentParams: {
+ inlineHelpComponent: GroupInlineHelpComponent,
+ },
+ children: [
+ {
+ field: 'title',
+ headerName: 'Title',
+ type: [],
+ sortable: true,
+ },
+ {
+ field: 'culture',
+ headerName: 'Culture',
+ type: [],
+ sortable: true,
+ columnGroupShow: 'open',
+ },
+ {
+ field: 'period',
+ headerName: 'Period',
+ type: [],
+ sortable: true,
+ columnGroupShow: 'open',
+ },
+ ],
+ },
+ {
+ headerName: 'Artist',
+ children: [
+ {
+ field: 'artist_role',
+ headerName: 'Artist Role',
+ type: [],
+ sortable: true,
+ },
+ {
+ field: 'artist_display_name',
+ headerName: 'Artist Display Name',
+ type: [],
+ sortable: true,
+ },
+ {
+ field: 'artist_display_bio',
+ headerName: 'Artist Display Bio',
+ type: [],
+ sortable: true,
+ columnGroupShow: 'open',
+ },
+ {
+ field: 'artist_suffix',
+ headerName: 'Artist Suffix',
+ type: [],
+ sortable: true,
+ columnGroupShow: 'open',
+ },
+ {
+ field: 'artist_nationality',
+ headerName: 'Artist Nationality',
+ type: [],
+ sortable: true,
+ columnGroupShow: 'open',
+ },
+ {
+ field: 'artist_wikidata_url',
+ headerName: 'Artist Wikidata URL',
+ type: ['custom_link'],
+ sortable: true,
+ columnGroupShow: 'open',
+ },
+ ],
+ },
+ {
+ headerName: 'Collection',
+ children: [
+ {
+ field: 'object_date',
+ headerName: 'Object Date',
+ type: [],
+ sortable: true,
+ },
+ {
+ field: 'object_begin_date',
+ headerName: 'Object Begin Date',
+ type: [],
+ sortable: true,
+ },
+ {
+ field: 'object_end_date',
+ headerName: 'Object End Date',
+ type: [],
+ sortable: true,
+ columnGroupShow: 'open',
+ },
+ {
+ field: 'medium',
+ headerName: 'Medium',
+ type: [],
+ sortable: true,
+ columnGroupShow: 'open',
+ },
+ {
+ field: 'dimensions',
+ headerName: 'Dimensions',
+ type: [],
+ sortable: true,
+ columnGroupShow: 'open',
+ },
+ ],
+ },
+ {
+ headerName: 'Geography & Classification',
+ children: [
+ {
+ field: 'geography_type',
+ headerName: 'Geography Type',
+ type: [],
+ sortable: true,
+ },
+ {
+ field: 'city',
+ headerName: 'City',
+ type: [],
+ sortable: true,
+ },
+ {
+ field: 'state',
+ headerName: 'State',
+ type: [],
+ sortable: true,
+ columnGroupShow: 'open',
+ },
+ {
+ field: 'county',
+ headerName: 'County',
+ type: [],
+ sortable: true,
+ columnGroupShow: 'open',
+ },
+ {
+ field: 'country',
+ headerName: 'Country',
+ type: [],
+ sortable: true,
+ columnGroupShow: 'open',
+ },
+ ],
+ },
+ {
+ headerName: 'Metadata',
+ children: [
+ {
+ field: 'classification',
+ headerName: 'Classification',
+ type: [],
+ sortable: true,
+ },
+ {
+ field: 'rights_and_reproduction',
+ headerName: 'Rights and Reproduction',
+ type: [],
+ sortable: true,
+ columnGroupShow: 'open',
+ },
+ {
+ field: 'link_resource',
+ headerName: 'Link Resource',
+ type: ['custom_link'],
+ sortable: true,
+ columnGroupShow: 'open',
+ },
+ {
+ field: 'object_wikidata_url',
+ headerName: 'Object Wikidata URL',
+ type: ['custom_link'],
+ sortable: true,
+ columnGroupShow: 'open',
+ },
+ {
+ field: 'metadata_date',
+ headerName: 'Metadata Date',
+ type: [],
+ sortable: true,
+ columnGroupShow: 'open',
+ },
+ {
+ field: 'tags_wikidata_url',
+ headerName: 'Tags Wikidata URL',
+ type: ['custom_link'],
+ sortable: true,
+ columnGroupShow: 'open',
+ },
+ ],
+ },
+];
+
export const data = [
{
object_number: '24.109.38a\u2013c',
diff --git a/apps/playground/src/app/components/ag-grid/data-manager-large/inline-help/group-inline-help.component.html b/apps/playground/src/app/components/ag-grid/data-manager-large/inline-help/group-inline-help.component.html
new file mode 100644
index 0000000000..bd7eeb3e98
--- /dev/null
+++ b/apps/playground/src/app/components/ag-grid/data-manager-large/inline-help/group-inline-help.component.html
@@ -0,0 +1,4 @@
+
diff --git a/apps/playground/src/app/components/ag-grid/data-manager-large/inline-help/group-inline-help.component.ts b/apps/playground/src/app/components/ag-grid/data-manager-large/inline-help/group-inline-help.component.ts
new file mode 100644
index 0000000000..e025a97fde
--- /dev/null
+++ b/apps/playground/src/app/components/ag-grid/data-manager-large/inline-help/group-inline-help.component.ts
@@ -0,0 +1,22 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { SkyAgGridHeaderGroupInfo } from '@skyux/ag-grid';
+
+@Component({
+ selector: 'app-group-inline-help',
+ templateUrl: './group-inline-help.component.html',
+ styles: [
+ `
+ :host {
+ display: block;
+ }
+ `,
+ ],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class GroupInlineHelpComponent {
+ constructor(public info: SkyAgGridHeaderGroupInfo) {}
+
+ public onHelpClick(): void {
+ console.log(`Help was clicked for ${this.info.displayName}.`);
+ }
+}
diff --git a/apps/playground/src/app/components/ag-grid/data-manager-large/inline-help/inline-help.component.html b/apps/playground/src/app/components/ag-grid/data-manager-large/inline-help/inline-help.component.html
new file mode 100644
index 0000000000..bd7eeb3e98
--- /dev/null
+++ b/apps/playground/src/app/components/ag-grid/data-manager-large/inline-help/inline-help.component.html
@@ -0,0 +1,4 @@
+
diff --git a/apps/playground/src/app/components/ag-grid/data-manager-large/inline-help/inline-help.component.ts b/apps/playground/src/app/components/ag-grid/data-manager-large/inline-help/inline-help.component.ts
new file mode 100644
index 0000000000..b8c2ccc58b
--- /dev/null
+++ b/apps/playground/src/app/components/ag-grid/data-manager-large/inline-help/inline-help.component.ts
@@ -0,0 +1,22 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { SkyAgGridHeaderInfo } from '@skyux/ag-grid';
+
+@Component({
+ selector: 'app-inline-help',
+ templateUrl: './inline-help.component.html',
+ styles: [
+ `
+ :host {
+ display: block;
+ }
+ `,
+ ],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class InlineHelpComponent {
+ constructor(public info: SkyAgGridHeaderInfo) {}
+
+ public onHelpClick(): void {
+ console.log(`Help was clicked for ${this.info.displayName}.`);
+ }
+}
diff --git a/apps/playground/src/app/components/ag-grid/edit-complex-cells/edit-complex-cells.component.ts b/apps/playground/src/app/components/ag-grid/edit-complex-cells/edit-complex-cells.component.ts
index 7b3084d0fd..a249140670 100644
--- a/apps/playground/src/app/components/ag-grid/edit-complex-cells/edit-complex-cells.component.ts
+++ b/apps/playground/src/app/components/ag-grid/edit-complex-cells/edit-complex-cells.component.ts
@@ -35,6 +35,7 @@ import {
EditableGridOption,
EditableGridRow,
} from './edit-complex-cells-data';
+import { InlineHelpComponent } from './inline-help/inline-help.component';
@Component({
selector: 'app-edit-complex-cells-visual',
@@ -92,6 +93,9 @@ export class EditComplexCellsComponent implements OnInit {
minWidth: 220,
editable: this.editMode,
type: SkyCellType.Text,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
},
{
colId: 'language',
@@ -103,6 +107,9 @@ export class EditComplexCellsComponent implements OnInit {
values: ['English', 'Spanish', 'French', 'Portuguese', '(other)'],
},
editable: this.editMode,
+ headerComponentParams: {
+ inlineHelpComponent: InlineHelpComponent,
+ },
},
{
colId: 'validationAutocomplete',
@@ -122,6 +129,8 @@ export class EditComplexCellsComponent implements OnInit {
validatorMessage: 'Please choose an odd number option',
},
},
+ sortable: true,
+ filter: true,
},
{
colId: 'validationCurrency',
@@ -130,6 +139,7 @@ export class EditComplexCellsComponent implements OnInit {
maxWidth: 235,
editable: this.editMode,
type: [SkyCellType.CurrencyValidator],
+ sortable: true,
},
{
colId: 'validationDate',
@@ -145,6 +155,7 @@ export class EditComplexCellsComponent implements OnInit {
validatorMessage: 'Please enter a future date',
},
},
+ sortable: true,
},
{
colId: 'lookupSingle',
diff --git a/apps/playground/src/app/components/ag-grid/edit-complex-cells/edit-complex-cells.module.ts b/apps/playground/src/app/components/ag-grid/edit-complex-cells/edit-complex-cells.module.ts
index 3023ccb6b9..b000ab9233 100644
--- a/apps/playground/src/app/components/ag-grid/edit-complex-cells/edit-complex-cells.module.ts
+++ b/apps/playground/src/app/components/ag-grid/edit-complex-cells/edit-complex-cells.module.ts
@@ -1,6 +1,7 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { SkyAgGridModule } from '@skyux/ag-grid';
+import { SkyHelpInlineModule } from '@skyux/indicators';
import { SkyToolbarModule } from '@skyux/layout';
import { AgGridModule } from 'ag-grid-angular';
@@ -8,9 +9,10 @@ import { AgGridModule } from 'ag-grid-angular';
import { CustomMultilineModule } from './custom-multiline/custom-multiline.module';
import { EditComplexCellsRoutingModule } from './edit-complex-cells-routing.module';
import { EditComplexCellsComponent } from './edit-complex-cells.component';
+import { InlineHelpComponent } from './inline-help/inline-help.component';
@NgModule({
- declarations: [EditComplexCellsComponent],
+ declarations: [EditComplexCellsComponent, InlineHelpComponent],
imports: [
AgGridModule,
CommonModule,
@@ -18,6 +20,7 @@ import { EditComplexCellsComponent } from './edit-complex-cells.component';
EditComplexCellsRoutingModule,
SkyAgGridModule,
SkyToolbarModule,
+ SkyHelpInlineModule,
],
})
export class EditComplexCellsModule {
diff --git a/apps/playground/src/app/components/ag-grid/edit-complex-cells/inline-help/inline-help.component.html b/apps/playground/src/app/components/ag-grid/edit-complex-cells/inline-help/inline-help.component.html
new file mode 100644
index 0000000000..bd7eeb3e98
--- /dev/null
+++ b/apps/playground/src/app/components/ag-grid/edit-complex-cells/inline-help/inline-help.component.html
@@ -0,0 +1,4 @@
+
diff --git a/apps/playground/src/app/components/ag-grid/edit-complex-cells/inline-help/inline-help.component.ts b/apps/playground/src/app/components/ag-grid/edit-complex-cells/inline-help/inline-help.component.ts
new file mode 100644
index 0000000000..7190e40433
--- /dev/null
+++ b/apps/playground/src/app/components/ag-grid/edit-complex-cells/inline-help/inline-help.component.ts
@@ -0,0 +1,19 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+
+@Component({
+ selector: 'app-inline-help',
+ templateUrl: './inline-help.component.html',
+ styles: [
+ `
+ :host {
+ display: block;
+ }
+ `,
+ ],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class InlineHelpComponent {
+ public onHelpClick(): void {
+ console.log(`Help was clicked.`);
+ }
+}
diff --git a/libs/components/ag-grid/src/assets/locales/resources_en_US.json b/libs/components/ag-grid/src/assets/locales/resources_en_US.json
index 149d0edde6..23d190c3e6 100644
--- a/libs/components/ag-grid/src/assets/locales/resources_en_US.json
+++ b/libs/components/ag-grid/src/assets/locales/resources_en_US.json
@@ -30,5 +30,13 @@
"sky_ag_grid_cell_editor_currency_aria_label": {
"_description": "aria label for the currency cell editor",
"message": "Editable currency {0} for row {1}"
+ },
+ "sky_ag_grid_column_group_header_expand_aria_label": {
+ "_description": "aria label for the expand column group header button",
+ "message": "Expand column group {0}"
+ },
+ "sky_ag_grid_column_group_header_collapse_aria_label": {
+ "_description": "aria label for the collapse column group header button",
+ "message": "Collapse column group {0}"
}
}
diff --git a/libs/components/ag-grid/src/index.ts b/libs/components/ag-grid/src/index.ts
index f8bedf2377..ecf08ad788 100644
--- a/libs/components/ag-grid/src/index.ts
+++ b/libs/components/ag-grid/src/index.ts
@@ -11,6 +11,10 @@ export * from './lib/modules/ag-grid/types/cell-type';
export * from './lib/modules/ag-grid/types/currency-properties';
export * from './lib/modules/ag-grid/types/datepicker-properties';
export * from './lib/modules/ag-grid/types/header-class';
+export * from './lib/modules/ag-grid/types/header-group-info';
+export * from './lib/modules/ag-grid/types/header-group-params';
+export * from './lib/modules/ag-grid/types/header-info';
+export * from './lib/modules/ag-grid/types/header-params';
export * from './lib/modules/ag-grid/types/lookup-properties';
export * from './lib/modules/ag-grid/types/number-properties';
export * from './lib/modules/ag-grid/types/sky-grid-options';
@@ -35,3 +39,5 @@ export { SkyAgGridRowDeleteDirective as λ13 } from './lib/modules/ag-grid/ag-gr
export { SkyAgGridDataManagerAdapterDirective as λ14 } from './lib/modules/ag-grid/ag-grid-data-manager-adapter.directive';
export { SkyAgGridCellEditorLookupComponent as λ15 } from './lib/modules/ag-grid/cell-editors/cell-editor-lookup/cell-editor-lookup.component';
export { SkyAgGridCellRendererLookupComponent as λ16 } from './lib/modules/ag-grid/cell-renderers/cell-renderer-lookup/cell-renderer-lookup.component';
+export { SkyAgGridHeaderComponent as λ17 } from './lib/modules/ag-grid/header/header.component';
+export { SkyAgGridHeaderGroupComponent as λ18 } from './lib/modules/ag-grid/header/header-group.component';
diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/ag-grid-wrapper.component.spec.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/ag-grid-wrapper.component.spec.ts
index 5ecfee3d9d..90b76fce19 100644
--- a/libs/components/ag-grid/src/lib/modules/ag-grid/ag-grid-wrapper.component.spec.ts
+++ b/libs/components/ag-grid/src/lib/modules/ag-grid/ag-grid-wrapper.component.spec.ts
@@ -15,11 +15,12 @@ import { Subject } from 'rxjs';
import { SkyAgGridAdapterService } from './ag-grid-adapter.service';
import { SkyAgGridWrapperComponent } from './ag-grid-wrapper.component';
-import { SkyAgGridModule } from './ag-grid.module';
import {
EnableTopScroll,
SkyAgGridFixtureComponent,
} from './fixtures/ag-grid.component.fixture';
+import { SkyAgGridFixtureModule } from './fixtures/ag-grid.module.fixture';
+import { SecondInlineHelpComponent } from './fixtures/inline-help.component';
describe('SkyAgGridWrapperComponent', () => {
let gridAdapterService: SkyAgGridAdapterService;
@@ -37,7 +38,7 @@ describe('SkyAgGridWrapperComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
- imports: [SkyAgGridModule],
+ imports: [SkyAgGridFixtureModule],
});
gridWrapperFixture = TestBed.createComponent(SkyAgGridWrapperComponent);
@@ -282,7 +283,7 @@ describe('SkyAgGridWrapperComponent via fixture', () => {
it('should move the horizontal scroll based on enableTopScroll check, static data', async () => {
TestBed.configureTestingModule({
- imports: [SkyAgGridModule],
+ imports: [SkyAgGridFixtureModule],
providers: [
{
provide: EnableTopScroll,
@@ -309,7 +310,7 @@ describe('SkyAgGridWrapperComponent via fixture', () => {
it('should move the horizontal scroll based on enableTopScroll check, async loading', async () => {
TestBed.configureTestingModule({
- imports: [SkyAgGridModule],
+ imports: [SkyAgGridFixtureModule],
});
gridWrapperFixture = TestBed.createComponent(SkyAgGridFixtureComponent);
gridWrapperNativeElement = gridWrapperFixture.nativeElement;
@@ -357,4 +358,80 @@ describe('SkyAgGridWrapperComponent via fixture', () => {
'ag-overlay',
]);
});
+
+ it('should show inline help', async () => {
+ TestBed.configureTestingModule({
+ imports: [SkyAgGridFixtureModule],
+ });
+ gridWrapperFixture = TestBed.createComponent(SkyAgGridFixtureComponent);
+ gridWrapperNativeElement = gridWrapperFixture.nativeElement;
+
+ gridWrapperFixture.detectChanges();
+ await gridWrapperFixture.whenStable();
+
+ expect(
+ gridWrapperNativeElement.querySelector(
+ `[col-id="name"] .sky-control-help`
+ )
+ ).toBeTruthy();
+ expect(
+ gridWrapperNativeElement.querySelector(
+ `[col-id="value"] .sky-control-help`
+ )
+ ).toBeTruthy();
+ expect(
+ gridWrapperNativeElement
+ .querySelector(`[col-id="value"] .sky-control-help`)
+ .getAttribute('title')
+ ).toEqual('Current Value help');
+
+ gridWrapperFixture.componentInstance.agGrid.api.setColumnDefs([
+ ...gridWrapperFixture.componentInstance.columnDefs.map((col) => {
+ switch (col.field) {
+ case 'name':
+ return {
+ ...col,
+ headerComponentParams: {
+ ...col.headerComponentParams,
+ inlineHelpComponent: undefined,
+ },
+ };
+ case 'value':
+ return {
+ ...col,
+ headerComponentParams: {
+ ...col.headerComponentParams,
+ inlineHelpComponent: SecondInlineHelpComponent,
+ },
+ };
+ case 'target':
+ return {
+ ...col,
+ hide: true,
+ };
+ default:
+ return col;
+ }
+ }),
+ ]);
+ gridWrapperFixture.detectChanges();
+ await gridWrapperFixture.whenStable();
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+
+ expect(
+ gridWrapperNativeElement.querySelector(
+ `[col-id="name"] .sky-control-help`
+ )
+ ).toBeFalsy();
+ expect(
+ gridWrapperNativeElement.querySelector(
+ `[col-id="value"] .sky-control-help`
+ )
+ ).toBeTruthy();
+ expect(
+ gridWrapperNativeElement
+ .querySelector(`[col-id="value"] .sky-control-help`)
+ .getAttribute('title')
+ ).toEqual('Current Value help replaced');
+ });
});
diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/ag-grid.module.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/ag-grid.module.ts
index 66ec06b369..e15ded1e81 100644
--- a/libs/components/ag-grid/src/lib/modules/ag-grid/ag-grid.module.ts
+++ b/libs/components/ag-grid/src/lib/modules/ag-grid/ag-grid.module.ts
@@ -2,7 +2,10 @@ import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { SkyViewkeeperModule } from '@skyux/core';
import { SkyDataManagerModule } from '@skyux/data-manager';
+import { SkyI18nModule } from '@skyux/i18n';
+import { SkyIconModule } from '@skyux/indicators';
import { SkyInlineDeleteModule } from '@skyux/layout';
+import { SkyThemeModule } from '@skyux/theme';
import { AgGridModule } from 'ag-grid-angular';
@@ -21,10 +24,14 @@ import { SkyAgGridCellRendererLookupModule } from './cell-renderers/cell-rendere
import { SkyAgGridCellRendererRowSelectorModule } from './cell-renderers/cell-renderer-row-selector/cell-renderer-row-selector.module';
import { SkyAgGridCellRendererValidatorTooltipModule } from './cell-renderers/cell-renderer-validator-tooltip/cell-renderer-validator-tooltip.module';
import { SkyAgGridCellValidatorModule } from './cell-validator/ag-grid-cell-validator.module';
+import { SkyAgGridHeaderGroupComponent } from './header/header-group.component';
+import { SkyAgGridHeaderComponent } from './header/header.component';
@NgModule({
declarations: [
SkyAgGridDataManagerAdapterDirective,
+ SkyAgGridHeaderComponent,
+ SkyAgGridHeaderGroupComponent,
SkyAgGridRowDeleteComponent,
SkyAgGridRowDeleteDirective,
SkyAgGridWrapperComponent,
@@ -44,14 +51,19 @@ import { SkyAgGridCellValidatorModule } from './cell-validator/ag-grid-cell-vali
SkyAgGridCellValidatorModule,
SkyAgGridCellEditorTextModule,
SkyDataManagerModule,
+ SkyI18nModule,
+ SkyIconModule,
SkyInlineDeleteModule,
SkyViewkeeperModule,
+ SkyThemeModule,
],
exports: [
SkyAgGridDataManagerAdapterDirective,
SkyAgGridRowDeleteComponent,
SkyAgGridRowDeleteDirective,
SkyAgGridWrapperComponent,
+ SkyAgGridHeaderComponent,
+ SkyAgGridHeaderGroupComponent,
],
})
export class SkyAgGridModule {}
diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/ag-grid.service.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/ag-grid.service.ts
index d982d45299..f2ad91abd3 100644
--- a/libs/components/ag-grid/src/lib/modules/ag-grid/ag-grid.service.ts
+++ b/libs/components/ag-grid/src/lib/modules/ag-grid/ag-grid.service.ts
@@ -27,6 +27,8 @@ import { SkyAgGridCellRendererCurrencyComponent } from './cell-renderers/cell-re
import { SkyAgGridCellRendererLookupComponent } from './cell-renderers/cell-renderer-lookup/cell-renderer-lookup.component';
import { SkyAgGridCellRendererRowSelectorComponent } from './cell-renderers/cell-renderer-row-selector/cell-renderer-row-selector.component';
import { SkyAgGridCellRendererValidatorTooltipComponent } from './cell-renderers/cell-renderer-validator-tooltip/cell-renderer-validator-tooltip.component';
+import { SkyAgGridHeaderGroupComponent } from './header/header-group.component';
+import { SkyAgGridHeaderComponent } from './header/header.component';
import { SkyCellClass } from './types/cell-class';
import { SkyCellType } from './types/cell-type';
import { SkyHeaderClass } from './types/header-class';
@@ -183,7 +185,7 @@ export class SkyAgGridService implements OnDestroy {
defaultGridOptions: GridOptions,
providedGridOptions: GridOptions
): GridOptions {
- const mergedGridOptions = {
+ const mergedGridOptions: GridOptions = {
...defaultGridOptions,
...providedGridOptions,
components: {
@@ -202,6 +204,10 @@ export class SkyAgGridService implements OnDestroy {
// allow consumers to override all defaultColDef properties except cellClassRules, which we reserve for styling
cellClassRules: defaultGridOptions.defaultColDef.cellClassRules,
},
+ defaultColGroupDef: {
+ ...defaultGridOptions.defaultColGroupDef,
+ ...providedGridOptions.defaultColGroupDef,
+ },
icons: {
...defaultGridOptions.icons,
...providedGridOptions.icons,
@@ -366,12 +372,16 @@ export class SkyAgGridService implements OnDestroy {
},
defaultColDef: {
cellClassRules: editableCellClassRules,
+ headerComponent: SkyAgGridHeaderComponent,
minWidth: 100,
resizable: true,
sortable: true,
suppressKeyboardEvent: (keypress: SuppressKeyboardEventParams) =>
this.suppressTab(keypress),
},
+ defaultColGroupDef: {
+ headerGroupComponent: SkyAgGridHeaderGroupComponent,
+ },
domLayout: 'autoHeight',
enterMovesDownAfterEdit: true,
components: {
diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/fixtures/ag-grid.component.fixture.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/fixtures/ag-grid.component.fixture.ts
index ff3887f02d..e5f7b27719 100644
--- a/libs/components/ag-grid/src/lib/modules/ag-grid/fixtures/ag-grid.component.fixture.ts
+++ b/libs/components/ag-grid/src/lib/modules/ag-grid/fixtures/ag-grid.component.fixture.ts
@@ -9,12 +9,13 @@ import {
} from '@angular/core';
import { AgGridAngular } from 'ag-grid-angular';
-import { GridOptions } from 'ag-grid-community';
+import { ColDef, GridOptions } from 'ag-grid-community';
import { SkyAgGridService } from '../ag-grid.service';
import { SkyCellType } from '../types/cell-type';
import { SKY_AG_GRID_DATA, SKY_AG_GRID_LOOKUP } from './ag-grid-data.fixture';
+import { FirstInlineHelpComponent } from './inline-help.component';
export const EnableTopScroll = new InjectionToken('EnableTopScroll');
@@ -28,7 +29,7 @@ export class SkyAgGridFixtureComponent implements OnInit {
public agGrid: AgGridAngular;
public gridData = SKY_AG_GRID_DATA;
- public columnDefs = [
+ public columnDefs: ColDef[] = [
{
field: 'selected',
headerName: '',
@@ -39,6 +40,9 @@ export class SkyAgGridFixtureComponent implements OnInit {
{
field: 'name',
headerName: 'First Name',
+ headerComponentParams: {
+ inlineHelpComponent: FirstInlineHelpComponent,
+ },
},
{
field: 'nickname',
@@ -51,35 +55,53 @@ export class SkyAgGridFixtureComponent implements OnInit {
headerName: 'Current Value',
editable: true,
type: SkyCellType.Number,
+ headerComponentParams: {
+ inlineHelpComponent: FirstInlineHelpComponent,
+ },
},
{
field: 'target',
headerName: 'Goal',
type: SkyCellType.Number,
+ headerComponentParams: {
+ inlineHelpComponent: FirstInlineHelpComponent,
+ },
},
{
field: 'date',
headerName: 'Completed Date',
editable: true,
type: SkyCellType.Date,
+ headerComponentParams: {
+ inlineHelpComponent: FirstInlineHelpComponent,
+ },
},
{
field: 'currency',
headerName: 'Currency amount',
editable: true,
type: SkyCellType.Currency,
+ headerComponentParams: {
+ inlineHelpComponent: FirstInlineHelpComponent,
+ },
},
{
field: 'validNumber',
headerName: 'Valid number',
editable: true,
type: SkyCellType.NumberValidator,
+ headerComponentParams: {
+ inlineHelpComponent: FirstInlineHelpComponent,
+ },
},
{
field: 'validCurrency',
headerName: 'Valid currency',
editable: true,
type: SkyCellType.Currency,
+ headerComponentParams: {
+ inlineHelpComponent: FirstInlineHelpComponent,
+ },
},
{
field: 'validDate',
@@ -95,6 +117,9 @@ export class SkyAgGridFixtureComponent implements OnInit {
validatorMessage: 'Please enter a future date',
},
},
+ headerComponentParams: {
+ inlineHelpComponent: FirstInlineHelpComponent,
+ },
},
{
colId: 'lookupSingle',
@@ -116,6 +141,9 @@ export class SkyAgGridFixtureComponent implements OnInit {
descriptorProperty: 'name',
},
},
+ headerComponentParams: {
+ inlineHelpComponent: FirstInlineHelpComponent,
+ },
},
{
colId: 'lookupMultiple',
@@ -138,6 +166,9 @@ export class SkyAgGridFixtureComponent implements OnInit {
descriptorProperty: 'name',
},
},
+ headerComponentParams: {
+ inlineHelpComponent: FirstInlineHelpComponent,
+ },
},
];
diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/fixtures/ag-grid.module.fixture.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/fixtures/ag-grid.module.fixture.ts
index fb67584316..147b2929d7 100644
--- a/libs/components/ag-grid/src/lib/modules/ag-grid/fixtures/ag-grid.module.fixture.ts
+++ b/libs/components/ag-grid/src/lib/modules/ag-grid/fixtures/ag-grid.module.fixture.ts
@@ -13,6 +13,10 @@ import { SkyAgGridCellValidatorTooltipFixtureComponent } from './ag-grid-cell-va
import { SkyAgGridDataManagerFixtureComponent } from './ag-grid-data-manager.component.fixture';
import { SkyAgGridRowDeleteFixtureComponent } from './ag-grid-row-delete.component.fixture';
import { SkyAgGridFixtureComponent } from './ag-grid.component.fixture';
+import {
+ FirstInlineHelpComponent,
+ SecondInlineHelpComponent,
+} from './inline-help.component';
@NgModule({
imports: [
@@ -29,12 +33,16 @@ import { SkyAgGridFixtureComponent } from './ag-grid.component.fixture';
SkyAgGridFixtureComponent,
SkyAgGridRowDeleteFixtureComponent,
SkyAgGridCellValidatorTooltipFixtureComponent,
+ FirstInlineHelpComponent,
+ SecondInlineHelpComponent,
],
exports: [
SkyAgGridDataManagerFixtureComponent,
SkyAgGridFixtureComponent,
SkyAgGridRowDeleteFixtureComponent,
SkyAgGridCellValidatorTooltipFixtureComponent,
+ FirstInlineHelpComponent,
+ SecondInlineHelpComponent,
],
})
export class SkyAgGridFixtureModule {}
diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/fixtures/inline-help.component.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/fixtures/inline-help.component.ts
new file mode 100644
index 0000000000..d0b70354eb
--- /dev/null
+++ b/libs/components/ag-grid/src/lib/modules/ag-grid/fixtures/inline-help.component.ts
@@ -0,0 +1,34 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { SkyAgGridHeaderInfo } from '@skyux/ag-grid';
+
+@Component({
+ selector: 'app-first-inline-help',
+ template: `
+ ℹ︎
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class FirstInlineHelpComponent {
+ public readonly displayName: string;
+
+ constructor({ displayName }: SkyAgGridHeaderInfo) {
+ this.displayName = displayName;
+ }
+}
+
+@Component({
+ selector: 'app-second-inline-help',
+ template: `
+ ℹ︎
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class SecondInlineHelpComponent {
+ public readonly displayName: string;
+
+ constructor({ displayName }: SkyAgGridHeaderInfo) {
+ this.displayName = displayName;
+ }
+}
diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/header/header-group.component.html b/libs/components/ag-grid/src/lib/modules/ag-grid/header/header-group.component.html
new file mode 100644
index 0000000000..1f7a784b3d
--- /dev/null
+++ b/libs/components/ag-grid/src/lib/modules/ag-grid/header/header-group.component.html
@@ -0,0 +1,37 @@
+
+
+
+
+
+
diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/header/header-group.component.scss b/libs/components/ag-grid/src/lib/modules/ag-grid/header/header-group.component.scss
new file mode 100644
index 0000000000..0e75946156
--- /dev/null
+++ b/libs/components/ag-grid/src/lib/modules/ag-grid/header/header-group.component.scss
@@ -0,0 +1,22 @@
+:host {
+ display: flex;
+ max-width: 100%;
+ padding-right: 12px;
+ padding-left: 12px;
+ align-items: center;
+ align-content: center;
+}
+
+.header-group-text {
+ flex-grow: 0;
+ flex-shrink: 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+button {
+ cursor: pointer;
+ margin-left: var(--sky-margin-inline-sm);
+ flex-grow: 0;
+ flex-shrink: 0;
+}
diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/header/header-group.component.spec.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/header/header-group.component.spec.ts
new file mode 100644
index 0000000000..00be84c139
--- /dev/null
+++ b/libs/components/ag-grid/src/lib/modules/ag-grid/header/header-group.component.spec.ts
@@ -0,0 +1,132 @@
+import { Component } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
+import { SkyAgGridHeaderGroupParams } from '@skyux/ag-grid';
+import { SkyI18nModule } from '@skyux/i18n';
+import { SkyIconModule } from '@skyux/indicators';
+import { SkyThemeModule } from '@skyux/theme';
+
+import {
+ ColGroupDef,
+ ColumnGroup,
+ Events,
+ ProvidedColumnGroup,
+} from 'ag-grid-community';
+
+import { SkyAgGridHeaderGroupComponent } from './header-group.component';
+
+@Component({
+ template: `Help text`,
+})
+class TestHelpComponent {}
+
+type mockEventParam = { columnGroup: ProvidedColumnGroup };
+
+describe('SkyAgGridHeaderGroupComponent', () => {
+ let component: SkyAgGridHeaderGroupComponent;
+ let fixture: ComponentFixture;
+ let events: { [key: string]: ((value: mockEventParam) => void)[] };
+ let expanded: boolean;
+ let providedColumnGroup: ProvidedColumnGroup;
+ const baseProvidedColumnGroup = {
+ isExpanded: () => expanded,
+ isExpandable: () => true,
+ };
+ const baseParams = {
+ displayName: 'Test Column',
+ api: {
+ addEventListener: (
+ eventType: string,
+ listener: (value: mockEventParam) => void
+ ) => {
+ events[eventType] = events[eventType] || [];
+ events[eventType].push(listener);
+ },
+ removeEventListener: (
+ eventType: string,
+ listener: (value: mockEventParam) => void
+ ) => {
+ events[eventType] = events[eventType] || [];
+ events[eventType] = events[eventType].filter((l) => l !== listener);
+ },
+ },
+ columnGroup: {
+ getProvidedColumnGroup: () => providedColumnGroup,
+ },
+ setExpanded: (open: boolean) => {
+ expanded = open;
+ (events[Events.EVENT_COLUMN_GROUP_OPENED] || []).forEach((l) =>
+ l({ columnGroup: providedColumnGroup })
+ );
+ },
+ } as unknown as SkyAgGridHeaderGroupParams;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ declarations: [SkyAgGridHeaderGroupComponent, TestHelpComponent],
+ imports: [SkyI18nModule, SkyIconModule, SkyThemeModule],
+ providers: [],
+ });
+ events = {};
+ expanded = false;
+ providedColumnGroup = {
+ ...baseProvidedColumnGroup,
+ } as unknown as ProvidedColumnGroup;
+
+ fixture = TestBed.createComponent(SkyAgGridHeaderGroupComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', async () => {
+ expect(component).toBeTruthy();
+ component.agInit(undefined);
+ fixture.detectChanges();
+ await fixture.whenStable();
+ expect(
+ fixture.debugElement.query(By.css('.header-group-text')).properties[
+ 'innerText'
+ ]
+ ).toBeFalsy();
+ providedColumnGroup = {
+ ...baseProvidedColumnGroup,
+ isExpandable: () => false,
+ } as unknown as ProvidedColumnGroup;
+ component.agInit({
+ ...baseParams,
+ columnGroup: {
+ ...baseParams.columnGroup,
+ getColGroupDef: () =>
+ ({
+ headerGroupComponent: undefined,
+ } as unknown as ColGroupDef),
+ } as unknown as ColumnGroup,
+ });
+ });
+
+ it('should expand and collapse', async () => {
+ component.agInit({
+ ...baseParams,
+ columnGroup: {
+ ...baseParams.columnGroup,
+ getColGroupDef: () =>
+ ({
+ headerGroupComponent: SkyAgGridHeaderGroupComponent,
+ headerGroupComponentParams: {
+ inlineHelpComponent: TestHelpComponent,
+ },
+ } as ColGroupDef),
+ } as unknown as ColumnGroup,
+ });
+ component.ngAfterViewInit();
+ fixture.detectChanges();
+ await fixture.whenStable();
+ expect(
+ fixture.debugElement.query(By.css('.test-help-component'))
+ ).toBeTruthy();
+ component.setExpanded(true);
+ fixture.detectChanges();
+ await fixture.whenStable();
+ expect(expanded).toBeTruthy();
+ });
+});
diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/header/header-group.component.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/header/header-group.component.ts
new file mode 100644
index 0000000000..1278966946
--- /dev/null
+++ b/libs/components/ag-grid/src/lib/modules/ag-grid/header/header-group.component.ts
@@ -0,0 +1,124 @@
+import {
+ AfterViewInit,
+ ChangeDetectionStrategy,
+ ChangeDetectorRef,
+ Component,
+ ElementRef,
+ OnDestroy,
+ ViewChild,
+} from '@angular/core';
+import {
+ SkyDynamicComponentLocation,
+ SkyDynamicComponentOptions,
+ SkyDynamicComponentService,
+} from '@skyux/core';
+
+import { IHeaderGroupAngularComp } from 'ag-grid-angular';
+import {
+ ColumnGroupOpenedEvent,
+ Events,
+ ProvidedColumnGroup,
+} from 'ag-grid-community';
+import { BehaviorSubject, Observable, Subscription, fromEvent } from 'rxjs';
+
+import { SkyAgGridHeaderGroupInfo } from '../types/header-group-info';
+import { SkyAgGridHeaderGroupParams } from '../types/header-group-params';
+
+/**
+ * @internal
+ */
+@Component({
+ selector: 'sky-header-group',
+ templateUrl: './header-group.component.html',
+ styleUrls: ['./header-group.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class SkyAgGridHeaderGroupComponent
+ implements IHeaderGroupAngularComp, OnDestroy, AfterViewInit
+{
+ @ViewChild('inlineHelpContainer', { read: ElementRef, static: true })
+ public inlineHelpContainer: ElementRef;
+
+ public params: SkyAgGridHeaderGroupParams | undefined = undefined;
+ public isExpanded$: Observable;
+
+ #columnGroup: ProvidedColumnGroup | undefined = undefined;
+ #isExpandedSubject = new BehaviorSubject(false);
+ #subscriptions = new Subscription();
+ readonly #changeDetector: ChangeDetectorRef;
+ readonly #dynamicComponentService: SkyDynamicComponentService;
+ #viewInitialized = false;
+ #agIntialized = false;
+
+ constructor(
+ changeDetector: ChangeDetectorRef,
+ dynamicComponentService: SkyDynamicComponentService
+ ) {
+ this.#changeDetector = changeDetector;
+ this.#dynamicComponentService = dynamicComponentService;
+ this.isExpanded$ = this.#isExpandedSubject.asObservable();
+ }
+
+ public ngAfterViewInit(): void {
+ this.#viewInitialized = true;
+ this.#updateInlineHelp();
+ this.#changeDetector.markForCheck();
+ }
+
+ public ngOnDestroy(): void {
+ this.#subscriptions.unsubscribe();
+ }
+
+ public agInit(params: SkyAgGridHeaderGroupParams): void {
+ this.#agIntialized = true;
+ this.params = params;
+ this.#subscriptions.unsubscribe();
+ if (!this.params) {
+ return;
+ }
+ this.#subscriptions = new Subscription();
+ this.#columnGroup = this.params.columnGroup.getProvidedColumnGroup();
+ if (this.#columnGroup.isExpandable()) {
+ this.#subscriptions.add(
+ fromEvent(this.params.api, Events.EVENT_COLUMN_GROUP_OPENED).subscribe(
+ (event: ColumnGroupOpenedEvent) => {
+ if (event.columnGroup === this.#columnGroup) {
+ this.#isExpandedSubject.next(this.#columnGroup.isExpanded());
+ }
+ }
+ )
+ );
+ }
+ this.#updateInlineHelp();
+ this.#changeDetector.markForCheck();
+ }
+
+ public setExpanded($event: boolean): void {
+ this.params.setExpanded($event);
+ }
+
+ #updateInlineHelp(): void {
+ if (!this.#viewInitialized || !this.#agIntialized) {
+ return;
+ }
+ const colGroupDef = this.params?.columnGroup?.getColGroupDef();
+ const inlineHelpComponent =
+ colGroupDef?.headerGroupComponentParams?.inlineHelpComponent;
+ if (inlineHelpComponent) {
+ this.#dynamicComponentService.createComponent(inlineHelpComponent, {
+ providers: [
+ {
+ provide: SkyAgGridHeaderGroupInfo,
+ useValue: {
+ columnGroup: this.params.columnGroup,
+ context: this.params.context,
+ displayName: this.params.displayName,
+ } as SkyAgGridHeaderGroupInfo,
+ },
+ ],
+ referenceEl: this.inlineHelpContainer.nativeElement,
+ location: SkyDynamicComponentLocation.ElementBottom,
+ } as SkyDynamicComponentOptions);
+ }
+ }
+}
diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/header/header.component.html b/libs/components/ag-grid/src/lib/modules/ag-grid/header/header.component.html
new file mode 100644
index 0000000000..7167d6eae3
--- /dev/null
+++ b/libs/components/ag-grid/src/lib/modules/ag-grid/header/header.component.html
@@ -0,0 +1,49 @@
+
+
+
+
+
diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/header/header.component.scss b/libs/components/ag-grid/src/lib/modules/ag-grid/header/header.component.scss
new file mode 100644
index 0000000000..1ad08ea0f5
--- /dev/null
+++ b/libs/components/ag-grid/src/lib/modules/ag-grid/header/header.component.scss
@@ -0,0 +1,19 @@
+:host {
+ display: flex;
+ max-width: 100%;
+ padding-right: 12px;
+ padding-left: 12px;
+ align-items: center;
+ align-content: center;
+}
+
+.ag-header-cell-label {
+ padding-right: 0;
+ padding-left: 0;
+}
+
+button {
+ cursor: pointer;
+ flex-grow: 0;
+ flex-shrink: 0;
+}
diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/header/header.component.spec.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/header/header.component.spec.ts
new file mode 100644
index 0000000000..47f247735c
--- /dev/null
+++ b/libs/components/ag-grid/src/lib/modules/ag-grid/header/header.component.spec.ts
@@ -0,0 +1,189 @@
+import { Component } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
+import { SkyIconModule } from '@skyux/indicators';
+import { SkyThemeModule } from '@skyux/theme';
+
+import { Column, ColumnApi } from 'ag-grid-community';
+
+import { SkyAgGridHeaderParams } from '../types/header-params';
+
+import { SkyAgGridHeaderComponent } from './header.component';
+
+@Component({
+ template: `Help text`,
+})
+class TestHelpComponent {}
+
+@Component({
+ template: `Other help text`,
+})
+class OtherTestHelpComponent {}
+
+describe('HeaderComponent', () => {
+ let component: SkyAgGridHeaderComponent;
+ let fixture: ComponentFixture;
+ let apiEvents: { [key: string]: (() => void)[] };
+ let columnEvents: { [key: string]: (() => void)[] };
+ let params: SkyAgGridHeaderParams;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ declarations: [
+ SkyAgGridHeaderComponent,
+ TestHelpComponent,
+ OtherTestHelpComponent,
+ ],
+ imports: [SkyIconModule, SkyThemeModule],
+ });
+ apiEvents = {};
+ columnEvents = {};
+ params = {
+ displayName: 'Test Column',
+ showColumnMenu: () => undefined,
+ progressSort: () => undefined,
+ api: {
+ addEventListener: (eventType: string, listener: () => void) => {
+ apiEvents[eventType] = apiEvents[eventType] || [];
+ apiEvents[eventType].push(listener);
+ },
+ removeEventListener: (eventType: string, listener: () => void) => {
+ apiEvents[eventType] = apiEvents[eventType] || [];
+ apiEvents[eventType] = apiEvents[eventType].filter(
+ (l) => l !== listener
+ );
+ },
+ },
+ column: {
+ addEventListener: (eventType: string, listener: () => void) => {
+ columnEvents[eventType] = columnEvents[eventType] || [];
+ columnEvents[eventType].push(listener);
+ },
+ removeEventListener: (eventType: string, listener: () => void) => {
+ columnEvents[eventType] = columnEvents[eventType] || [];
+ columnEvents[eventType] = columnEvents[eventType].filter(
+ (l) => l !== listener
+ );
+ },
+ isFilterActive: () => false,
+ isFilterAllowed: () => false,
+ isSortAscending: () => false,
+ isSortDescending: () => false,
+ isSortNone: () => true,
+ getSort: (): 'asc' | 'desc' | null | undefined => undefined,
+ getSortIndex: () => undefined,
+ getColId: () => 'test',
+ } as Column,
+ enableSorting: false,
+ columnApi: {
+ getAllColumns: () => [],
+ } as ColumnApi,
+ } as unknown as SkyAgGridHeaderParams;
+
+ fixture = TestBed.createComponent(SkyAgGridHeaderComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ component.agInit(undefined);
+ expect(component).toBeTruthy();
+ });
+
+ it('should implement IHeaderAngularComp', () => {
+ component.agInit(params);
+ fixture.detectChanges();
+ expect(
+ fixture.debugElement.query(By.css('.ag-header-cell-text')).nativeElement
+ .textContent
+ ).toBe('Test Column');
+ const sortSpy = spyOn(params, 'progressSort');
+ component.onSortRequested({ shiftKey: false });
+ expect(sortSpy).toHaveBeenCalled();
+ const menuSpy = spyOn(params, 'showColumnMenu');
+ component.onMenuClick({ target: {} } as Event);
+ expect(menuSpy).toHaveBeenCalled();
+ expect(component.refresh(params)).toBe(false);
+ });
+
+ it('should handle events', async () => {
+ let useSort = 'asc';
+ params = {
+ ...params,
+ enableSorting: true,
+ column: {
+ ...params.column,
+ getSort: () => useSort,
+ getSortIndex: () => useSort && 0,
+ isFilterActive: () => true,
+ isFilterAllowed: () => true,
+ isSortAscending: () => useSort === 'asc',
+ isSortDescending: () => useSort === 'desc',
+ isSortNone: () => !useSort,
+ } as unknown as Column,
+ columnApi: {
+ ...params.columnApi,
+ getAllColumns() {
+ return [
+ {
+ getColId: () => 'test',
+ getSort: () => useSort,
+ },
+ {
+ getColId: () => 'other',
+ getSort: () => useSort,
+ },
+ ];
+ },
+ } as unknown as ColumnApi,
+ };
+ component.agInit(params);
+ fixture.detectChanges();
+ expect(apiEvents['sortChanged'].length).toBeGreaterThanOrEqual(1);
+ expect(columnEvents['sortChanged'].length).toBeGreaterThanOrEqual(1);
+ expect(columnEvents['filterChanged'].length).toBeGreaterThanOrEqual(1);
+ apiEvents['sortChanged'].forEach((listener) => listener());
+ columnEvents['sortChanged'].forEach((listener) => listener());
+ expect(
+ fixture.debugElement.query(By.css('.ag-header-label-icon')).attributes[
+ 'icon'
+ ]
+ ).toBe('caret-up');
+ useSort = undefined;
+ apiEvents['sortChanged'].forEach((listener) => listener());
+ columnEvents['sortChanged'].forEach((listener) => listener());
+ fixture.detectChanges();
+ await fixture.whenStable();
+ expect(
+ fixture.debugElement.query(By.css('.ag-header-label-icon'))
+ ).toBeFalsy();
+
+ columnEvents['filterChanged'].forEach((listener) => listener());
+ expect(component.filterEnabled$.getValue()).toBe(true);
+ fixture.detectChanges();
+ await fixture.whenStable();
+ expect(fixture.debugElement.query(By.css('.ag-filter-icon'))).toBeTruthy();
+ });
+
+ it('should inject help component', () => {
+ component.agInit({
+ ...params,
+ inlineHelpComponent: TestHelpComponent,
+ });
+ fixture.detectChanges();
+ expect(
+ fixture.debugElement.query(By.css('.test-help-component'))
+ ).toBeTruthy();
+ component.refresh({
+ ...params,
+ inlineHelpComponent: OtherTestHelpComponent,
+ });
+ fixture.detectChanges();
+ expect(
+ fixture.debugElement.query(By.css('.test-help-component'))
+ ).toBeFalsy();
+ expect(
+ fixture.debugElement.query(By.css('.other-help-component'))
+ ).toBeTruthy();
+ });
+});
diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/header/header.component.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/header/header.component.ts
new file mode 100644
index 0000000000..44de2d1f4f
--- /dev/null
+++ b/libs/components/ag-grid/src/lib/modules/ag-grid/header/header.component.ts
@@ -0,0 +1,176 @@
+import {
+ AfterViewInit,
+ ChangeDetectionStrategy,
+ ChangeDetectorRef,
+ Component,
+ ComponentRef,
+ ElementRef,
+ OnDestroy,
+ ViewChild,
+} from '@angular/core';
+import {
+ SkyDynamicComponentLocation,
+ SkyDynamicComponentOptions,
+ SkyDynamicComponentService,
+} from '@skyux/core';
+
+import { IHeaderAngularComp } from 'ag-grid-angular';
+import { Events } from 'ag-grid-community';
+import { BehaviorSubject, Subscription, fromEvent } from 'rxjs';
+
+import { SkyAgGridHeaderInfo } from '../types/header-info';
+import { SkyAgGridHeaderParams } from '../types/header-params';
+
+/**
+ * @internal
+ */
+@Component({
+ selector: 'sky-ag-grid-header',
+ templateUrl: './header.component.html',
+ styleUrls: ['./header.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class SkyAgGridHeaderComponent
+ implements IHeaderAngularComp, OnDestroy, AfterViewInit
+{
+ @ViewChild('inlineHelpContainer', { read: ElementRef, static: true })
+ public inlineHelpContainer: ElementRef;
+
+ public params: SkyAgGridHeaderParams | undefined = undefined;
+ public sorted = '';
+ public readonly filterEnabled$ = new BehaviorSubject(false);
+ public readonly sortOrder$ = new BehaviorSubject<'asc' | 'desc' | undefined>(
+ undefined
+ );
+ public readonly sortIndexDisplay$ = new BehaviorSubject('');
+
+ #subscriptions = new Subscription();
+ readonly #changeDetector: ChangeDetectorRef;
+ readonly #dynamicComponentService: SkyDynamicComponentService;
+ #inlineHelpComponentRef: ComponentRef | undefined;
+ #viewInitialized = false;
+ #agIntialized = false;
+
+ constructor(
+ changeDetector: ChangeDetectorRef,
+ dynamicComponentService: SkyDynamicComponentService
+ ) {
+ this.#changeDetector = changeDetector;
+ this.#dynamicComponentService = dynamicComponentService;
+ }
+
+ public ngAfterViewInit(): void {
+ this.#viewInitialized = true;
+ this.#updateInlineHelp();
+ }
+
+ public ngOnDestroy(): void {
+ this.#subscriptions.unsubscribe();
+ }
+
+ public agInit(params: SkyAgGridHeaderParams): void {
+ this.#agIntialized = true;
+ this.params = params;
+ this.#subscriptions.unsubscribe();
+ if (!this.params) {
+ return;
+ }
+ this.#subscriptions = new Subscription();
+ if (params.column.isFilterAllowed()) {
+ this.#subscriptions.add(
+ fromEvent(params.column, 'filterChanged').subscribe(() => {
+ const isFilterActive = params.column.isFilterActive();
+ if (isFilterActive !== this.filterEnabled$.getValue()) {
+ this.filterEnabled$.next(isFilterActive);
+ }
+ })
+ );
+ }
+ if (params.enableSorting) {
+ // Column sort state changes
+ this.#subscriptions.add(
+ fromEvent(params.column, Events.EVENT_SORT_CHANGED).subscribe(() => {
+ this.#updateSort();
+ })
+ );
+ // Other column sort state changes, for multi-column sorting
+ this.#subscriptions.add(
+ fromEvent(params.api, Events.EVENT_SORT_CHANGED).subscribe(() => {
+ this.#updateSortIndex();
+ })
+ );
+ this.#updateSort();
+ this.#updateSortIndex();
+ }
+ this.#updateInlineHelp();
+ this.#changeDetector.markForCheck();
+ }
+
+ public onMenuClick($event: Event): void {
+ this.params.showColumnMenu($event.target as HTMLElement);
+ }
+
+ public onSortRequested(event): void {
+ this.params.progressSort(!!event.shiftKey);
+ }
+
+ public refresh(params: SkyAgGridHeaderParams): boolean {
+ this.agInit(params);
+ return false;
+ }
+
+ #updateInlineHelp(): void {
+ if (!this.#viewInitialized || !this.#agIntialized) {
+ return;
+ }
+ const inlineHelpComponent = this.params.inlineHelpComponent;
+ if (
+ inlineHelpComponent &&
+ (!this.#inlineHelpComponentRef ||
+ this.#inlineHelpComponentRef.componentType !== inlineHelpComponent)
+ ) {
+ this.#dynamicComponentService.removeComponent(
+ this.#inlineHelpComponentRef
+ );
+ this.#inlineHelpComponentRef =
+ this.#dynamicComponentService.createComponent(inlineHelpComponent, {
+ providers: [
+ {
+ provide: SkyAgGridHeaderInfo,
+ useValue: {
+ column: this.params.column,
+ context: this.params.context,
+ displayName: this.params.displayName,
+ } as SkyAgGridHeaderInfo,
+ },
+ ],
+ referenceEl: this.inlineHelpContainer.nativeElement,
+ location: SkyDynamicComponentLocation.ElementBottom,
+ } as SkyDynamicComponentOptions);
+ } else if (!inlineHelpComponent) {
+ this.#dynamicComponentService.removeComponent(
+ this.#inlineHelpComponentRef
+ );
+ }
+ }
+
+ #updateSort(): void {
+ this.sortOrder$.next(this.params.column.getSort() || undefined);
+ }
+
+ #updateSortIndex(): void {
+ const sortIndex = this.params.column.getSortIndex();
+ const otherSortColumns = this.params.columnApi
+ .getAllColumns()
+ .some(
+ (column) =>
+ column.getColId() !== this.params.column.getColId() &&
+ !!column.getSort()
+ );
+ if (sortIndex !== undefined && sortIndex !== null && otherSortColumns) {
+ this.sortIndexDisplay$.next(`${sortIndex + 1}`);
+ } else {
+ this.sortIndexDisplay$.next('');
+ }
+ }
+}
diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/types/header-group-info.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/types/header-group-info.ts
new file mode 100644
index 0000000000..43d31099da
--- /dev/null
+++ b/libs/components/ag-grid/src/lib/modules/ag-grid/types/header-group-info.ts
@@ -0,0 +1,19 @@
+import { Injectable } from '@angular/core';
+
+import { ColumnGroup } from 'ag-grid-community';
+
+/**
+ * To display a help button beside the column group header, create a component that includes the help button element,
+ * such as `sky-help-inline`, include a `SkyAgGridHeaderGroupInfo` parameter in the constructor to access the column
+ * group information, such as display name, and add the component to the `headerComponentParams.inlineHelpComponent`
+ * property of the column definition.
+ */
+@Injectable()
+export class SkyAgGridHeaderGroupInfo {
+ columnGroup: ColumnGroup;
+ displayName: string;
+ /**
+ * Application context as set on `gridOptions.context`.
+ */
+ context: any;
+}
diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/types/header-group-params.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/types/header-group-params.ts
new file mode 100644
index 0000000000..786ed12d54
--- /dev/null
+++ b/libs/components/ag-grid/src/lib/modules/ag-grid/types/header-group-params.ts
@@ -0,0 +1,12 @@
+import { Type } from '@angular/core';
+
+import { IHeaderGroupParams } from 'ag-grid-community';
+
+/**
+ * Interface to use for the
+ * [`headerGroupComponentParams`](https://www.ag-grid.com/angular-data-grid/column-properties/#reference-groupsHeader-headerGroupComponentParams)
+ * property on `ColDef`.
+ */
+export interface SkyAgGridHeaderGroupParams extends IHeaderGroupParams {
+ inlineHelpComponent?: Type;
+}
diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/types/header-info.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/types/header-info.ts
new file mode 100644
index 0000000000..dd824e5e0a
--- /dev/null
+++ b/libs/components/ag-grid/src/lib/modules/ag-grid/types/header-info.ts
@@ -0,0 +1,19 @@
+import { Injectable } from '@angular/core';
+
+import { Column } from 'ag-grid-community';
+
+/**
+ * To display a help button beside the column header, create a component that includes the help button element,
+ * such as `sky-help-inline`, include a `SkyAgGridHeaderInfo` parameter in the constructor to access the column
+ * information, such as display name, and add the component to the `headerComponentParams.inlineHelpComponent` property
+ * of the column definition.
+ */
+@Injectable()
+export class SkyAgGridHeaderInfo {
+ column: Column;
+ displayName: string;
+ /**
+ * Application context as set on `gridOptions.context`.
+ */
+ context: any;
+}
diff --git a/libs/components/ag-grid/src/lib/modules/ag-grid/types/header-params.ts b/libs/components/ag-grid/src/lib/modules/ag-grid/types/header-params.ts
new file mode 100644
index 0000000000..cdef4a5d96
--- /dev/null
+++ b/libs/components/ag-grid/src/lib/modules/ag-grid/types/header-params.ts
@@ -0,0 +1,12 @@
+import { Type } from '@angular/core';
+
+import { IHeaderParams } from 'ag-grid-community/dist/lib/headerRendering/cells/column/headerComp';
+
+/**
+ * Interface to use for the
+ * [`headerComponentParams`](https://www.ag-grid.com/angular-data-grid/column-properties/#reference-header-headerComponentParams)
+ * property on `ColDef`.
+ */
+export interface SkyAgGridHeaderParams extends IHeaderParams {
+ inlineHelpComponent?: Type;
+}
diff --git a/libs/components/ag-grid/src/lib/modules/shared/sky-ag-grid-resources.module.ts b/libs/components/ag-grid/src/lib/modules/shared/sky-ag-grid-resources.module.ts
index 5c3e4f01fb..850ce530d9 100644
--- a/libs/components/ag-grid/src/lib/modules/shared/sky-ag-grid-resources.module.ts
+++ b/libs/components/ag-grid/src/lib/modules/shared/sky-ag-grid-resources.module.ts
@@ -38,6 +38,12 @@ const RESOURCES: { [locale: string]: SkyLibResources } = {
sky_ag_grid_cell_editor_currency_aria_label: {
message: 'Editable currency {0} for row {1}',
},
+ sky_ag_grid_column_group_header_expand_aria_label: {
+ message: 'Expand column group {0}',
+ },
+ sky_ag_grid_column_group_header_collapse_aria_label: {
+ message: 'Collapse column group {0}',
+ },
},
};
diff --git a/libs/components/ag-grid/src/lib/styles/ag-grid-styles.scss b/libs/components/ag-grid/src/lib/styles/ag-grid-styles.scss
index 767bee911b..fadce4aa81 100644
--- a/libs/components/ag-grid/src/lib/styles/ag-grid-styles.scss
+++ b/libs/components/ag-grid/src/lib/styles/ag-grid-styles.scss
@@ -631,7 +631,7 @@ ag-grid-angular {
padding-right: 12px;
}
- .sky-ag-grid-header-right-aligned .ag-header-cell-label {
+ .ag-header-cell.sky-ag-grid-header-right-aligned {
justify-content: flex-end;
}
}