diff --git a/projects/igniteui-angular-i18n/src/i18n/BG/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/BG/grid-resources.ts index a443455e39a..b962412b3b6 100644 --- a/projects/igniteui-angular-i18n/src/i18n/BG/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/BG/grid-resources.ts @@ -151,6 +151,11 @@ const GridResourceStringsBG_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Филтри', + igx_grid_pivot_selector_rows: 'Редове', + igx_grid_pivot_selector_columns: 'Колони', + igx_grid_pivot_selector_values: 'Стойнoсти', + igx_grid_pivot_selector_panel_empty: 'Привлачи тук', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular-i18n/src/i18n/CS/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/CS/grid-resources.ts index 5277d85ed4d..13c41d5d7a0 100644 --- a/projects/igniteui-angular-i18n/src/i18n/CS/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/CS/grid-resources.ts @@ -151,6 +151,11 @@ const GridResourceStringsCS_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drag Items Here', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular-i18n/src/i18n/DA/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/DA/grid-resources.ts index af6adda5945..b69f3921cc0 100644 --- a/projects/igniteui-angular-i18n/src/i18n/DA/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/DA/grid-resources.ts @@ -151,6 +151,11 @@ const GridResourceStringsDA_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drag Items Here', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular-i18n/src/i18n/DE/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/DE/grid-resources.ts index 975a538b659..697fefb1f9b 100644 --- a/projects/igniteui-angular-i18n/src/i18n/DE/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/DE/grid-resources.ts @@ -151,6 +151,11 @@ const GridResourceStringsDE_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drag Items Here', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular-i18n/src/i18n/ES/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/ES/grid-resources.ts index 32c431be944..141f43624df 100644 --- a/projects/igniteui-angular-i18n/src/i18n/ES/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/ES/grid-resources.ts @@ -151,6 +151,11 @@ const GridResourceStringsES_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drag Items Here', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular-i18n/src/i18n/FR/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/FR/grid-resources.ts index d14a7d4da2e..6318fa37bec 100644 --- a/projects/igniteui-angular-i18n/src/i18n/FR/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/FR/grid-resources.ts @@ -151,6 +151,11 @@ const GridResourceStringsFR_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drag Items Here', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular-i18n/src/i18n/HU/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/HU/grid-resources.ts index a7c2f2bc413..433e8c35955 100644 --- a/projects/igniteui-angular-i18n/src/i18n/HU/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/HU/grid-resources.ts @@ -152,6 +152,11 @@ const GridResourceStringsHU_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drag Items Here', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular-i18n/src/i18n/IT/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/IT/grid-resources.ts index ab2af817789..f8d7f7a4a92 100644 --- a/projects/igniteui-angular-i18n/src/i18n/IT/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/IT/grid-resources.ts @@ -151,6 +151,11 @@ const GridResourceStringsIT_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drag Items Here', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular-i18n/src/i18n/JA/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/JA/grid-resources.ts index 692bd0afd97..cd3a2e8056f 100644 --- a/projects/igniteui-angular-i18n/src/i18n/JA/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/JA/grid-resources.ts @@ -151,6 +151,11 @@ const GridResourceStringsJA_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drag Items Here', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular-i18n/src/i18n/KO/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/KO/grid-resources.ts index 8ec504d29d0..a181899d28b 100644 --- a/projects/igniteui-angular-i18n/src/i18n/KO/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/KO/grid-resources.ts @@ -151,6 +151,11 @@ const GridResourceStringsKO_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drag Items Here', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular-i18n/src/i18n/NB/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/NB/grid-resources.ts index 0a49102c68b..8c2bbeeaaa0 100644 --- a/projects/igniteui-angular-i18n/src/i18n/NB/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/NB/grid-resources.ts @@ -151,6 +151,11 @@ const GridResourceStringsNB_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drag Items Here', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular-i18n/src/i18n/NL/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/NL/grid-resources.ts index cc3d332f4d2..70c87ade8a7 100644 --- a/projects/igniteui-angular-i18n/src/i18n/NL/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/NL/grid-resources.ts @@ -151,6 +151,11 @@ const GridResourceStringsNL_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drag Items Here', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular-i18n/src/i18n/PL/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/PL/grid-resources.ts index 3227c59b144..9a181b3694f 100644 --- a/projects/igniteui-angular-i18n/src/i18n/PL/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/PL/grid-resources.ts @@ -151,6 +151,11 @@ const GridResourceStringsPL_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drag Items Here', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular-i18n/src/i18n/PT/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/PT/grid-resources.ts index ab9bb5818ae..44208c0ff49 100644 --- a/projects/igniteui-angular-i18n/src/i18n/PT/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/PT/grid-resources.ts @@ -151,6 +151,11 @@ const GridResourceStringsPT_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drag Items Here', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular-i18n/src/i18n/RO/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/RO/grid-resources.ts index cf5b66ee714..a30c71cc2cb 100644 --- a/projects/igniteui-angular-i18n/src/i18n/RO/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/RO/grid-resources.ts @@ -151,6 +151,11 @@ const GridResourceStringsRO_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drag Items Here', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular-i18n/src/i18n/SV/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/SV/grid-resources.ts index 3503d0451ea..24f72c0a06a 100644 --- a/projects/igniteui-angular-i18n/src/i18n/SV/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/SV/grid-resources.ts @@ -151,6 +151,11 @@ const GridResourceStringsSV_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drag Items Here', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular-i18n/src/i18n/TR/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/TR/grid-resources.ts index 3f495bf810d..41d16711ff2 100644 --- a/projects/igniteui-angular-i18n/src/i18n/TR/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/TR/grid-resources.ts @@ -151,6 +151,11 @@ const GridResourceStringsTR_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drag Items Here', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular-i18n/src/i18n/ZH-HANS/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/ZH-HANS/grid-resources.ts index 01c8034e80b..35933f955e1 100644 --- a/projects/igniteui-angular-i18n/src/i18n/ZH-HANS/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/ZH-HANS/grid-resources.ts @@ -151,6 +151,11 @@ const GridResourceStringsZHHANS_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drag Items Here', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular-i18n/src/i18n/ZH-HANT/grid-resources.ts b/projects/igniteui-angular-i18n/src/i18n/ZH-HANT/grid-resources.ts index f02d4021017..b343e4d633f 100644 --- a/projects/igniteui-angular-i18n/src/i18n/ZH-HANT/grid-resources.ts +++ b/projects/igniteui-angular-i18n/src/i18n/ZH-HANT/grid-resources.ts @@ -151,6 +151,11 @@ const GridResourceStringsZHHANT_: ExpandRequire = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drag Items Here', igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' }; diff --git a/projects/igniteui-angular/src/lib/core/i18n/grid-resources.ts b/projects/igniteui-angular/src/lib/core/i18n/grid-resources.ts index 849db7150e7..4581e0a530b 100644 --- a/projects/igniteui-angular/src/lib/core/i18n/grid-resources.ts +++ b/projects/igniteui-angular/src/lib/core/i18n/grid-resources.ts @@ -149,6 +149,11 @@ export interface IGridResourceStrings { igx_grid_pivot_filter_drop_chip?: string; igx_grid_pivot_value_drop_chip?: string; igx_grid_pivot_empty_message?: string; + igx_grid_pivot_selector_filters?: string; + igx_grid_pivot_selector_rows?: string; + igx_grid_pivot_selector_columns?: string; + igx_grid_pivot_selector_values?: string; + igx_grid_pivot_selector_panel_empty?: string; } export const GridResourceStringsEN: IGridResourceStrings = { @@ -301,5 +306,10 @@ export const GridResourceStringsEN: IGridResourceStrings = { igx_grid_pivot_column_drop_chip: 'Drop here to use as column', igx_grid_pivot_filter_drop_chip: 'Drop here to use as filter', igx_grid_pivot_value_drop_chip: 'Drop here to use as value', - igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.' + igx_grid_pivot_empty_message: 'Pivot grid has no dimensions and values.', + igx_grid_pivot_selector_filters: 'Filters', + igx_grid_pivot_selector_rows: 'Rows', + igx_grid_pivot_selector_columns: 'Columns', + igx_grid_pivot_selector_values: 'Values', + igx_grid_pivot_selector_panel_empty: 'Drop Items Here', }; diff --git a/projects/igniteui-angular/src/lib/core/styles/components/_index.scss b/projects/igniteui-angular/src/lib/core/styles/components/_index.scss index 139ccc30b09..a47c35c377d 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/_index.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/_index.scss @@ -21,6 +21,7 @@ @forward 'drop-down/drop-down-theme'; @forward 'expansion-panel/expansion-panel-theme'; @forward 'grid/grid-theme'; +@forward 'grid/pivot-data-selector-theme'; @forward 'grid-summary/grid-summary-theme'; @forward 'grid-toolbar/grid-toolbar-theme'; @forward 'highlight/highlight-theme.scss'; diff --git a/projects/igniteui-angular/src/lib/core/styles/components/grid/_pivot-data-selector-component.scss b/projects/igniteui-angular/src/lib/core/styles/components/grid/_pivot-data-selector-component.scss new file mode 100644 index 00000000000..f53a26ef421 --- /dev/null +++ b/projects/igniteui-angular/src/lib/core/styles/components/grid/_pivot-data-selector-component.scss @@ -0,0 +1,74 @@ +@use '../../base' as *; +@use 'sass:string'; + +@mixin component() { + @include b(igx-pivot-data-selector) { + $this: bem--selector-to-string(&); + @include register-component( + $name: string.slice($this, 2, -1), + $deps: () + ); + + @extend %selector-base !optional; + + @include e(header) { + @extend %selector-header !optional; + } + + @include e(header-inner) { + @extend %igx-expansion-panel__header-inner !optional; + } + + @include e(header-extra) { + @extend %selector-header-extra !optional; + } + + @include e(filter) { + @extend %selector-filter !optional; + } + + @include e(item) { + @extend %selector-item !optional; + } + + @include e(item-ghost) { + @extend %selector-item-ghost !optional; + } + + @include e(item-ghost, $m: no-drop) { + @extend %selector-item-ghost--no-drop !optional; + } + + @include e(item-ghost-text) { + @extend %selector-item-ghost-text !optional; + } + + @include e(item-start) { + @extend %selector-item-start !optional; + } + + @include e(item-end) { + @extend %selector-item-end !optional; + } + + @include e(item-text) { + @extend %selector-item-text !optional; + } + + @include e(action-sort) { + @extend %selector-action-sort !optional; + } + + @include e(action-filter) { + @extend %selector-action-filter !optional; + } + + @include e(action-move) { + @extend %selector-action-move !optional; + } + + @include e(action-summary) { + @extend %selector-action-summary !optional; + } + } +} diff --git a/projects/igniteui-angular/src/lib/core/styles/components/grid/_pivot-data-selector-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/grid/_pivot-data-selector-theme.scss new file mode 100644 index 00000000000..e336e73a1a8 --- /dev/null +++ b/projects/igniteui-angular/src/lib/core/styles/components/grid/_pivot-data-selector-theme.scss @@ -0,0 +1,277 @@ +@use '../../base' as *; +@use '../../themes/schemas' as *; +@use 'sass:map'; +@use 'sass:meta'; + +//// +/// @group themes +/// @access public +/// @author Simeon Simeonoff +//// + +/// @param {Map} $palette [null] - The palette used as basis for styling the component. +/// @param {Map} $schema [$light-schema] - The schema used as basis for styling the component. +/// +@function pivot-data-selector-theme( + $palette: null, + $schema: $light-schema, + $background: null +) { + $name: 'igx-pivot-data-selector'; + $selector: '.igx-pivot-data-selector'; + $pivot-data-selector-schema: (); + + @if map.has-key($schema, $name) { + $pivot-data-selector-schema: map.get($schema, $name); + } @else { + $pivot-data-selector-schema: $schema; + } + + $theme: apply-palette($pivot-data-selector-schema, $palette); + + @return extend($theme, ( + name: $name, + palette: $palette, + )); +} + +/// @param {Map} $theme - The theme used to style the component. +/// @requires {mixin} igx-css-vars +/// @requires {mixin} ellipsis +/// @requires rem +/// @requires var-get +@mixin pivot-data-selector($theme) { + @include igx-css-vars($theme); + + $left: if-ltr(left, right); + $right: if-ltr(right, left); + + $chip-height-material: ( + comfortable: rem(22px), + cosy: rem(20px), + compact: rem(18px) + ); + + $chip-item-padding: 0 rem(2px); + $panel-padding: em(4px, 16px); + + %selector-base { + display: flex; + flex-direction: column; + max-width: rem(280px); + background: var-get($theme, 'background'); + z-index: 0; + + > igx-input-group { + flex: 0 1 auto; + } + + igx-display-container { + display: flex; + flex-direction: column; + } + + > igx-list { + igx-display-container { + padding: rem(4px); + } + + igx-list-item { + display: flex; + min-height: rem(28px); + } + + %cbx-label { + font-size: rem(13px); + } + } + + %form-group-input--box { + transform: none; + } + + %form-group-prefix, + %form-group-prefix--cosy, + %form-group-prefix--compact { + padding-#{$right}: rem(16px) !important; + box-sizing: content-box; + } + + %form-group-bundle-main--box, + %form-group-bundle-main--box-cosy, + %form-group-bundle-main--box-compact { + padding-top: 0 !important; + } + + %igx-expansion-panel__body { + position: relative; + height: rem(128px); + font-size: rem(14px); + padding: $panel-padding; + overflow-y: auto; + } + + %igx-expansion-panel__header-icon--start { + margin-#{$right}: rem(8px); + } + + igx-icon { + width: rem(18px); + height: rem(18px); + font-size: rem(18px); + } + + %igx-expansion-panel__header-title > h6 { + font-size: rem(12px); + } + } + + %selector-filter { + display: flex; + flex-direction: column; + overflow: hidden; + + igx-list { + display: flex; + flex-direction: column; + padding: rem(8px) rem(4px); + min-height: 186px; + max-height: 208px; + overflow-y: auto; + } + + igx-list-item { + display: flex; + align-items: center; + } + + igx-checkbox + span { + margin-#{$left}: rem(8px); + line-height: rem(28px); + } + } + + %selector-header, + %selector-header-extra { + display: flex; + align-items: center; + } + + %igx-expansion-panel__header-inner { + background: var-get($theme, 'header-color'); + padding: $panel-padding; + + .dragOver & { + background: igx-color($color: 'grays', $variant: 300); + box-shadow: inset 0 0 0 1px igx-color($color: 'grays', $variant: 400); + } + } + + %selector-header-extra { + igx-icon { + padding: 0 rem(8px); + box-sizing: content-box; + } + + %igx-chip__item { + height: map.get($chip-height-material, 'comfortable'); + } + + %igx-chip__item--cosy { + height: map.get($chip-height-material, 'cosy'); + } + + %igx-chip__item--compact { + height: map.get($chip-height-material, 'compact'); + } + + %igx-chip__content { + padding: $chip-item-padding; + } + } + + %selector-item { + display: flex; + align-items: center; + justify-content: space-between; + min-height: rem(32px); + + .igx-drag--push & { + padding-top: rem(32px); + } + } + + %selector-item-ghost { + display: flex; + align-items: center; + justify-content: space-between; + font-size: rem(14px); + background: igx-color($color: 'surface'); + min-height: rem(32px); + height: auto; + padding: 0 rem(2px) 0 rem(4px); + cursor: grabbing; + box-shadow: igx-elevation($igx-elevations, 24); + border: 1px solid igx-color($color: 'grays', $variant: 100); + border-radius: rem(2px); + + igx-icon { + width: rem(18px); + height: rem(18px); + font-size: rem(18px); + } + } + + %selector-item-ghost-text { + display: flex; + align-items: center; + + igx-icon { + margin-inline-end: rem(8px); + } + } + + %selector-item-ghost--no-drop { + cursor: no-drop; + } + + %selector-item-text { + @include ellipsis(); + max-width: calc(100% - 18px + 8px); + } + + %selector-item-text, + %selector-action-sort, + %selector-action-filter, + %selector-action-move, + %selector-action-summary { + user-select: none; + } + + %selector-action-sort, + %selector-action-summary, + %selector-action-filter { + cursor: pointer; + } + + %selector-action-move { + cursor: grab; + } + + %selector-item-start { + display: flex; + justify-content: space-between; + align-items: center; + flex: 0 1 100%; + margin-inline-end: rem(8px); + overflow: hidden; + } + + %selector-item-end { + display: flex; + + igx-icon + igx-icon { + margin-#{$left}: rem(8px); + } + } +} diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/_core.scss b/projects/igniteui-angular/src/lib/core/styles/themes/_core.scss index 9a2f0ddc826..577a67729c4 100644 --- a/projects/igniteui-angular/src/lib/core/styles/themes/_core.scss +++ b/projects/igniteui-angular/src/lib/core/styles/themes/_core.scss @@ -46,6 +46,7 @@ @use '../components/drop-down/drop-down-component' as drop-down; @use '../components/expansion-panel/expansion-panel-component' as expansion-panel; @use '../components/grid/grid-component' as grid; +@use '../components/grid/pivot-data-selector-component' as pivot-data-selector; @use '../components/grid-summary/grid-summary-component' as grid-summary; @use '../components/grid-toolbar/grid-toolbar-component' as grid-toolbar; @use '../components/highlight/highlight-component' as highlight; @@ -148,6 +149,7 @@ @include grid.component(); @include grid-summary.component(); @include grid-toolbar.component(); + @include pivot-data-selector.component(); @include highlight.component(); @include icon.component(); @include input-group.component(); diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/_index.scss b/projects/igniteui-angular/src/lib/core/styles/themes/_index.scss index 1c922030179..8715fd848e5 100644 --- a/projects/igniteui-angular/src/lib/core/styles/themes/_index.scss +++ b/projects/igniteui-angular/src/lib/core/styles/themes/_index.scss @@ -309,6 +309,12 @@ )); } + @if is-used('igx-pivot-data-selector', $exclude) { + @include pivot-data-selector(pivot-data-selector-theme( + $schema: $schema + )); + } + @if is-used('igx-highlight', $exclude) { @include igx-highlight(igx-highlight-theme( $schema: $schema diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_index.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_index.scss index 7d757bb5341..487135e2dde 100644 --- a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_index.scss +++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_index.scss @@ -36,6 +36,7 @@ @use './pagination' as *; @use './grid-summary' as *; @use './grid-toolbar' as *; +@use './pivot-data-selector' as *; @use './highlight' as *; @use './icon' as *; @use './input-group' as *; @@ -99,6 +100,7 @@ /// @property {Map} funnel-chart [$dark-funnel-chart] /// @property {Map} igx-grid-summary [$dark-grid-summary] /// @property {Map} igx-grid-toolbar [$dark-grid-toolbar] +/// @property {Map} igx-pivot-data-selector [$dark-pivot-data-selector] /// @property {Map} igx-highlight [$dark-highlight] /// @property {Map} igx-icon [$dark-icon] /// @property {Map} igx-input-group [$dark-input-group] @@ -159,6 +161,7 @@ $dark-schema: ( igx-paginator: $dark-pagination, igx-grid-summary: $dark-grid-summary, igx-grid-toolbar: $dark-grid-toolbar, + igx-pivot-data-selector: $dark-pivot-data-selector, igx-highlight: $dark-highlight, igx-icon: $dark-icon, igx-input-group: $dark-input-group, @@ -229,6 +232,7 @@ $dark-material-schema: $dark-schema; /// @property {Map} funnel-chart [$dark-fluent-funnel-chart], /// @property {Map} igx-grid-summary [$dark-fluent-grid-summary], /// @property {Map} igx-grid-toolbar [$dark-fluent-grid-toolbar], +/// @property {Map} igx-pivot-data-selector [$dark-fluent-pivot-data-selector] /// @property {Map} igx-highlight [$dark-fluent-highlight], /// @property {Map} igx-icon [$dark-fluent-icon], /// @property {Map} igx-input-group [$dark-fluent-input-group], @@ -289,6 +293,7 @@ $dark-fluent-schema: ( funnel-chart: $dark-fluent-funnel-chart, igx-grid-summary: $dark-fluent-grid-summary, igx-grid-toolbar: $dark-fluent-grid-toolbar, + igx-pivot-data-selector: $dark-fluent-pivot-data-selector, igx-highlight: $dark-fluent-highlight, igx-icon: $dark-fluent-icon, igx-input-group: $dark-fluent-input-group, @@ -354,6 +359,7 @@ $dark-fluent-schema: ( /// @property {Map} funnel-chart [$dark-bootstrap-funnel-chart], /// @property {Map} igx-grid-summary [$dark-bootstrap-grid-summary], /// @property {Map} igx-grid-toolbar [$dark-bootstrap-grid-toolbar], +/// @property {Map} igx-pivot-data-selector [$dark-bootstrap-pivot-data-selector] /// @property {Map} igx-highlight [$dark-bootstrap-highlight], /// @property {Map} igx-icon [$dark-bootstrap-icon], /// @property {Map} igx-input-group [$dark-bootstrap-input-group], @@ -414,6 +420,7 @@ $dark-bootstrap-schema: ( funnel-chart: $dark-bootstrap-funnel-chart, igx-grid-summary: $dark-bootstrap-grid-summary, igx-grid-toolbar: $dark-bootstrap-grid-toolbar, + igx-pivot-data-selector: $dark-bootstrap-pivot-data-selector, igx-highlight: $dark-bootstrap-highlight, igx-icon: $dark-bootstrap-icon, igx-input-group: $dark-bootstrap-input-group, @@ -479,6 +486,7 @@ $dark-bootstrap-schema: ( /// @property {Map} funnel-chart [$dark-indigo-funnel-chart] /// @property {Map} igx-grid-summary [$dark-indigo-grid-summary] /// @property {Map} igx-grid-toolbar [$dark-indigo-grid-toolbar] +/// @property {Map} igx-pivot-data-selector [$dark-indigo-pivot-data-selector] /// @property {Map} igx-highlight [$dark-indigo-highlight] /// @property {Map} igx-icon [$dark-indigo-icon] /// @property {Map} igx-input-group [$dark-indigo-input-group] @@ -539,6 +547,7 @@ $dark-indigo-schema: ( funnel-chart: $dark-indigo-funnel-chart, igx-grid-summary: $dark-indigo-grid-summary, igx-grid-toolbar: $dark-indigo-grid-toolbar, + igx-pivot-data-selector: $dark-indigo-pivot-data-selector, igx-highlight: $dark-indigo-highlight, igx-icon: $dark-indigo-icon, igx-input-group: $dark-indigo-input-group, diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_pivot-data-selector.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_pivot-data-selector.scss new file mode 100644 index 00000000000..044f4ebfd17 --- /dev/null +++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_pivot-data-selector.scss @@ -0,0 +1,27 @@ +@use '../light/pivot-data-selector' as *; + +//// +/// @group schemas +/// @access public +/// @author Simeon Simeonoff +//// + +/// Generates a dark pivot data selector schema. +/// @type {Map} +/// @see $default-palette +$dark-pivot-data-selector: $light-pivot-data-selector; + +/// Generates a dark fluent pivot data selector schema. +/// @type {Map} +/// @requires {Map} $light-pivot-data-selector +$dark-fluent-pivot-data-selector: $fluent-pivot-data-selector; + +/// Generates a dark bootstrap pivot data selector schema. +/// @type {Map} +/// @requires {Map} $light-pivot-data-selector +$dark-bootstrap-pivot-data-selector: $bootstrap-pivot-data-selector; + +/// Generates a dark indigo pivot data selector schema. +/// @type {Map} +/// @requires {Map} $light-pivot-data-selector +$dark-indigo-pivot-data-selector: $indigo-pivot-data-selector; diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_index.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_index.scss index ebcfe2b852b..a11a3a35a16 100644 --- a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_index.scss +++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_index.scss @@ -36,6 +36,7 @@ @use './pagination' as *; @use './grid-summary' as *; @use './grid-toolbar' as *; +@use './pivot-data-selector' as *; @use './highlight' as *; @use './icon' as *; @use './input-group' as *; @@ -99,6 +100,7 @@ /// @property {Map} igx-paginator [$light-pagination] /// @property {Map} igx-grid-summary [$light-grid-summary] /// @property {Map} igx-grid-toolbar [$light-grid-toolbar] +/// @property {Map} igx-pivot-data-selector [$light-pivot-data-selector] /// @property {Map} igx-highlight [$light-highlight] /// @property {Map} igx-icon [$light-icon] /// @property {Map} igx-input-group [$light-input-group] @@ -159,6 +161,7 @@ $light-schema: ( igx-paginator: $light-pagination, igx-grid-summary: $light-grid-summary, igx-grid-toolbar: $light-grid-toolbar, + igx-pivot-data-selector: $light-pivot-data-selector, igx-highlight: $light-highlight, igx-icon: $light-icon, igx-input-group: $light-input-group, @@ -230,6 +233,7 @@ $light-fluent-schema: ( igx-paginator: $fluent-pagination, igx-grid-summary: $fluent-grid-summary, igx-grid-toolbar: $fluent-grid-toolbar, + igx-pivot-data-selector: $fluent-pivot-data-selector, igx-highlight: $fluent-highlight, igx-icon: $fluent-icon, igx-input-group: $fluent-input-group, @@ -296,6 +300,7 @@ $light-bootstrap-schema: ( igx-paginator: $bootstrap-pagination, igx-grid-summary: $bootstrap-grid-summary, igx-grid-toolbar: $bootstrap-grid-toolbar, + igx-pivot-data-selector: $bootstrap-pivot-data-selector, igx-highlight: $bootstrap-highlight, igx-icon: $bootstrap-icon, igx-input-group: $bootstrap-input-group, @@ -362,6 +367,7 @@ $light-indigo-schema: ( igx-paginator: $indigo-pagination, igx-grid-summary: $indigo-grid-summary, igx-grid-toolbar: $indigo-grid-toolbar, + igx-pivot-data-selector: $indigo-pivot-data-selector, igx-highlight: $indigo-highlight, igx-icon: $indigo-icon, igx-input-group: $indigo-input-group, diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_pivot-data-selector.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_pivot-data-selector.scss new file mode 100644 index 00000000000..000823064b2 --- /dev/null +++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_pivot-data-selector.scss @@ -0,0 +1,35 @@ +@use '../../../base' as *; + +//// +/// @group schemas +/// @access public +/// @author Simeon Simeonoff +//// + +/// Generates a light pivot data selector schema. +/// @type {Map} +/// @see $default-palette +$light-pivot-data-selector: ( + background: ( + igx-color: 'surface', + ), + + header-color: ( + igx-color: ('grays', 100) + ) +); + +/// Generates a fluent pivot data selector schema. +/// @type {Map} +/// @requires {Map} $light-pivot-data-selector +$fluent-pivot-data-selector: $light-pivot-data-selector; + +/// Generates a bootstrap pivot data selector schema. +/// @type {Map} +/// @requires {Map} $light-pivot-data-selector +$bootstrap-pivot-data-selector: $light-pivot-data-selector; + +/// Generates a indigo pivot data selector schema. +/// @type {Map} +/// @requires {Map} $light-pivot-data-selector +$indigo-pivot-data-selector: $light-pivot-data-selector; diff --git a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-data-selector.component.html b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-data-selector.component.html new file mode 100644 index 00000000000..7634c23234d --- /dev/null +++ b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-data-selector.component.html @@ -0,0 +1,182 @@ +
+ + search + + + + + + {{ item.memberName }} + + + + {{ item.member }} + + +
+ + + + + +
+ {{ grid.resourceStrings[panel.i18n] }} +
+
+ {{ panel.icon }} + {{ this.grid[panel.dataKey].length }} +
+
+
+ + + +
+
+
+ {{ + item.aggregate.key + }} + ( + {{ item[panel.itemKey] }} + ) +
+ + {{ + item.sortDirection < 2 + ? "arrow_upward" + : "arrow_downward" + }} + +
+
+ filter_list + + + functions + + drag_handle +
+
+
+
+
+ {{ grid.resourceStrings.igx_grid_pivot_selector_panel_empty }} +
+
+
+
+ + + + {{ item.label }} + + + + +
+
+ unfold_more + {{ ghostText }} +
+ drag_handle +
+
diff --git a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-data-selector.component.ts b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-data-selector.component.ts new file mode 100644 index 00000000000..311ef3d7d49 --- /dev/null +++ b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-data-selector.component.ts @@ -0,0 +1,559 @@ +import { useAnimation } from "@angular/animations"; +import { + Component, + HostBinding, + Input, + Renderer2 +} from "@angular/core"; +import { first } from "rxjs/operators"; +import { fadeIn, fadeOut } from "../../animations/fade"; +import { DisplayDensity } from "../../core/displayDensity"; +import { GridColumnDataType } from "../../data-operations/data-util"; +import { SortingDirection } from "../../data-operations/sorting-strategy"; +import { + IDragBaseEventArgs, + IDragGhostBaseEventArgs, + IDropBaseEventArgs, + IDropDroppedEventArgs +} from "../../directives/drag-drop/drag-drop.directive"; +import { ISelectionEventArgs } from "../../drop-down/drop-down.common"; +import { IgxDropDownComponent } from "../../drop-down/drop-down.component"; +import { + AbsoluteScrollStrategy, + AutoPositionStrategy, + OverlaySettings, + PositionSettings, + VerticalAlignment +} from "../../services/public_api"; +import { ColumnType, PivotGridType } from "../common/grid.interface"; +import { + IgxPivotAggregate, + IgxPivotDateAggregate, + IgxPivotTimeAggregate +} from "./pivot-grid-aggregate"; +import { + IPivotAggregator, + IPivotDimension, + IPivotValue, + PivotDimensionType +} from "./pivot-grid.interface"; + +interface IDataSelectorPanel { + name: string; + i18n: string; + type?: PivotDimensionType; + dataKey: string; + icon: string; + itemKey: string; + sortable: boolean; + dragChannels: string[]; +} + +@Component({ + selector: "igx-pivot-data-selector", + templateUrl: "./pivot-data-selector.component.html", +}) +export class IgxPivotDataSelectorComponent { + private _grid: PivotGridType; + private _dropDelta = 0; + + @HostBinding("class.igx-pivot-data-selector") + public cssClass = "igx-pivot-data-selector"; + public dimensions: IPivotDimension[]; + + private _subMenuPositionSettings: PositionSettings = { + verticalStartPoint: VerticalAlignment.Bottom, + closeAnimation: undefined, + }; + + private _subMenuOverlaySettings: OverlaySettings = { + closeOnOutsideClick: true, + modal: false, + positionStrategy: new AutoPositionStrategy( + this._subMenuPositionSettings + ), + scrollStrategy: new AbsoluteScrollStrategy(), + }; + public animationSettings = { + closeAnimation: useAnimation(fadeOut, { + params: { + duration: "0ms", + }, + }), + openAnimation: useAnimation(fadeIn, { + params: { + duration: "0ms", + }, + }), + }; + + /** @hidden @internal */ + public aggregateList: IPivotAggregator[] = []; + /** @hidden @internal */ + public value: IPivotValue; + /** @hidden @internal */ + public ghostText: string; + /** @hidden @internal */ + public ghostWidth: number; + /** @hidden @internal */ + public dropAllowed: boolean; + /** @hidden @internal */ + public dims: IPivotDimension[]; + /** @hidden @internal */ + public values: IPivotValue[]; + + constructor(private renderer: Renderer2) {} + + /** + * @hidden @internal + */ + public _panels: IDataSelectorPanel[] = [ + { + name: "Filters", + i18n: 'igx_grid_pivot_selector_filters', + type: PivotDimensionType.Filter, + dataKey: "filterDimensions", + icon: "filter_list", + itemKey: "memberName", + sortable: false, + dragChannels: ["Filters", "Columns", "Rows"], + }, + { + name: "Columns", + i18n: 'igx_grid_pivot_selector_columns', + type: PivotDimensionType.Column, + dataKey: "columnDimensions", + icon: "view_column", + itemKey: "memberName", + sortable: true, + dragChannels: ["Filters", "Columns", "Rows"], + }, + { + name: "Rows", + i18n: 'igx_grid_pivot_selector_rows', + type: PivotDimensionType.Row, + dataKey: "rowDimensions", + icon: "table_rows", + itemKey: "memberName", + sortable: true, + dragChannels: ["Filters", "Columns", "Rows"], + }, + { + name: "Values", + i18n: 'igx_grid_pivot_selector_values', + type: null, + dataKey: "values", + icon: "functions", + itemKey: "member", + sortable: false, + dragChannels: ["Values"], + }, + ]; + + /** + * @hidden @internal + */ + public get displayDensity(): DisplayDensity { + return this.grid?.displayDensity; + } + + /** + * An @Input property that sets the grid. + */ + @Input() + public set grid(value: PivotGridType) { + this._grid = value; + this.dims = [ + ...this._grid.pivotConfiguration.columns, + ...this._grid.pivotConfiguration.rows, + ...this._grid.pivotConfiguration.filters, + ]; + this.values = this._grid.pivotConfiguration.values; + } + + /** + * Returns the grid. + */ + public get grid(): PivotGridType { + return this._grid; + } + + /** + * @hidden + * @internal + */ + public onItemSort( + _: Event, + dimension: IPivotDimension, + dimensionType: PivotDimensionType + ) { + if ( + !this._panels.find( + (panel: IDataSelectorPanel) => panel.type === dimensionType + ).sortable + ) + return; + + if (!dimension.sortDirection) { + dimension.sortDirection = SortingDirection.None; + } + + dimension.sortDirection = + dimension.sortDirection + 1 > SortingDirection.Desc + ? SortingDirection.None + : dimension.sortDirection + 1; + // apply same sort direction to children. + let dim = dimension; + + while (dim.childLevel) { + dim.childLevel.sortDirection = dimension.sortDirection; + dim = dim.childLevel; + } + + this.grid.pipeTrigger++; + this.grid.cdr.markForCheck(); + + if (dimensionType === PivotDimensionType.Column) { + this.grid.setupColumns(); + } + } + + /** + * @hidden + * @internal + */ + public onFilteringIconPointerDown(event: PointerEvent) { + event.stopPropagation(); + event.preventDefault(); + } + + /** + * @hidden + * @internal + */ + public onFilteringIconClick(event: MouseEvent, dimension: IPivotDimension) { + event.stopPropagation(); + event.preventDefault(); + + let dim = dimension; + let col: ColumnType; + + while (dim) { + col = this.grid.dimensionDataColumns.find( + (x) => x.field === dim.memberName + ); + if (col) { + break; + } else { + dim = dim.childLevel; + } + } + + this.grid.filteringService.toggleFilterDropdown(event.target, col); + } + + /** + * @hidden + * @internal + */ + protected getDimensionState(dimensionType: PivotDimensionType) { + switch (dimensionType) { + case PivotDimensionType.Row: + return this.grid.rowDimensions; + case PivotDimensionType.Column: + return this.grid.columnDimensions; + case PivotDimensionType.Filter: + return this.grid.filterDimensions; + default: + return null; + } + } + + /** + * @hidden + * @internal + */ + protected moveValueItem(itemId: string) { + const aggregation = this.grid.pivotConfiguration.values; + const valueIndex = + aggregation.findIndex((x) => x.member === itemId) !== -1 + ? aggregation?.findIndex((x) => x.member === itemId) + : aggregation.length; + const newValueIndex = + valueIndex + this._dropDelta < 0 ? 0 : valueIndex + this._dropDelta; + + const aggregationItem = aggregation.find( + (x) => x.member === itemId || x.displayName === itemId + ); + + if (aggregationItem) { + this.grid.moveValue(aggregationItem, newValueIndex); + this.grid.valuesChange.emit({ + values: this.grid.pivotConfiguration.values, + }); + } + } + + /** + * @hidden + * @internal + */ + public onItemDropped( + event: IDropDroppedEventArgs, + dimensionType: PivotDimensionType + ) { + if (!this.dropAllowed) { + return; + } + + const dimension = this.grid.getDimensionsByType(dimensionType); + const dimensionState = this.getDimensionState(dimensionType); + const itemId = event.drag.element.nativeElement.id; + const targetId = event.owner.element.nativeElement.id; + const dimensionItem = dimension?.find((x) => x.memberName === itemId); + const itemIndex = + dimension?.findIndex((x) => x?.memberName === itemId) !== -1 + ? dimension?.findIndex((x) => x.memberName === itemId) + : dimension?.length; + const dimensions = this.grid.pivotConfiguration.rows + .concat(this.grid.pivotConfiguration.columns) + .concat(this.grid.pivotConfiguration.filters) + .filter((x) => x && x.memberName === itemId); + + const reorder = + dimensionState?.findIndex((item) => item.memberName === itemId) !== + -1; + + let targetIndex = + targetId !== "" + ? dimension?.findIndex((x) => x.memberName === targetId) + : dimension?.length; + + if (!dimension) { + this.moveValueItem(itemId); + } + + if (reorder) { + targetIndex = + itemIndex + this._dropDelta < 0 + ? 0 + : itemIndex + this._dropDelta; + } + + if (dimensionItem) { + this.grid.moveDimension(dimensionItem, dimensionType, targetIndex); + } else { + const newDim = dimensions.find((x) => x.memberName === itemId); + this.grid.moveDimension(newDim, dimensionType, targetIndex); + } + + this.grid.dimensionsChange.emit({ + dimensions: dimension, + dimensionCollectionType: dimensionType, + }); + } + + /** + * @hidden + * @internal + */ + protected updateDropDown( + value: IPivotValue, + dropdown: IgxDropDownComponent + ) { + this.value = value; + dropdown.width = "200px"; + this.aggregateList = this.getAggregateList(value); + dropdown.open(this._subMenuOverlaySettings); + } + + /** + * @hidden + * @internal + */ + public onSummaryClick( + event: MouseEvent, + value: IPivotValue, + dropdown: IgxDropDownComponent + ) { + this._subMenuOverlaySettings.target = + event.currentTarget as HTMLElement; + + if (dropdown.collapsed) { + this.updateDropDown(value, dropdown); + } else { + // close for previous chip + dropdown.close(); + dropdown.closed.pipe(first()).subscribe(() => { + this.updateDropDown(value, dropdown); + }); + } + } + + /** + * @hidden + * @internal + */ + protected getAggregatorsForValue(value: IPivotValue): IPivotAggregator[] { + const dataType = + value.dataType || + this.grid.resolveDataTypes(this.grid.data[0][value.member]); + switch (dataType) { + case GridColumnDataType.Number: + case GridColumnDataType.Currency: + return IgxPivotDateAggregate.aggregators(); + case GridColumnDataType.Date: + case GridColumnDataType.DateTime: + return IgxPivotDateAggregate.aggregators(); + case GridColumnDataType.Time: + return IgxPivotTimeAggregate.aggregators(); + default: + return IgxPivotAggregate.aggregators(); + } + } + + /** + * @hidden + * @internal + */ + public getAggregateList(val: IPivotValue): IPivotAggregator[] { + if (!val.aggregateList) { + let defaultAggr = this.getAggregatorsForValue(val); + const isDefault = defaultAggr.find( + (x) => x.key === val.aggregate.key + ); + // resolve custom aggregations + if (!isDefault && this.grid.data[0][val.member] !== undefined) { + // if field exists, then we can apply default aggregations and add the custom one. + defaultAggr.unshift(val.aggregate); + } else if (!isDefault) { + // otherwise this is a custom aggregation that is not compatible + // with the defaults, since it operates on field that is not in the data + // leave only the custom one. + defaultAggr = [val.aggregate]; + } + val.aggregateList = defaultAggr; + } + return val.aggregateList; + } + + /** + * @hidden + * @internal + */ + public onAggregationChange(event: ISelectionEventArgs) { + if (!this.isSelected(event.newSelection.value)) { + this.value.aggregate = event.newSelection.value; + this.grid.pipeTrigger++; + this.grid.cdr.markForCheck(); + } + } + + /** + * @hidden + * @internal + */ + public isSelected(val: IPivotAggregator) { + return this.value.aggregate.key === val.key; + } + + /** + * @hidden + * @internal + */ + public ghostCreated(event: IDragGhostBaseEventArgs, value: string) { + const { width: itemWidth } = + event.owner.element.nativeElement.getBoundingClientRect(); + this.ghostWidth = itemWidth; + this.ghostText = value; + this.renderer.setStyle( + event.owner.element.nativeElement, + "position", + "absolute" + ); + this.renderer.setStyle( + event.owner.element.nativeElement, + "visibility", + "hidden" + ); + } + + /** + * @hidden + * @internal + */ + public toggleItem(item: IPivotDimension | IPivotValue) { + if (item as IPivotValue) { + this.grid.toggleValue(item as IPivotValue); + } + + if (item as IPivotDimension) { + this.grid.toggleDimension(item as IPivotDimension); + } + } + + /** + * @hidden + * @internal + */ + public onPanelEntry(event: IDropBaseEventArgs, panel: string) { + this.dropAllowed = event.dragData.some( + (channel: string) => channel === panel + ); + } + + /** + * @hidden + * @internal + */ + public onItemDragMove(event: IDragBaseEventArgs) { + const clientRect = + event.owner.element.nativeElement.getBoundingClientRect(); + this._dropDelta = Math.round( + (event.pageY - event.startY) / clientRect.height + ); + } + + /** + * @hidden + * @internal + */ + public onItemDragEnd(event: IDragBaseEventArgs) { + this.renderer.setStyle( + event.owner.element.nativeElement, + "position", + "static" + ); + this.renderer.setStyle( + event.owner.element.nativeElement, + "visibility", + "visible" + ); + } + + /** + * @hidden + * @internal + */ + public onItemDragOver(event: IDropBaseEventArgs) { + if (this.dropAllowed) { + this.renderer.addClass( + event.owner.element.nativeElement, + "igx-drag--push" + ); + } + } + + /** + * @hidden + * @internal + */ + public onItemDragLeave(event: IDropBaseEventArgs) { + if (this.dropAllowed) { + this.renderer.removeClass( + event.owner.element.nativeElement, + "igx-drag--push" + ); + } + } +} diff --git a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-data-selector.spec.ts b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-data-selector.spec.ts new file mode 100644 index 00000000000..92ccc5fd13b --- /dev/null +++ b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-data-selector.spec.ts @@ -0,0 +1,346 @@ +import { DebugElement } from "@angular/core"; +import { fakeAsync, TestBed } from "@angular/core/testing"; +import { By } from "@angular/platform-browser"; +import { NoopAnimationsModule } from "@angular/platform-browser/animations"; +import { IgxCheckboxComponent } from "../../checkbox/checkbox.component"; +import { DisplayDensity } from "../../core/displayDensity"; +import { SortingDirection } from "../../data-operations/sorting-strategy"; +import { IgxInputDirective } from "../../input-group/public_api"; +import { configureTestSuite } from "../../test-utils/configure-suite"; +import { IgxPivotGridTestBaseComponent } from "../../test-utils/pivot-grid-samples.spec"; +import { UIInteractions } from "../../test-utils/ui-interactions.spec"; +import { PivotGridType } from "../common/grid.interface"; +import { IgxPivotDataSelectorComponent } from "./pivot-data-selector.component"; +import { + IPivotDimension, + IPivotValue, + PivotDimensionType +} from "./pivot-grid.interface"; +import { IgxPivotGridModule } from "./pivot-grid.module"; + +describe("Pivot data selector", () => { + let fixture; + let grid: PivotGridType; + let selector: IgxPivotDataSelectorComponent; + let pivotItems: (IPivotDimension | IPivotValue)[]; + + configureTestSuite(() => { + TestBed.configureTestingModule({ + declarations: [IgxPivotGridTestBaseComponent], + imports: [NoopAnimationsModule, IgxPivotGridModule], + }); + }); + + beforeEach(fakeAsync(() => { + fixture = TestBed.createComponent(IgxPivotGridTestBaseComponent); + fixture.detectChanges(); + grid = fixture.componentInstance.pivotGrid; + selector = fixture.componentInstance.dataSelector; + pivotItems = [ + ...grid.pivotConfiguration.columns, + ...grid.pivotConfiguration.rows, + ...grid.pivotConfiguration.filters, + ...grid.pivotConfiguration.values, + ]; + })); + + it("should set its display density based on the passed grid instance", () => { + grid.displayDensity = DisplayDensity.compact; + fixture.detectChanges(); + expect(selector.displayDensity).toEqual(DisplayDensity.compact); + }); + + it("should render a list of all row, column, filter, and value dimensions", () => { + const valueList = Array.from( + fixture.debugElement + .query(By.directive(IgxPivotDataSelectorComponent)) + .nativeElement.querySelectorAll( + ".igx-pivot-data-selector__filter > igx-list > igx-list-item" + ) as NodeList + ); + + valueList.forEach((li, index) => { + expect(li.textContent).toEqual( + (pivotItems[index] as any).memberName || + (pivotItems[index] as any).member + ); + }); + }); + + it("should filter the dimension list based on a search term", () => { + const term = ( + Object.values( + fixture.componentInstance.pivotConfigHierarchy + )[0][0] as IPivotDimension + ).memberName; + + const inputElement = fixture.debugElement + .query(By.directive(IgxPivotDataSelectorComponent)) + .query(By.directive(IgxInputDirective)).nativeElement; + + inputElement.value = term; + inputElement.dispatchEvent(new Event("input")); + fixture.detectChanges(); + + const valueList = Array.from( + fixture.debugElement + .query(By.directive(IgxPivotDataSelectorComponent)) + .nativeElement.querySelectorAll( + ".igx-pivot-data-selector__filter > igx-list > igx-list-item" + ) as NodeList + ); + + valueList.forEach((li) => { + expect(li.textContent).toContain(term); + }); + + expect(valueList.length).toBe(1); + + // Clear the filter + inputElement.value = undefined; + inputElement.dispatchEvent(new Event("input")); + fixture.detectChanges(); + }); + + it("should enable/disable dimensions from the pivot config on checkbox click", () => { + const dimension = grid.pivotConfiguration.columns[0]; + let items = getPanelItemsByDimensionType(PivotDimensionType.Column); + + const checkbox = fixture.debugElement + .query(By.directive(IgxPivotDataSelectorComponent)) + .queryAll(By.directive(IgxCheckboxComponent)) + .find( + (el: DebugElement) => + el.componentInstance.ariaLabelledBy === dimension.memberName + ); + + // Initial State + expect(dimension.enabled).toBe(true); + expect(items.length).toEqual(grid.pivotConfiguration.columns.length); + checkbox.nativeElement.dispatchEvent(new Event("click")); + + fixture.detectChanges(); + + // After clicking on the checkbox + items = getPanelItemsByDimensionType(PivotDimensionType.Column); + expect(dimension.enabled).toBe(false); + expect(items.length).toEqual( + grid.pivotConfiguration.columns.length - 1 + ); + }); + + it("should sort column and row dimensions on item click", () => { + const colDimension = grid.pivotConfiguration.columns[0]; + const rowDimension = grid.pivotConfiguration.rows[0]; + const colSortEl = getPanelItemsByDimensionType( + PivotDimensionType.Column + ) + .find((item) => item.textContent.includes(colDimension.memberName)) + .parentNode.querySelector(".igx-pivot-data-selector__action-sort"); + const rowSortEl = getPanelItemsByDimensionType(PivotDimensionType.Row) + .find((item) => item.textContent.includes(rowDimension.memberName)) + .parentNode.querySelector(".igx-pivot-data-selector__action-sort"); + + colSortEl.dispatchEvent(new Event("click")); + rowSortEl.dispatchEvent(new Event("click")); + fixture.detectChanges(); + + expect(colDimension.sortDirection).toEqual(SortingDirection.Asc); + expect(rowDimension.sortDirection).toEqual(SortingDirection.Asc); + + colSortEl.dispatchEvent(new Event("click")); + rowSortEl.dispatchEvent(new Event("click")); + fixture.detectChanges(); + + expect(colDimension.sortDirection).toEqual(SortingDirection.Desc); + expect(rowDimension.sortDirection).toEqual(SortingDirection.Desc); + + colSortEl.dispatchEvent(new Event("click")); + rowSortEl.dispatchEvent(new Event("click")); + fixture.detectChanges(); + + expect(colDimension.sortDirection).toEqual(SortingDirection.None); + expect(rowDimension.sortDirection).toEqual(SortingDirection.None); + }); + + it("should render panel header sections for all pivot dimensions", () => { + Object.values(PivotDimensionType).forEach((dt) => { + if (isNaN(Number(dt))) return; + const headerNode = getPanelHeaderByDimensionType( + dt as PivotDimensionType + ); + const headerTitle = selector._panels.find( + (panel) => panel.type === (dt as PivotDimensionType) + ).name; + const dimensionSize = grid.getDimensionsByType( + dt as PivotDimensionType + ).length; + + expect(headerNode.textContent).toContain(headerTitle); + expect(headerNode.textContent).toContain(dimensionSize); + }); + }); + + it("should render panel header section for the values", () => { + const headerNode = getPanelHeaderByDimensionType(null); + const headerTitle = selector._panels.find( + (panel) => panel.type === null + ).name; + const valuesSize = grid.pivotConfiguration.values?.length; + + expect(headerNode.textContent).toContain(headerTitle); + expect(headerNode.textContent).toContain(valuesSize.toString()); + }); + + it("should render a section of all dimension items in a panel", () => { + Object.values(PivotDimensionType).forEach((dt) => { + if (isNaN(Number(dt))) return; + expectConfigToMatchPanels(dt as PivotDimensionType); + }); + }); + + it("should render a section of all value items in a panel", () => { + expectConfigToMatchPanels(null); // pass an invalid type (null) to test for values + }); + + xit("should fire event handlers on reorder in a panel using drag and drop gestures", () => { + // Get all value items + let items = getPanelItemsByDimensionType(null); + + spyOn(selector, "ghostCreated"); + spyOn(selector, "onItemDragMove"); + spyOn(selector, "onItemDragEnd"); + spyOn(selector, "onItemDropped"); + + // Get the drag handle of the last item in the panel + const dragHandle = items[0].parentNode + .querySelectorAll("igx-list-item") + [items.length - 1].querySelector("[igxDragHandle]"); + + const { x: handleX, y: handleY } = dragHandle.getBoundingClientRect(); + + UIInteractions.simulatePointerEvent( + "pointerdown", + dragHandle, + handleX, + handleY + ); + fixture.detectChanges(); + + UIInteractions.simulatePointerEvent( + "pointermove", + dragHandle, + handleX, + handleY - 10 + ); + fixture.detectChanges(); + + const ghost = document.body.querySelector( + ".igx-pivot-data-selector__item-ghost" + ); + expect(selector.ghostCreated).toHaveBeenCalled(); + + UIInteractions.simulatePointerEvent( + "pointermove", + ghost, + handleX, + handleY - 36 + ); + fixture.detectChanges(); + expect(selector.onItemDragMove).toHaveBeenCalled(); + + UIInteractions.simulatePointerEvent( + "pointerup", + ghost, + handleX, + handleY - 36 + ); + fixture.detectChanges(); + + expect(selector.onItemDragEnd).toHaveBeenCalled(); + expect(selector.onItemDropped).toHaveBeenCalled(); + }); + + it("should call filtering menu on column and row filter click", () => { + spyOn(grid.filteringService, "toggleFilterDropdown"); + + let columnItems = getPanelItemsByDimensionType( + PivotDimensionType.Column + ); + let rowItems = getPanelItemsByDimensionType(PivotDimensionType.Row); + + const getFilteringIcon = (item: Node) => + item.parentNode + .querySelector("igx-list-item") + .querySelector(".igx-pivot-data-selector__action-filter"); + + const colFilterActions = columnItems.map(getFilteringIcon); + const rowFilterActions = rowItems.map(getFilteringIcon); + + colFilterActions[0].dispatchEvent(new Event('click')); + fixture.detectChanges(); + + expect(grid.filteringService.toggleFilterDropdown).toHaveBeenCalled(); + + rowFilterActions[0].dispatchEvent(new Event('click')); + fixture.detectChanges(); + + expect(grid.filteringService.toggleFilterDropdown).toHaveBeenCalled(); + }); + + const expectConfigToMatchPanels = (dimensionType: PivotDimensionType) => { + const items = getPanelItemsByDimensionType(dimensionType); + let dimension: IPivotDimension[] | IPivotValue[]; + + switch (dimensionType) { + case PivotDimensionType.Filter: + dimension = grid.pivotConfiguration.filters; + break; + case PivotDimensionType.Column: + dimension = grid.pivotConfiguration.columns; + break; + case PivotDimensionType.Row: + dimension = grid.pivotConfiguration.rows; + break; + default: + dimension = grid.pivotConfiguration.values; + break; + } + + expect(items.length).toEqual(dimension.length); + + items.forEach((li, index) => { + const item = dimension[index] as any; + expect(li.textContent).toContain(item.memberName || item.member); + }); + }; + + const getPanelHeaderByDimensionType = ( + dimensionType: PivotDimensionType + ) => { + const panelIndex = selector._panels.findIndex( + (panel) => panel.type === dimensionType + ); + + return fixture.debugElement + .query(By.directive(IgxPivotDataSelectorComponent)) + .nativeElement.querySelectorAll("igx-expansion-panel-header")[ + panelIndex + ] as Node; + }; + + const getPanelItemsByDimensionType = ( + dimensionType: PivotDimensionType + ) => { + const panelIndex = selector._panels.findIndex( + (panel) => panel.type === dimensionType + ); + + return Array.from( + fixture.debugElement + .query(By.directive(IgxPivotDataSelectorComponent)) + .nativeElement.querySelectorAll("igx-expansion-panel-body") + [panelIndex].querySelectorAll("igx-list-item") as NodeList + ); + }; +}); diff --git a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.module.ts b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.module.ts index 63eefbeabac..394413f2583 100644 --- a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.module.ts +++ b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.module.ts @@ -1,59 +1,70 @@ -import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; -import { IgxGridModule } from '../grid/grid.module'; -import { IgxPivotGridComponent } from './pivot-grid.component'; -import { IgxPivotRowComponent } from './pivot-row.component'; -import { IgxPivotRowPipe, IgxPivotColumnPipe, IgxPivotGridFilterPipe, - IgxPivotRowExpansionPipe, IgxPivotGridSortingPipe, IgxPivotGridColumnSortingPipe, IgxPivotCellMergingPipe, IgxPivotAutoTransform } from './pivot-grid.pipes'; -import { IgxGridComponent } from '../grid/grid.component'; -import { IgxPivotHeaderRowComponent } from './pivot-header-row.component'; -import { IgxPivotRowDimensionContentComponent } from './pivot-row-dimension-content.component'; -import { IgxPivotRowDimensionHeaderGroupComponent } from './pivot-row-dimension-header-group.component'; -import { IgxPivotRowDimensionHeaderComponent } from './pivot-row-dimension-header.component'; - -/** - * @hidden - */ -@NgModule({ - declarations: [ - IgxPivotGridComponent, - IgxPivotRowComponent, - IgxPivotHeaderRowComponent, - IgxPivotRowDimensionContentComponent, - IgxPivotRowDimensionHeaderComponent, - IgxPivotRowDimensionHeaderGroupComponent, - IgxPivotRowPipe, - IgxPivotRowExpansionPipe, +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from "@angular/core"; +import { IgxDragDropModule } from "../../directives/drag-drop/drag-drop.directive"; +import { IgxExpansionPanelModule } from "../../expansion-panel/expansion-panel.module"; +import { IgxGridComponent } from "../grid/grid.component"; +import { IgxGridModule } from "../grid/grid.module"; +import { IgxPivotDataSelectorComponent } from "./pivot-data-selector.component"; +import { IgxPivotGridComponent } from "./pivot-grid.component"; +import { + IgxFilterPivotItemsPipe, IgxPivotAutoTransform, + IgxPivotCellMergingPipe, IgxPivotColumnPipe, - IgxPivotGridFilterPipe, - IgxPivotGridSortingPipe, IgxPivotGridColumnSortingPipe, - IgxPivotCellMergingPipe - ], - exports: [ - IgxGridModule, - IgxPivotGridComponent, - IgxPivotRowComponent, - IgxPivotHeaderRowComponent, - IgxPivotRowDimensionContentComponent, - IgxPivotRowDimensionHeaderComponent, - IgxPivotRowDimensionHeaderGroupComponent, - IgxPivotRowExpansionPipe, - IgxPivotAutoTransform, - IgxPivotRowPipe, - IgxPivotColumnPipe, IgxPivotGridFilterPipe, IgxPivotGridSortingPipe, - IgxPivotGridColumnSortingPipe, - IgxPivotCellMergingPipe - ], - imports: [ - IgxGridModule, - ], - entryComponents: [ - IgxGridComponent - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA] + IgxPivotRowExpansionPipe, + IgxPivotRowPipe +} from "./pivot-grid.pipes"; +import { IgxPivotHeaderRowComponent } from "./pivot-header-row.component"; +import { IgxPivotRowDimensionContentComponent } from "./pivot-row-dimension-content.component"; +import { IgxPivotRowDimensionHeaderGroupComponent } from "./pivot-row-dimension-header-group.component"; +import { IgxPivotRowDimensionHeaderComponent } from "./pivot-row-dimension-header.component"; +import { IgxPivotRowComponent } from "./pivot-row.component"; + +/** + * @hidden + */ +@NgModule({ + declarations: [ + IgxPivotGridComponent, + IgxPivotRowComponent, + IgxPivotHeaderRowComponent, + IgxPivotRowDimensionContentComponent, + IgxPivotRowDimensionHeaderComponent, + IgxPivotRowDimensionHeaderGroupComponent, + IgxPivotRowPipe, + IgxPivotRowExpansionPipe, + IgxPivotAutoTransform, + IgxPivotColumnPipe, + IgxPivotGridFilterPipe, + IgxPivotGridSortingPipe, + IgxPivotGridColumnSortingPipe, + IgxPivotCellMergingPipe, + IgxFilterPivotItemsPipe, + IgxPivotDataSelectorComponent, + ], + exports: [ + IgxGridModule, + IgxPivotGridComponent, + IgxPivotRowComponent, + IgxPivotHeaderRowComponent, + IgxPivotRowDimensionContentComponent, + IgxPivotRowDimensionHeaderComponent, + IgxPivotRowDimensionHeaderGroupComponent, + IgxPivotRowExpansionPipe, + IgxPivotAutoTransform, + IgxPivotRowPipe, + IgxPivotColumnPipe, + IgxPivotGridFilterPipe, + IgxPivotGridSortingPipe, + IgxPivotGridColumnSortingPipe, + IgxPivotCellMergingPipe, + IgxFilterPivotItemsPipe, + IgxPivotDataSelectorComponent, + ], + imports: [IgxGridModule, IgxExpansionPanelModule, IgxDragDropModule], + entryComponents: [IgxGridComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA], }) -export class IgxPivotGridModule { -} +export class IgxPivotGridModule {} diff --git a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.pipes.ts b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.pipes.ts index 342d89fba7e..8e53594d820 100644 --- a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.pipes.ts +++ b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.pipes.ts @@ -3,19 +3,18 @@ import { cloneArray } from '../../core/utils'; import { DataUtil } from '../../data-operations/data-util'; import { FilteringExpressionsTree, IFilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree'; import { IFilteringStrategy } from '../../data-operations/filtering-strategy'; -import { DEFAULT_PIVOT_KEYS, IPivotConfiguration, IPivotDimension, IPivotGridGroupRecord, IPivotGridRecord, IPivotKeys, PivotDimensionType } from './pivot-grid.interface'; import { DefaultPivotGridRecordSortingStrategy, - DefaultPivotSortingStrategy, DimensionValuesFilteringStrategy, NoopPivotDimensionsStrategy, PivotColumnDimensionsStrategy, + DefaultPivotSortingStrategy, DimensionValuesFilteringStrategy, PivotColumnDimensionsStrategy, PivotRowDimensionsStrategy } from '../../data-operations/pivot-strategy'; -import { PivotUtil } from './pivot-util'; -import { FilteringLogic } from '../../data-operations/filtering-expression.interface'; import { ISortingExpression, SortingDirection } from '../../data-operations/sorting-strategy'; -import { GridType, IGX_GRID_BASE } from '../common/grid.interface'; import { GridBaseAPIService } from '../api.service'; -import { IgxGridBaseDirective } from '../grid-base.directive'; +import { GridType, IGX_GRID_BASE } from '../common/grid.interface'; import { IGridSortingStrategy } from '../common/strategy'; +import { IgxGridBaseDirective } from '../grid-base.directive'; +import { DEFAULT_PIVOT_KEYS, IPivotConfiguration, IPivotDimension, IPivotGridGroupRecord, IPivotGridRecord, IPivotKeys, IPivotValue } from './pivot-grid.interface'; +import { PivotUtil } from './pivot-util'; /** * @hidden @@ -330,3 +329,36 @@ export class IgxPivotGridSortingPipe implements PipeTransform { return result; } } + +/** + * @hidden + */ +@Pipe({ name: "filterPivotItems" }) +export class IgxFilterPivotItemsPipe implements PipeTransform { + public transform( + collection: (IPivotDimension | IPivotValue)[], + filterCriteria: string, + _pipeTrigger: number + ): any[] { + if (!collection) { + return collection; + } + let copy = collection.slice(0); + if (filterCriteria && filterCriteria.length > 0) { + const filterFunc = (c) => { + const filterText = c.member || c.memberName; + if (!filterText) { + return false; + } + return ( + filterText + .toLocaleLowerCase() + .indexOf(filterCriteria.toLocaleLowerCase()) >= 0 || + (c.children?.some(filterFunc) ?? false) + ); + }; + copy = collection.filter(filterFunc); + } + return copy; + } +} diff --git a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.spec.ts b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.spec.ts index 3e875064b45..8db906569a6 100644 --- a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.spec.ts @@ -1,20 +1,21 @@ import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { IgxChipComponent } from '../../chips/chip.component'; import { FilteringExpressionsTree, FilteringLogic, IgxPivotGridComponent, IgxPivotRowDimensionHeaderGroupComponent, IgxStringFilteringOperand } from 'igniteui-angular'; +import { IgxChipComponent } from '../../chips/chip.component'; import { IgxChipsAreaComponent } from '../../chips/chips-area.component'; import { configureTestSuite } from '../../test-utils/configure-suite'; import { GridFunctions, GridSelectionFunctions } from '../../test-utils/grid-functions.spec'; +import { PivotGridFunctions } from '../../test-utils/pivot-grid-functions.spec'; import { IgxPivotGridTestBaseComponent, IgxPivotGridTestComplexHierarchyComponent, IgxTotalSaleAggregate } from '../../test-utils/pivot-grid-samples.spec'; import { UIInteractions } from '../../test-utils/ui-interactions.spec'; +import { IgxPivotDateAggregate, IgxPivotNumericAggregate } from './pivot-grid-aggregate'; +import { IgxPivotDateDimension } from './pivot-grid-dimensions'; import { IPivotGridRecord, PivotDimensionType } from './pivot-grid.interface'; +import { IgxPivotGridModule } from './pivot-grid.module'; import { IgxPivotHeaderRowComponent } from './pivot-header-row.component'; -import { IgxPivotDateDimension, IgxPivotGridModule } from './public_api'; import { IgxPivotRowDimensionHeaderComponent } from './pivot-row-dimension-header.component'; -import { IgxPivotDateAggregate, IgxPivotNumericAggregate } from './pivot-grid-aggregate'; import { IgxPivotRowComponent } from './pivot-row.component'; -import { PivotGridFunctions } from '../../test-utils/pivot-grid-functions.spec'; const CSS_CLASS_DROP_DOWN_BASE = 'igx-drop-down'; const CSS_CLASS_LIST = 'igx-drop-down__list'; const CSS_CLASS_ITEM = 'igx-drop-down__item'; @@ -896,7 +897,7 @@ describe('IgxPivotGrid #pivotGrid', () => { fixture.detectChanges(); let dropDown = fixture.debugElement.queryAll(By.css(`.${CSS_CLASS_LIST}`)); - expect(dropDown.length).toBe(1); + expect(dropDown.length).toBe(2); const valueChipUnitPrice = headerRow.querySelector('igx-chip[id="UnitPrice"]'); @@ -905,7 +906,7 @@ describe('IgxPivotGrid #pivotGrid', () => { fixture.detectChanges(); dropDown = fixture.debugElement.queryAll(By.css(`.${CSS_CLASS_LIST}`)); - expect(dropDown.length).toBe(1); + expect(dropDown.length).toBe(2); }); it('should allow reorder in row chip area.', () => { @@ -1677,4 +1678,4 @@ describe('IgxPivotGrid #pivotGrid', () => { expect(valueCols[1].header).toBe('Amount of Sale'); }); }); -}); \ No newline at end of file +}); diff --git a/projects/igniteui-angular/src/lib/grids/pivot-grid/public_api.ts b/projects/igniteui-angular/src/lib/grids/pivot-grid/public_api.ts index 8a244b38447..5d57c0ff77f 100644 --- a/projects/igniteui-angular/src/lib/grids/pivot-grid/public_api.ts +++ b/projects/igniteui-angular/src/lib/grids/pivot-grid/public_api.ts @@ -8,4 +8,5 @@ export * from './pivot-row.component'; export * from './pivot-header-row.component'; export * from './pivot-row-dimension-content.component'; export * from './pivot-row-dimension-header-group.component'; +export * from './pivot-data-selector.component'; export * from './pivot-row-dimension-header.component'; diff --git a/projects/igniteui-angular/src/lib/test-utils/pivot-grid-samples.spec.ts b/projects/igniteui-angular/src/lib/test-utils/pivot-grid-samples.spec.ts index f2a6e245e63..ad39c0f0ea5 100644 --- a/projects/igniteui-angular/src/lib/test-utils/pivot-grid-samples.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/pivot-grid-samples.spec.ts @@ -1,4 +1,5 @@ import { Component, TemplateRef, ViewChild } from '@angular/core'; +import { IgxPivotDataSelectorComponent } from '../grids/pivot-grid/pivot-data-selector.component'; import { IgxPivotNumericAggregate } from '../grids/pivot-grid/pivot-grid-aggregate'; import { IgxPivotGridComponent } from '../grids/pivot-grid/pivot-grid.component'; import { IPivotConfiguration, PivotAggregation } from '../grids/pivot-grid/pivot-grid.interface'; @@ -8,6 +9,7 @@ import { IPivotConfiguration, PivotAggregation } from '../grids/pivot-grid/pivot + Custom empty template. @@ -17,6 +19,7 @@ export class IgxPivotGridTestBaseComponent { public defaultExpand = true; @ViewChild('emptyTemplate', { read: TemplateRef, static: true }) public emptyTemplate: TemplateRef; @ViewChild('grid', { read: IgxPivotGridComponent, static: true }) public pivotGrid: IgxPivotGridComponent; + @ViewChild('selector', { read: IgxPivotDataSelectorComponent, static: true}) public dataSelector: IgxPivotDataSelectorComponent; public data; public cellClasses; @@ -99,7 +102,7 @@ export class IgxPivotGridTestBaseComponent { dataType: 'currency' } ], - filters: null + filters: [] }; } public callback = (rowData: any, columnKey: any) => rowData[columnKey] >= 5; diff --git a/src/app/pivot-grid/pivot-grid.sample.html b/src/app/pivot-grid/pivot-grid.sample.html index 3511f82f779..7da17f0ba48 100644 --- a/src/app/pivot-grid/pivot-grid.sample.html +++ b/src/app/pivot-grid/pivot-grid.sample.html @@ -1,32 +1,64 @@
- +
- - - + + +
- - - - + + + + - - - - + + + +
-
- - +
+ + +
diff --git a/src/app/pivot-grid/pivot-grid.sample.scss b/src/app/pivot-grid/pivot-grid.sample.scss index 4bb0a5c23f5..020b4629315 100644 --- a/src/app/pivot-grid/pivot-grid.sample.scss +++ b/src/app/pivot-grid/pivot-grid.sample.scss @@ -1,13 +1,11 @@ :host { display: flex; flex-direction: column; - height: 100%; } .density-chooser { max-width: 60%; min-width: 400px; - } igx-pivot-grid { @@ -42,4 +40,16 @@ igx-pivot-grid { .downFont1 { color: yellow; } + + igx-pivot-data-selector { + border: 1px solid hsla(var(--igx-grays-200)); + margin: 0 8px; + } +} + +.pivot-container { + display: flex; + align-items: flex-start; + flex: 1 1 auto; + order: 0; }