@reforgium/data-grid 2.2.2 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -593,42 +593,82 @@ import { DataGridColumnManager } from '@reforgium/data-grid/column-manager';
593
593
  <re-data-grid [columns]="managedColumns()" ... />
594
594
  ```
595
595
 
596
- Custom trigger template:
597
-
598
- ```html
599
-
600
- <ng-template #cmTrigger let-label let-visible="visible" let-total="total">
601
- <span>{{ label }}</span>
602
- <strong>{{ visible }}/{{ total }}</strong>
603
- </ng-template>
604
-
605
- <re-data-grid-column-manager
606
- [columns]="managedColumns()"
607
- [triggerTemplate]="cmTrigger"
608
- (columnsChange)="managedColumns.set($event)"
609
- />
610
- ```
611
-
612
- Trigger template context:
613
-
614
- - `$implicit` - trigger label
615
- - `visible` - visible columns count
616
- - `total` - total columns count
617
-
618
- Inputs:
619
-
620
- - `columns: GridColumn<T>[]`
621
- - `triggerLabel?: string`
622
- - `triggerTemplate?: TemplateRef<{ $implicit: string; visible: number; total: number }>`
623
- - `controlsVisible?: boolean` - hides search and "show all / hide optional" panel
624
- - `searchable?: boolean`
625
- - `allowReorder?: boolean`
626
- - `allowPin?: boolean`
627
- - `allowVisibility?: boolean`
628
-
629
- Outputs:
630
-
631
- - `columnsChange: GridColumn<T>[]`
596
+ Custom trigger via content projection:
597
+
598
+ ```html
599
+
600
+ <re-data-grid-column-manager
601
+ triggerLabel="Columns"
602
+ [columns]="managedColumns()"
603
+ (columnsChange)="managedColumns.set($event)"
604
+ >
605
+ <span reDataGridColumnManagerTrigger>Manage columns</span>
606
+ </re-data-grid-column-manager>
607
+ ```
608
+
609
+ Custom column title template (controls stay built-in):
610
+
611
+ ```html
612
+ <re-data-grid-column-manager
613
+ [columns]="managedColumns()"
614
+ (columnsChange)="managedColumns.set($event)"
615
+ >
616
+ <ng-template reDataGridColumnManagerColumnTitle let-title let-column="column">
617
+ <span class="font-medium">{{ title }}</span>
618
+ </ng-template>
619
+ </re-data-grid-column-manager>
620
+ ```
621
+
622
+ `reDataGridColumnManagerColumnTitle` context:
623
+
624
+ - `$implicit` / `title` - resolved column title (`header || key`)
625
+ - `column` - current `GridColumn<T>`
626
+
627
+ Standalone imports for custom trigger/title markers:
628
+
629
+ ```ts
630
+ import {
631
+ DataGridColumnManager,
632
+ DataGridColumnManagerColumnTitleDirective,
633
+ DataGridColumnManagerTriggerDirective,
634
+ } from '@reforgium/data-grid/column-manager';
635
+ ```
636
+
637
+ ```ts
638
+ @Component({
639
+ imports: [
640
+ DataGridColumnManager,
641
+ DataGridColumnManagerTriggerDirective,
642
+ DataGridColumnManagerColumnTitleDirective,
643
+ ],
644
+ })
645
+ export class ExampleComponent {}
646
+ ```
647
+
648
+ Example with both trigger and column title customizations:
649
+
650
+ ```html
651
+ <re-data-grid-column-manager [columns]="managedColumns()" (columnsChange)="managedColumns.set($event)">
652
+ <span reDataGridColumnManagerTrigger>Manage columns</span>
653
+ <ng-template reDataGridColumnManagerColumnTitle let-title>
654
+ <span>{{ title }}</span>
655
+ </ng-template>
656
+ </re-data-grid-column-manager>
657
+ ```
658
+
659
+ Inputs:
660
+
661
+ - `columns: GridColumn<T>[]`
662
+ - `triggerLabel?: string`
663
+ - `controlsVisible?: boolean` - hides search and "show all / hide optional" panel
664
+ - `searchable?: boolean`
665
+ - `allowReorder?: boolean`
666
+ - `allowPin?: boolean`
667
+ - `allowVisibility?: boolean`
668
+
669
+ Outputs:
670
+
671
+ - `columnsChange: GridColumn<T>[]`
632
672
 
633
673
  ### Column manager CSS Variables
634
674
 
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, input, booleanAttribute, output, signal, viewChild, computed, effect } from '@angular/core';
2
+ import { inject, TemplateRef, Directive, Component, input, booleanAttribute, ElementRef, output, contentChild, signal, viewChild, computed, effect, afterNextRender } from '@angular/core';
3
3
  import { NgTemplateOutlet } from '@angular/common';
4
4
 
5
5
  const isVisible = (column) => column.visible !== false;
@@ -61,31 +61,52 @@ function setColumnVisibility(columns, key, visible) {
61
61
  return next;
62
62
  }
63
63
 
64
+ class DataGridColumnManagerColumnTitleDirective {
65
+ template = inject((TemplateRef));
66
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridColumnManagerColumnTitleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
67
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: DataGridColumnManagerColumnTitleDirective, isStandalone: true, selector: "ng-template[reDataGridColumnManagerColumnTitle]", ngImport: i0 });
68
+ }
69
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridColumnManagerColumnTitleDirective, decorators: [{
70
+ type: Directive,
71
+ args: [{
72
+ selector: 'ng-template[reDataGridColumnManagerColumnTitle]',
73
+ standalone: true,
74
+ }]
75
+ }] });
76
+
77
+ class DataGridColumnManagerTriggerDirective {
78
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridColumnManagerTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
79
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: DataGridColumnManagerTriggerDirective, isStandalone: true, selector: "[reDataGridColumnManagerTrigger]", ngImport: i0 });
80
+ }
81
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridColumnManagerTriggerDirective, decorators: [{
82
+ type: Directive,
83
+ args: [{
84
+ selector: '[reDataGridColumnManagerTrigger]',
85
+ standalone: true,
86
+ }]
87
+ }] });
88
+
64
89
  class CrossIcon {
65
90
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: CrossIcon, deps: [], target: i0.ɵɵFactoryTarget.Component });
66
91
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.1", type: CrossIcon, isStandalone: true, selector: "re-cross-ic", ngImport: i0, template: `
67
- <svg width="16" height="16" viewBox="0 0 20 18" fill="none" xmlns="http://www.w3.org/2000/svg">
68
- <svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
69
- <path
70
- d="M10.1958 7.3658L14.4358 3.1258C14.5295 3.03284 14.6039 2.92223 14.6547 2.80037C14.7055 2.67852 14.7316 2.54781 14.7316 2.4158C14.7316 2.28379 14.7055 2.15308 14.6547 2.03122C14.6039 1.90936 14.5295 1.79876 14.4358 1.7058L13.0258 0.295798C12.9328 0.20207 12.8222 0.127676 12.7004 0.0769072C12.5785 0.0261385 12.4478 0 12.3158 0C12.1838 0 12.0531 0.0261385 11.9312 0.0769072C11.8094 0.127676 11.6988 0.20207 11.6058 0.295798L7.3658 4.5358L3.1258 0.295798C3.03284 0.20207 2.92223 0.127676 2.80037 0.0769072C2.67852 0.0261385 2.54781 0 2.4158 0C2.28379 0 2.15308 0.0261385 2.03122 0.0769072C1.90936 0.127676 1.79876 0.20207 1.7058 0.295798L0.295798 1.7058C0.20207 1.79876 0.127676 1.90936 0.0769072 2.03122C0.0261385 2.15308 0 2.28379 0 2.4158C0 2.54781 0.0261385 2.67852 0.0769072 2.80037C0.127676 2.92223 0.20207 3.03284 0.295798 3.1258L4.5358 7.3658L0.295798 11.6058C0.20207 11.6988 0.127676 11.8094 0.0769072 11.9312C0.0261385 12.0531 0 12.1838 0 12.3158C0 12.4478 0.0261385 12.5785 0.0769072 12.7004C0.127676 12.8222 0.20207 12.9328 0.295798 13.0258L1.7058 14.4358C1.79876 14.5295 1.90936 14.6039 2.03122 14.6547C2.15308 14.7055 2.28379 14.7316 2.4158 14.7316C2.54781 14.7316 2.67852 14.7055 2.80037 14.6547C2.92223 14.6039 3.03284 14.5295 3.1258 14.4358L7.3658 10.1958L11.6058 14.4358C11.6988 14.5295 11.8094 14.6039 11.9312 14.6547C12.0531 14.7055 12.1838 14.7316 12.3158 14.7316C12.4478 14.7316 12.5785 14.7055 12.7004 14.6547C12.8222 14.6039 12.9328 14.5295 13.0258 14.4358L14.4358 13.0258C14.5295 12.9328 14.6039 12.8222 14.6547 12.7004C14.7055 12.5785 14.7316 12.4478 14.7316 12.3158C14.7316 12.1838 14.7055 12.0531 14.6547 11.9312C14.6039 11.8094 14.5295 11.6988 14.4358 11.6058L10.1958 7.3658Z"
71
- fill="var(--re-data-grid-cross-ic-surface)"
72
- />
73
- </svg>
92
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
93
+ <path
94
+ d="M10.3052 8L13.759 4.5462C13.8354 4.47048 13.896 4.38038 13.9374 4.28111C13.9787 4.18186 14 4.07538 14 3.96785C14 3.86032 13.9787 3.75385 13.9374 3.65458C13.896 3.55532 13.8354 3.46523 13.759 3.3895L12.6105 2.24095C12.5347 2.1646 12.4447 2.104 12.3454 2.06265C12.2461 2.02129 12.1397 2 12.0321 2C11.9246 2 11.8182 2.02129 11.7189 2.06265C11.6196 2.104 11.5296 2.1646 11.4538 2.24095L8 5.69475L4.5462 2.24095C4.47048 2.1646 4.38038 2.104 4.28111 2.06265C4.18186 2.02129 4.07538 2 3.96785 2C3.86032 2 3.75385 2.02129 3.65458 2.06265C3.55532 2.104 3.46523 2.1646 3.3895 2.24095L2.24095 3.3895C2.1646 3.46523 2.104 3.55532 2.06265 3.65458C2.02129 3.75385 2 3.86032 2 3.96785C2 4.07538 2.02129 4.18186 2.06265 4.28111C2.104 4.38038 2.1646 4.47048 2.24095 4.5462L5.69475 8L2.24095 11.4538C2.1646 11.5296 2.104 11.6196 2.06265 11.7189C2.02129 11.8182 2 11.9246 2 12.0321C2 12.1397 2.02129 12.2461 2.06265 12.3454C2.104 12.4447 2.1646 12.5347 2.24095 12.6105L3.3895 13.759C3.46523 13.8354 3.55532 13.896 3.65458 13.9374C3.75385 13.9787 3.86032 14 3.96785 14C4.07538 14 4.18186 13.9787 4.28111 13.9374C4.38038 13.896 4.47048 13.8354 4.5462 13.759L8 10.3052L11.4538 13.759C11.5296 13.8354 11.6196 13.896 11.7189 13.9374C11.8182 13.9787 11.9246 14 12.0321 14C12.1397 14 12.2461 13.9787 12.3454 13.9374C12.4447 13.896 12.5347 13.8354 12.6105 13.759L13.759 12.6105C13.8354 12.5347 13.896 12.4447 13.9374 12.3454C13.9787 12.2461 14 12.1397 14 12.0321C14 11.9246 13.9787 11.8182 13.9374 11.7189C13.896 11.6196 13.8354 11.5296 13.759 11.4538L10.3052 8Z"
95
+ fill="var(--re-data-grid-cross-ic-surface)"
96
+ />
74
97
  </svg>
75
- `, isInline: true, styles: [":host{--re-data-grid-cross-ic-surface: currentColor}\n"] });
98
+ `, isInline: true, styles: [":host{--re-data-grid-cross-ic-surface: currentColor;display:inline-block;width:16px;height:16px}\n"] });
76
99
  }
77
100
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: CrossIcon, decorators: [{
78
101
  type: Component,
79
102
  args: [{ selector: 're-cross-ic', template: `
80
- <svg width="16" height="16" viewBox="0 0 20 18" fill="none" xmlns="http://www.w3.org/2000/svg">
81
- <svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
82
- <path
83
- d="M10.1958 7.3658L14.4358 3.1258C14.5295 3.03284 14.6039 2.92223 14.6547 2.80037C14.7055 2.67852 14.7316 2.54781 14.7316 2.4158C14.7316 2.28379 14.7055 2.15308 14.6547 2.03122C14.6039 1.90936 14.5295 1.79876 14.4358 1.7058L13.0258 0.295798C12.9328 0.20207 12.8222 0.127676 12.7004 0.0769072C12.5785 0.0261385 12.4478 0 12.3158 0C12.1838 0 12.0531 0.0261385 11.9312 0.0769072C11.8094 0.127676 11.6988 0.20207 11.6058 0.295798L7.3658 4.5358L3.1258 0.295798C3.03284 0.20207 2.92223 0.127676 2.80037 0.0769072C2.67852 0.0261385 2.54781 0 2.4158 0C2.28379 0 2.15308 0.0261385 2.03122 0.0769072C1.90936 0.127676 1.79876 0.20207 1.7058 0.295798L0.295798 1.7058C0.20207 1.79876 0.127676 1.90936 0.0769072 2.03122C0.0261385 2.15308 0 2.28379 0 2.4158C0 2.54781 0.0261385 2.67852 0.0769072 2.80037C0.127676 2.92223 0.20207 3.03284 0.295798 3.1258L4.5358 7.3658L0.295798 11.6058C0.20207 11.6988 0.127676 11.8094 0.0769072 11.9312C0.0261385 12.0531 0 12.1838 0 12.3158C0 12.4478 0.0261385 12.5785 0.0769072 12.7004C0.127676 12.8222 0.20207 12.9328 0.295798 13.0258L1.7058 14.4358C1.79876 14.5295 1.90936 14.6039 2.03122 14.6547C2.15308 14.7055 2.28379 14.7316 2.4158 14.7316C2.54781 14.7316 2.67852 14.7055 2.80037 14.6547C2.92223 14.6039 3.03284 14.5295 3.1258 14.4358L7.3658 10.1958L11.6058 14.4358C11.6988 14.5295 11.8094 14.6039 11.9312 14.6547C12.0531 14.7055 12.1838 14.7316 12.3158 14.7316C12.4478 14.7316 12.5785 14.7055 12.7004 14.6547C12.8222 14.6039 12.9328 14.5295 13.0258 14.4358L14.4358 13.0258C14.5295 12.9328 14.6039 12.8222 14.6547 12.7004C14.7055 12.5785 14.7316 12.4478 14.7316 12.3158C14.7316 12.1838 14.7055 12.0531 14.6547 11.9312C14.6039 11.8094 14.5295 11.6988 14.4358 11.6058L10.1958 7.3658Z"
84
- fill="var(--re-data-grid-cross-ic-surface)"
85
- />
86
- </svg>
103
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
104
+ <path
105
+ d="M10.3052 8L13.759 4.5462C13.8354 4.47048 13.896 4.38038 13.9374 4.28111C13.9787 4.18186 14 4.07538 14 3.96785C14 3.86032 13.9787 3.75385 13.9374 3.65458C13.896 3.55532 13.8354 3.46523 13.759 3.3895L12.6105 2.24095C12.5347 2.1646 12.4447 2.104 12.3454 2.06265C12.2461 2.02129 12.1397 2 12.0321 2C11.9246 2 11.8182 2.02129 11.7189 2.06265C11.6196 2.104 11.5296 2.1646 11.4538 2.24095L8 5.69475L4.5462 2.24095C4.47048 2.1646 4.38038 2.104 4.28111 2.06265C4.18186 2.02129 4.07538 2 3.96785 2C3.86032 2 3.75385 2.02129 3.65458 2.06265C3.55532 2.104 3.46523 2.1646 3.3895 2.24095L2.24095 3.3895C2.1646 3.46523 2.104 3.55532 2.06265 3.65458C2.02129 3.75385 2 3.86032 2 3.96785C2 4.07538 2.02129 4.18186 2.06265 4.28111C2.104 4.38038 2.1646 4.47048 2.24095 4.5462L5.69475 8L2.24095 11.4538C2.1646 11.5296 2.104 11.6196 2.06265 11.7189C2.02129 11.8182 2 11.9246 2 12.0321C2 12.1397 2.02129 12.2461 2.06265 12.3454C2.104 12.4447 2.1646 12.5347 2.24095 12.6105L3.3895 13.759C3.46523 13.8354 3.55532 13.896 3.65458 13.9374C3.75385 13.9787 3.86032 14 3.96785 14C4.07538 14 4.18186 13.9787 4.28111 13.9374C4.38038 13.896 4.47048 13.8354 4.5462 13.759L8 10.3052L11.4538 13.759C11.5296 13.8354 11.6196 13.896 11.7189 13.9374C11.8182 13.9787 11.9246 14 12.0321 14C12.1397 14 12.2461 13.9787 12.3454 13.9374C12.4447 13.896 12.5347 13.8354 12.6105 13.759L13.759 12.6105C13.8354 12.5347 13.896 12.4447 13.9374 12.3454C13.9787 12.2461 14 12.1397 14 12.0321C14 11.9246 13.9787 11.8182 13.9374 11.7189C13.896 11.6196 13.8354 11.5296 13.759 11.4538L10.3052 8Z"
106
+ fill="var(--re-data-grid-cross-ic-surface)"
107
+ />
87
108
  </svg>
88
- `, styles: [":host{--re-data-grid-cross-ic-surface: currentColor}\n"] }]
109
+ `, styles: [":host{--re-data-grid-cross-ic-surface: currentColor;display:inline-block;width:16px;height:16px}\n"] }]
89
110
  }] });
90
111
 
91
112
  class EyeIcon {
@@ -147,7 +168,7 @@ class PinIcon {
147
168
  fill="var(--re-data-grid-pin-ic-surface)"
148
169
  />
149
170
  </svg>
150
- `, isInline: true, styles: [":host{--re-data-grid-pin-ic-surface: currentColor}.toRight{transform:rotate(-90deg)}\n"] });
171
+ `, isInline: true, styles: [":host{--re-data-grid-pin-ic-surface: currentColor;display:inline-block;width:16px;height:16px}.toRight{transform:rotate(-90deg)}\n"] });
151
172
  }
152
173
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: PinIcon, decorators: [{
153
174
  type: Component,
@@ -165,14 +186,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
165
186
  fill="var(--re-data-grid-pin-ic-surface)"
166
187
  />
167
188
  </svg>
168
- `, styles: [":host{--re-data-grid-pin-ic-surface: currentColor}.toRight{transform:rotate(-90deg)}\n"] }]
189
+ `, styles: [":host{--re-data-grid-pin-ic-surface: currentColor;display:inline-block;width:16px;height:16px}.toRight{transform:rotate(-90deg)}\n"] }]
169
190
  }], propDecorators: { toRight: [{ type: i0.Input, args: [{ isSignal: true, alias: "toRight", required: false }] }] } });
170
191
 
171
- // noinspection CssUnresolvedCustomProperty
172
192
  class DataGridColumnManager {
193
+ host = inject((ElementRef));
173
194
  columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
174
195
  triggerLabel = input('Columns', ...(ngDevMode ? [{ debugName: "triggerLabel" }] : []));
175
- triggerTemplate = input(undefined, ...(ngDevMode ? [{ debugName: "triggerTemplate" }] : []));
176
196
  controlsVisible = input(true, { ...(ngDevMode ? { debugName: "controlsVisible" } : {}), transform: booleanAttribute });
177
197
  searchable = input(true, { ...(ngDevMode ? { debugName: "searchable" } : {}), transform: booleanAttribute });
178
198
  searchPlaceholder = input('Search columns...', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : []));
@@ -180,11 +200,17 @@ class DataGridColumnManager {
180
200
  allowPin = input(true, { ...(ngDevMode ? { debugName: "allowPin" } : {}), transform: booleanAttribute });
181
201
  allowVisibility = input(true, { ...(ngDevMode ? { debugName: "allowVisibility" } : {}), transform: booleanAttribute });
182
202
  columnsChange = output();
203
+ triggerDirective = contentChild(DataGridColumnManagerTriggerDirective, ...(ngDevMode ? [{ debugName: "triggerDirective" }] : []));
204
+ columnTitleTemplate = contentChild((DataGridColumnManagerColumnTitleDirective), ...(ngDevMode ? [{ debugName: "columnTitleTemplate" }] : []));
183
205
  state = signal([], ...(ngDevMode ? [{ debugName: "state" }] : []));
184
206
  searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : []));
185
207
  draggingKey = signal(null, ...(ngDevMode ? [{ debugName: "draggingKey" }] : []));
186
208
  opened = signal(false, ...(ngDevMode ? [{ debugName: "opened" }] : []));
209
+ openedPinMenuKey = signal(null, ...(ngDevMode ? [{ debugName: "openedPinMenuKey" }] : []));
210
+ panelLeft = signal(0, ...(ngDevMode ? [{ debugName: "panelLeft" }] : []));
211
+ hasCustomTrigger = signal(false, ...(ngDevMode ? [{ debugName: "hasCustomTrigger" }] : []));
187
212
  root = viewChild('root', ...(ngDevMode ? [{ debugName: "root" }] : []));
213
+ panel = viewChild('panel', ...(ngDevMode ? [{ debugName: "panel" }] : []));
188
214
  filteredColumns = computed(() => {
189
215
  const query = this.searchQuery().trim().toLowerCase();
190
216
  if (!query) {
@@ -201,20 +227,59 @@ class DataGridColumnManager {
201
227
  effect(() => {
202
228
  this.state.set(cloneColumns(this.columns()));
203
229
  });
230
+ afterNextRender(() => this.syncCustomTriggerState());
231
+ }
232
+ ngAfterContentChecked() {
233
+ this.syncCustomTriggerState();
204
234
  }
205
235
  pin = (key) => resolvePinState(this.state(), key);
206
236
  toggleOpen() {
207
- this.opened.update((current) => !current);
237
+ const nextOpened = !this.opened();
238
+ this.opened.set(nextOpened);
239
+ if (nextOpened) {
240
+ this.schedulePanelPositioning();
241
+ }
242
+ else {
243
+ this.openedPinMenuKey.set(null);
244
+ this.panelLeft.set(0);
245
+ }
246
+ }
247
+ onWindowResize() {
248
+ if (!this.opened()) {
249
+ return;
250
+ }
251
+ this.schedulePanelPositioning();
208
252
  }
209
253
  onDocumentMouseDown(target) {
254
+ if (target instanceof Node && this.openedPinMenuKey() && !this.isInsidePinMenu(target)) {
255
+ this.openedPinMenuKey.set(null);
256
+ }
210
257
  if (!this.opened()) {
211
258
  return;
212
259
  }
213
260
  const root = this.root()?.nativeElement;
214
261
  if (root && target instanceof Node && !root.contains(target)) {
262
+ this.openedPinMenuKey.set(null);
215
263
  this.opened.set(false);
216
264
  }
217
265
  }
266
+ togglePinMenu(event, key) {
267
+ event.stopPropagation();
268
+ this.openedPinMenuKey.update((current) => (current === key ? null : key));
269
+ }
270
+ selectPin(key, pin) {
271
+ this.onPin(key, pin);
272
+ this.openedPinMenuKey.set(null);
273
+ }
274
+ pinLabel(pin) {
275
+ if (pin === 'left') {
276
+ return 'Pin left';
277
+ }
278
+ if (pin === 'right') {
279
+ return 'Pin right';
280
+ }
281
+ return 'Unpinned';
282
+ }
218
283
  onSearch(event) {
219
284
  const target = event.target;
220
285
  this.searchQuery.set(target?.value ?? '');
@@ -343,267 +408,60 @@ class DataGridColumnManager {
343
408
  this.state.set(next);
344
409
  this.columnsChange.emit(cloneColumns(next));
345
410
  }
411
+ hasProjectedTrigger() {
412
+ return !!this.host.nativeElement.querySelector('[reDataGridColumnManagerTrigger]');
413
+ }
414
+ syncCustomTriggerState() {
415
+ const hasCustom = !!this.triggerDirective() || this.hasProjectedTrigger();
416
+ if (this.hasCustomTrigger() !== hasCustom) {
417
+ this.hasCustomTrigger.set(hasCustom);
418
+ }
419
+ }
420
+ isInsidePinMenu(target) {
421
+ return target instanceof Element && !!target.closest('[data-pin-menu]');
422
+ }
423
+ buildColumnTitleContext(column) {
424
+ const title = String(column.header || column.key);
425
+ return {
426
+ $implicit: title,
427
+ title,
428
+ column,
429
+ };
430
+ }
431
+ schedulePanelPositioning() {
432
+ afterNextRender(() => this.positionPanel());
433
+ }
434
+ positionPanel() {
435
+ const root = this.root()?.nativeElement;
436
+ const panel = this.panel()?.nativeElement;
437
+ if (!root || !panel || typeof window === 'undefined') {
438
+ this.panelLeft.set(0);
439
+ return;
440
+ }
441
+ const viewportPadding = 8;
442
+ const rootRect = root.getBoundingClientRect();
443
+ const panelWidth = panel.getBoundingClientRect().width;
444
+ const minLeft = viewportPadding - rootRect.left;
445
+ const maxLeft = window.innerWidth - viewportPadding - rootRect.left - panelWidth;
446
+ const lower = Math.min(minLeft, maxLeft);
447
+ const upper = Math.max(minLeft, maxLeft);
448
+ const nextLeft = Math.min(Math.max(0, lower), upper);
449
+ this.panelLeft.set(Number.isFinite(nextLeft) ? nextLeft : 0);
450
+ }
346
451
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridColumnManager, deps: [], target: i0.ɵɵFactoryTarget.Component });
347
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: DataGridColumnManager, isStandalone: true, selector: "re-data-grid-column-manager", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, triggerLabel: { classPropertyName: "triggerLabel", publicName: "triggerLabel", isSignal: true, isRequired: false, transformFunction: null }, triggerTemplate: { classPropertyName: "triggerTemplate", publicName: "triggerTemplate", isSignal: true, isRequired: false, transformFunction: null }, controlsVisible: { classPropertyName: "controlsVisible", publicName: "controlsVisible", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, allowReorder: { classPropertyName: "allowReorder", publicName: "allowReorder", isSignal: true, isRequired: false, transformFunction: null }, allowPin: { classPropertyName: "allowPin", publicName: "allowPin", isSignal: true, isRequired: false, transformFunction: null }, allowVisibility: { classPropertyName: "allowVisibility", publicName: "allowVisibility", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { columnsChange: "columnsChange" }, host: { attributes: { "document:mousedown": "onDocumentMouseDown($event.target)" } }, viewQueries: [{ propertyName: "root", first: true, predicate: ["root"], descendants: true, isSignal: true }], ngImport: i0, template: `
348
- <div class="re-dg-cm" #root>
349
- <button
350
- type="button"
351
- class="re-dg-cm__trigger"
352
- [class.re-dg-cm__trigger--open]="opened()"
353
- [attr.aria-expanded]="opened()"
354
- [attr.aria-haspopup]="'dialog'"
355
- (click)="toggleOpen()"
356
- >
357
- @if (triggerTemplate()) {
358
- <ng-container
359
- [ngTemplateOutlet]="triggerTemplate()!"
360
- [ngTemplateOutletContext]="{
361
- $implicit: triggerLabel(),
362
- visible: visibleColumnsCount(),
363
- total: state().length,
364
- }"
365
- />
366
- } @else {
367
- <span class="re-dg-cm__trigger-label">{{ triggerLabel() }}</span>
368
- <span class="re-dg-cm__trigger-count">{{ visibleColumnsCount() }}/{{ state().length }}</span>
369
- }
370
- </button>
371
-
372
- @if (opened()) {
373
- <div class="re-dg-cm__panel" role="dialog">
374
- @let list = filteredColumns();
375
-
376
- @if (controlsVisible() && searchable()) {
377
- <label class="re-dg-cm__search">
378
- <input
379
- type="search"
380
- [value]="searchQuery()"
381
- [placeholder]="searchPlaceholder()"
382
- (input)="onSearch($event)"
383
- />
384
- </label>
385
- }
386
-
387
- <div class="re-dg-cm__title-row">
388
- @if (controlsVisible()) {
389
- <div class="re-dg-cm__tools">
390
- <button type="button" (click)="showAll()">Show all</button>
391
- <button type="button" (click)="hideOptional()">Hide All</button>
392
- </div>
393
- } @else {
394
- <span></span>
395
- }
396
-
397
- <span class="re-dg-cm__meta">{{ visibleColumnsCount() }} / {{ state().length }}</span>
398
- </div>
399
-
400
- <div class="re-dg-cm__list">
401
- @for (column of list; track column.key) {
402
- @let currentPin = pin(column.key);
403
- @let disabled = !!column.disabled;
404
- @let canHideValue = canHideColumn(column.key);
405
-
406
- <div
407
- class="re-dg-cm__row"
408
- [attr.draggable]="allowReorder() && !disabled"
409
- [class.re-dg-cm__row--disabled]="disabled"
410
- [class.re-dg-cm__row--dragging]="draggingKey() === column.key"
411
- (dragstart)="onDragStart($event, column.key)"
412
- (dragover)="onDragOver($event)"
413
- (drop)="onDrop($event, column.key)"
414
- (dragend)="draggingKey.set(null)"
415
- >
416
- <span class="re-dg-cm__drag" title="Reorder">::</span>
417
-
418
- <label class="re-dg-cm__checkbox">
419
- <button
420
- [class.active]="column.visible !== false"
421
- [disabled]="disabled || !canHideValue"
422
- (click)="onVisibleChange(column.key)"
423
- >
424
- <re-eye-ic [open]="column.visible !== false" />
425
- </button>
426
- <span>{{ column.header || column.key }}</span>
427
- </label>
428
-
429
- <div class="re-dg-cm__actions">
430
- @if (allowPin()) {
431
- <button
432
- type="button"
433
- class="pin-button"
434
- [class.re-dg-cm__action--active]="currentPin === 'left'"
435
- [disabled]="disabled"
436
- (click)="onPin(column.key, 'left')"
437
- title="Pin left"
438
- >
439
- <re-pin-ic />
440
- </button>
441
-
442
- <button
443
- type="button"
444
- class="pin-button"
445
- [class.re-dg-cm__action--active]="currentPin === 'none'"
446
- [disabled]="disabled"
447
- (click)="onPin(column.key, 'none')"
448
- title="Unpin"
449
- >
450
- <re-cross-ic />
451
- </button>
452
-
453
- <button
454
- type="button"
455
- class="pin-button"
456
- [class.re-dg-cm__action--active]="currentPin === 'right'"
457
- [disabled]="disabled"
458
- (click)="onPin(column.key, 'right')"
459
- title="Pin right"
460
- >
461
- <re-pin-ic toRight />
462
- </button>
463
- }
464
- </div>
465
- </div>
466
- }
467
- </div>
468
- </div>
469
- }
470
- </div>
471
- `, isInline: true, styles: [":host{--re-data-grid-cm-gap: .5rem;--re-data-grid-cm-rounded: .625rem;--re-data-grid-cm-border: 1px solid var(--surface-border, #dfe1e6);--re-data-grid-cm-surface: var(--surface-neutral, #fff);--re-data-grid-cm-muted: var(--text-muted, #64748b);--re-data-grid-cm-active: var(--primary-color, #2a90f4);--re-data-grid-cm-shadow: 0 12px 30px rgba(15, 23, 42, .18);display:inline-block;position:relative}.re-dg-cm{position:relative;display:inline-flex;flex-direction:column;gap:var(--re-data-grid-cm-gap)}.re-dg-cm__trigger{display:inline-flex;align-items:center;gap:.5rem;height:2.25rem;padding:0 .75rem;border:var(--re-data-grid-cm-border);border-radius:999px;background:var(--re-data-grid-cm-surface);color:inherit;cursor:pointer}.re-dg-cm__trigger--open{box-shadow:0 0 0 2px color-mix(in srgb,var(--re-data-grid-cm-active) 25%,transparent)}.re-dg-cm__trigger-label{font-size:.8125rem;font-weight:600}.re-dg-cm__trigger-count{font-size:.75rem;color:var(--re-data-grid-cm-muted)}.re-dg-cm__panel{position:absolute;top:calc(100% + .5rem);left:0;z-index:50;min-width:18rem;width:max-content;max-width:min(24rem,85vw);display:grid;gap:var(--re-data-grid-cm-gap);padding:.75rem;border:var(--re-data-grid-cm-border);border-radius:var(--re-data-grid-cm-rounded);background:var(--re-data-grid-cm-surface);box-shadow:var(--re-data-grid-cm-shadow)}.re-dg-cm__tools,.re-dg-cm__row,.re-dg-cm__actions{display:flex;align-items:center}.re-dg-cm__meta{color:var(--re-data-grid-cm-muted);font-size:.75rem}.re-dg-cm__search input{width:100%;height:2rem;border-radius:.5rem;border:var(--re-data-grid-cm-border);padding:0 .625rem;background:var(--re-data-grid-cm-surface);color:inherit}.re-dg-cm__tools{gap:.5rem}.re-dg-cm__title-row{display:flex;justify-content:space-between}.re-dg-cm__tools button,.re-dg-cm__actions button{color:inherit;cursor:pointer;font-size:.75rem;line-height:1}.re-dg-cm__tools button{height:1.8rem;padding:0 .5rem}.re-dg-cm__actions button{width:1.7rem;height:1.7rem}.re-dg-cm__list{display:grid;gap:.375rem;max-height:22rem;overflow:auto;padding-right:.125rem}.re-dg-cm__row{gap:.5rem;padding:.375rem .5rem;border:var(--re-data-grid-cm-border);border-radius:.5rem;background:color-mix(in srgb,var(--re-data-grid-cm-surface) 88%,#f8fafc)}.re-dg-cm__row--dragging{opacity:.55}.re-dg-cm__row--disabled{opacity:.6}.re-dg-cm__drag{width:1rem;color:var(--re-data-grid-cm-muted);cursor:grab;-webkit-user-select:none;user-select:none}.re-dg-cm__checkbox{display:inline-flex;align-items:center;gap:.5rem;flex:1 1 auto;min-width:0;font-size:.8125rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.re-dg-cm__checkbox>button{color:var(--re-data-grid-cm-muted)}.re-dg-cm__checkbox>button.active{color:var(--re-data-grid-cm-active)}.re-dg-cm__actions{gap:.25rem;margin-left:auto}.re-dg-cm__action--active{color:var(--re-data-grid-cm-active)!important;font-weight:700}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: EyeIcon, selector: "re-eye-ic", inputs: ["open"] }, { kind: "component", type: CrossIcon, selector: "re-cross-ic" }, { kind: "component", type: PinIcon, selector: "re-pin-ic", inputs: ["toRight"] }] });
452
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: DataGridColumnManager, isStandalone: true, selector: "re-data-grid-column-manager", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, triggerLabel: { classPropertyName: "triggerLabel", publicName: "triggerLabel", isSignal: true, isRequired: false, transformFunction: null }, controlsVisible: { classPropertyName: "controlsVisible", publicName: "controlsVisible", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, allowReorder: { classPropertyName: "allowReorder", publicName: "allowReorder", isSignal: true, isRequired: false, transformFunction: null }, allowPin: { classPropertyName: "allowPin", publicName: "allowPin", isSignal: true, isRequired: false, transformFunction: null }, allowVisibility: { classPropertyName: "allowVisibility", publicName: "allowVisibility", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { columnsChange: "columnsChange" }, host: { attributes: { "document:mousedown": "onDocumentMouseDown($event.target)", "window:resize": "onWindowResize()" } }, queries: [{ propertyName: "triggerDirective", first: true, predicate: DataGridColumnManagerTriggerDirective, descendants: true, isSignal: true }, { propertyName: "columnTitleTemplate", first: true, predicate: (DataGridColumnManagerColumnTitleDirective), descendants: true, isSignal: true }], viewQueries: [{ propertyName: "root", first: true, predicate: ["root"], descendants: true, isSignal: true }, { propertyName: "panel", first: true, predicate: ["panel"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"re-dg-cm\" #root>\n <button\n type=\"button\"\n class=\"re-dg-cm__trigger\"\n [class.re-dg-cm__trigger--open]=\"opened()\"\n [attr.aria-expanded]=\"opened()\"\n [attr.aria-haspopup]=\"'dialog'\"\n (click)=\"toggleOpen()\"\n >\n @if (hasCustomTrigger()) {\n <ng-content select=\"[reDataGridColumnManagerTrigger]\" />\n } @else {\n <span class=\"re-dg-cm__trigger-label\">{{ triggerLabel() }}</span>\n <span class=\"re-dg-cm__trigger-count\">{{ visibleColumnsCount() }}/{{ state().length }}</span>\n }\n </button>\n\n @if (opened()) {\n <div class=\"re-dg-cm__panel\" #panel role=\"dialog\" [style.left.px]=\"panelLeft()\">\n @let list = filteredColumns();\n\n @if (controlsVisible() && searchable()) {\n <label class=\"re-dg-cm__search\">\n <input\n type=\"search\"\n [value]=\"searchQuery()\"\n [placeholder]=\"searchPlaceholder()\"\n (input)=\"onSearch($event)\"\n />\n </label>\n }\n\n <div class=\"re-dg-cm__title-row\">\n @if (controlsVisible()) {\n <div class=\"re-dg-cm__tools\">\n <button type=\"button\" (click)=\"showAll()\">Show all</button>\n <button type=\"button\" (click)=\"hideOptional()\">Hide All</button>\n </div>\n } @else {\n <span></span>\n }\n\n <span class=\"re-dg-cm__meta\">{{ visibleColumnsCount() }} / {{ state().length }}</span>\n </div>\n\n <div class=\"re-dg-cm__list\">\n @for (column of list; track column.key) {\n @let currentPin = pin(column.key);\n @let disabled = !!column.disabled;\n @let canHideValue = canHideColumn(column.key);\n\n <div\n class=\"re-dg-cm__row\"\n [attr.draggable]=\"allowReorder() && !disabled\"\n [class.re-dg-cm__row--disabled]=\"disabled\"\n [class.re-dg-cm__row--dragging]=\"draggingKey() === column.key\"\n (dragstart)=\"onDragStart($event, column.key)\"\n (dragover)=\"onDragOver($event)\"\n (drop)=\"onDrop($event, column.key)\"\n (dragend)=\"draggingKey.set(null)\"\n >\n <span class=\"re-dg-cm__drag\" title=\"Reorder\">::</span>\n\n <label class=\"re-dg-cm__checkbox\">\n <button\n [class.active]=\"column.visible !== false\"\n [disabled]=\"disabled || !canHideValue\"\n (click)=\"onVisibleChange(column.key)\"\n >\n <re-eye-ic [open]=\"column.visible !== false\" />\n </button>\n @if (columnTitleTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"columnTitleTemplate()!.template\"\n [ngTemplateOutletContext]=\"buildColumnTitleContext(column)\"\n />\n } @else {\n <span>{{ column.header || column.key }}</span>\n }\n </label>\n\n <div class=\"re-dg-cm__actions\">\n @if (allowPin()) {\n <div class=\"re-dg-cm__pin-menu\" data-pin-menu>\n <button\n type=\"button\"\n class=\"re-dg-cm__pin-current\"\n [disabled]=\"disabled\"\n [class.re-dg-cm__action--active]=\"currentPin !== 'none'\"\n [attr.aria-expanded]=\"openedPinMenuKey() === column.key\"\n (click)=\"togglePinMenu($event, column.key)\"\n [title]=\"pinLabel(currentPin)\"\n >\n @if (currentPin === 'left') {\n <re-pin-ic />\n } @else if (currentPin === 'right') {\n <re-pin-ic toRight />\n } @else {\n <re-cross-ic />\n }\n </button>\n\n @if (openedPinMenuKey() === column.key && !disabled) {\n <div class=\"re-dg-cm__pin-popover\" data-pin-menu role=\"menu\">\n <button\n type=\"button\"\n class=\"pin-button\"\n [class.re-dg-cm__action--active]=\"currentPin === 'left'\"\n (click)=\"selectPin(column.key, 'left')\"\n title=\"Pin left\"\n >\n <re-pin-ic />\n </button>\n\n <button\n type=\"button\"\n class=\"pin-button\"\n [class.re-dg-cm__action--active]=\"currentPin === 'none'\"\n (click)=\"selectPin(column.key, 'none')\"\n title=\"Unpin\"\n >\n <re-cross-ic />\n </button>\n\n <button\n type=\"button\"\n class=\"pin-button\"\n [class.re-dg-cm__action--active]=\"currentPin === 'right'\"\n (click)=\"selectPin(column.key, 'right')\"\n title=\"Pin right\"\n >\n <re-pin-ic toRight />\n </button>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n }\n</div>\n", styles: [":host{--re-data-grid-cm-gap: .5rem;--re-data-grid-cm-rounded: .625rem;--re-data-grid-cm-border: 1px solid var(--surface-border, #dfe1e6);--re-data-grid-cm-surface: var(--surface-neutral, #fff);--re-data-grid-cm-muted: var(--text-muted, #64748b);--re-data-grid-cm-active: var(--primary-color, #2a90f4);--re-data-grid-cm-shadow: 0 12px 30px rgba(15, 23, 42, .18);display:inline-block;position:relative}.re-dg-cm{position:relative;display:inline-flex;flex-direction:column;gap:var(--re-data-grid-cm-gap)}.re-dg-cm__trigger{display:inline-flex;align-items:center;gap:.5rem;height:2.25rem;padding:0 .75rem;border:var(--re-data-grid-cm-border);border-radius:999px;background:var(--re-data-grid-cm-surface);color:inherit;cursor:pointer}.re-dg-cm__trigger--open{box-shadow:0 0 0 2px color-mix(in srgb,var(--re-data-grid-cm-active) 25%,transparent)}.re-dg-cm__trigger-label{font-size:.8125rem;font-weight:600}.re-dg-cm__trigger-count{font-size:.75rem;color:var(--re-data-grid-cm-muted)}.re-dg-cm__panel{position:absolute;top:calc(100% + .5rem);left:0;z-index:50;min-width:18rem;width:max-content;max-width:min(24rem,85vw);display:grid;gap:var(--re-data-grid-cm-gap);padding:.75rem;border:var(--re-data-grid-cm-border);border-radius:var(--re-data-grid-cm-rounded);background:var(--re-data-grid-cm-surface);box-shadow:var(--re-data-grid-cm-shadow)}.re-dg-cm__tools,.re-dg-cm__row,.re-dg-cm__actions{display:flex;align-items:center}.re-dg-cm__meta{color:var(--re-data-grid-cm-muted);font-size:.75rem}.re-dg-cm__search input{width:100%;height:2rem;border-radius:.5rem;border:var(--re-data-grid-cm-border);padding:0 .625rem;background:var(--re-data-grid-cm-surface);color:inherit}.re-dg-cm__tools{gap:.5rem}.re-dg-cm__title-row{display:flex;justify-content:space-between}.re-dg-cm__tools button,.re-dg-cm__actions button{color:inherit;cursor:pointer;font-size:.75rem;line-height:1}.re-dg-cm__tools button{height:1.8rem;padding:0 .5rem}.re-dg-cm__actions button{width:1.7rem;height:1.7rem}.re-dg-cm__list{display:grid;gap:.375rem;max-height:22rem;overflow:auto;padding-right:.125rem}.re-dg-cm__row{gap:.5rem;padding:.375rem .5rem;border:var(--re-data-grid-cm-border);border-radius:.5rem;background:color-mix(in srgb,var(--re-data-grid-cm-surface) 88%,#f8fafc)}.re-dg-cm__row--dragging{opacity:.55}.re-dg-cm__row--disabled{opacity:.6}.re-dg-cm__drag{width:1rem;color:var(--re-data-grid-cm-muted);cursor:grab;-webkit-user-select:none;user-select:none}.re-dg-cm__checkbox{display:inline-flex;align-items:center;gap:.5rem;flex:1 1 auto;min-width:0;font-size:.8125rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.re-dg-cm__checkbox>button{color:var(--re-data-grid-cm-muted)}.re-dg-cm__checkbox>button.active{color:var(--re-data-grid-cm-active)}.re-dg-cm__actions{gap:.25rem;margin-left:auto}.re-dg-cm__pin-menu{position:relative}.re-dg-cm__pin-current{width:1.7rem;height:1.7rem}.re-dg-cm__pin-popover{position:absolute;right:0;top:calc(100% + .25rem);z-index:2;display:flex;align-items:center;gap:.25rem;padding:.25rem;border:var(--re-data-grid-cm-border);border-radius:.5rem;background:var(--re-data-grid-cm-surface);box-shadow:var(--re-data-grid-cm-shadow)}.re-dg-cm__action--active{color:var(--re-data-grid-cm-active)!important;font-weight:700}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: EyeIcon, selector: "re-eye-ic", inputs: ["open"] }, { kind: "component", type: CrossIcon, selector: "re-cross-ic" }, { kind: "component", type: PinIcon, selector: "re-pin-ic", inputs: ["toRight"] }] });
472
453
  }
473
454
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DataGridColumnManager, decorators: [{
474
455
  type: Component,
475
- args: [{ selector: 're-data-grid-column-manager', standalone: true, template: `
476
- <div class="re-dg-cm" #root>
477
- <button
478
- type="button"
479
- class="re-dg-cm__trigger"
480
- [class.re-dg-cm__trigger--open]="opened()"
481
- [attr.aria-expanded]="opened()"
482
- [attr.aria-haspopup]="'dialog'"
483
- (click)="toggleOpen()"
484
- >
485
- @if (triggerTemplate()) {
486
- <ng-container
487
- [ngTemplateOutlet]="triggerTemplate()!"
488
- [ngTemplateOutletContext]="{
489
- $implicit: triggerLabel(),
490
- visible: visibleColumnsCount(),
491
- total: state().length,
492
- }"
493
- />
494
- } @else {
495
- <span class="re-dg-cm__trigger-label">{{ triggerLabel() }}</span>
496
- <span class="re-dg-cm__trigger-count">{{ visibleColumnsCount() }}/{{ state().length }}</span>
497
- }
498
- </button>
499
-
500
- @if (opened()) {
501
- <div class="re-dg-cm__panel" role="dialog">
502
- @let list = filteredColumns();
503
-
504
- @if (controlsVisible() && searchable()) {
505
- <label class="re-dg-cm__search">
506
- <input
507
- type="search"
508
- [value]="searchQuery()"
509
- [placeholder]="searchPlaceholder()"
510
- (input)="onSearch($event)"
511
- />
512
- </label>
513
- }
514
-
515
- <div class="re-dg-cm__title-row">
516
- @if (controlsVisible()) {
517
- <div class="re-dg-cm__tools">
518
- <button type="button" (click)="showAll()">Show all</button>
519
- <button type="button" (click)="hideOptional()">Hide All</button>
520
- </div>
521
- } @else {
522
- <span></span>
523
- }
524
-
525
- <span class="re-dg-cm__meta">{{ visibleColumnsCount() }} / {{ state().length }}</span>
526
- </div>
527
-
528
- <div class="re-dg-cm__list">
529
- @for (column of list; track column.key) {
530
- @let currentPin = pin(column.key);
531
- @let disabled = !!column.disabled;
532
- @let canHideValue = canHideColumn(column.key);
533
-
534
- <div
535
- class="re-dg-cm__row"
536
- [attr.draggable]="allowReorder() && !disabled"
537
- [class.re-dg-cm__row--disabled]="disabled"
538
- [class.re-dg-cm__row--dragging]="draggingKey() === column.key"
539
- (dragstart)="onDragStart($event, column.key)"
540
- (dragover)="onDragOver($event)"
541
- (drop)="onDrop($event, column.key)"
542
- (dragend)="draggingKey.set(null)"
543
- >
544
- <span class="re-dg-cm__drag" title="Reorder">::</span>
545
-
546
- <label class="re-dg-cm__checkbox">
547
- <button
548
- [class.active]="column.visible !== false"
549
- [disabled]="disabled || !canHideValue"
550
- (click)="onVisibleChange(column.key)"
551
- >
552
- <re-eye-ic [open]="column.visible !== false" />
553
- </button>
554
- <span>{{ column.header || column.key }}</span>
555
- </label>
556
-
557
- <div class="re-dg-cm__actions">
558
- @if (allowPin()) {
559
- <button
560
- type="button"
561
- class="pin-button"
562
- [class.re-dg-cm__action--active]="currentPin === 'left'"
563
- [disabled]="disabled"
564
- (click)="onPin(column.key, 'left')"
565
- title="Pin left"
566
- >
567
- <re-pin-ic />
568
- </button>
569
-
570
- <button
571
- type="button"
572
- class="pin-button"
573
- [class.re-dg-cm__action--active]="currentPin === 'none'"
574
- [disabled]="disabled"
575
- (click)="onPin(column.key, 'none')"
576
- title="Unpin"
577
- >
578
- <re-cross-ic />
579
- </button>
580
-
581
- <button
582
- type="button"
583
- class="pin-button"
584
- [class.re-dg-cm__action--active]="currentPin === 'right'"
585
- [disabled]="disabled"
586
- (click)="onPin(column.key, 'right')"
587
- title="Pin right"
588
- >
589
- <re-pin-ic toRight />
590
- </button>
591
- }
592
- </div>
593
- </div>
594
- }
595
- </div>
596
- </div>
597
- }
598
- </div>
599
- `, host: {
456
+ args: [{ selector: 're-data-grid-column-manager', standalone: true, host: {
600
457
  'document:mousedown': 'onDocumentMouseDown($event.target)',
601
- }, imports: [NgTemplateOutlet, EyeIcon, CrossIcon, PinIcon], styles: [":host{--re-data-grid-cm-gap: .5rem;--re-data-grid-cm-rounded: .625rem;--re-data-grid-cm-border: 1px solid var(--surface-border, #dfe1e6);--re-data-grid-cm-surface: var(--surface-neutral, #fff);--re-data-grid-cm-muted: var(--text-muted, #64748b);--re-data-grid-cm-active: var(--primary-color, #2a90f4);--re-data-grid-cm-shadow: 0 12px 30px rgba(15, 23, 42, .18);display:inline-block;position:relative}.re-dg-cm{position:relative;display:inline-flex;flex-direction:column;gap:var(--re-data-grid-cm-gap)}.re-dg-cm__trigger{display:inline-flex;align-items:center;gap:.5rem;height:2.25rem;padding:0 .75rem;border:var(--re-data-grid-cm-border);border-radius:999px;background:var(--re-data-grid-cm-surface);color:inherit;cursor:pointer}.re-dg-cm__trigger--open{box-shadow:0 0 0 2px color-mix(in srgb,var(--re-data-grid-cm-active) 25%,transparent)}.re-dg-cm__trigger-label{font-size:.8125rem;font-weight:600}.re-dg-cm__trigger-count{font-size:.75rem;color:var(--re-data-grid-cm-muted)}.re-dg-cm__panel{position:absolute;top:calc(100% + .5rem);left:0;z-index:50;min-width:18rem;width:max-content;max-width:min(24rem,85vw);display:grid;gap:var(--re-data-grid-cm-gap);padding:.75rem;border:var(--re-data-grid-cm-border);border-radius:var(--re-data-grid-cm-rounded);background:var(--re-data-grid-cm-surface);box-shadow:var(--re-data-grid-cm-shadow)}.re-dg-cm__tools,.re-dg-cm__row,.re-dg-cm__actions{display:flex;align-items:center}.re-dg-cm__meta{color:var(--re-data-grid-cm-muted);font-size:.75rem}.re-dg-cm__search input{width:100%;height:2rem;border-radius:.5rem;border:var(--re-data-grid-cm-border);padding:0 .625rem;background:var(--re-data-grid-cm-surface);color:inherit}.re-dg-cm__tools{gap:.5rem}.re-dg-cm__title-row{display:flex;justify-content:space-between}.re-dg-cm__tools button,.re-dg-cm__actions button{color:inherit;cursor:pointer;font-size:.75rem;line-height:1}.re-dg-cm__tools button{height:1.8rem;padding:0 .5rem}.re-dg-cm__actions button{width:1.7rem;height:1.7rem}.re-dg-cm__list{display:grid;gap:.375rem;max-height:22rem;overflow:auto;padding-right:.125rem}.re-dg-cm__row{gap:.5rem;padding:.375rem .5rem;border:var(--re-data-grid-cm-border);border-radius:.5rem;background:color-mix(in srgb,var(--re-data-grid-cm-surface) 88%,#f8fafc)}.re-dg-cm__row--dragging{opacity:.55}.re-dg-cm__row--disabled{opacity:.6}.re-dg-cm__drag{width:1rem;color:var(--re-data-grid-cm-muted);cursor:grab;-webkit-user-select:none;user-select:none}.re-dg-cm__checkbox{display:inline-flex;align-items:center;gap:.5rem;flex:1 1 auto;min-width:0;font-size:.8125rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.re-dg-cm__checkbox>button{color:var(--re-data-grid-cm-muted)}.re-dg-cm__checkbox>button.active{color:var(--re-data-grid-cm-active)}.re-dg-cm__actions{gap:.25rem;margin-left:auto}.re-dg-cm__action--active{color:var(--re-data-grid-cm-active)!important;font-weight:700}\n"] }]
602
- }], ctorParameters: () => [], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], triggerLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerLabel", required: false }] }], triggerTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerTemplate", required: false }] }], controlsVisible: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlsVisible", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], allowReorder: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowReorder", required: false }] }], allowPin: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowPin", required: false }] }], allowVisibility: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowVisibility", required: false }] }], columnsChange: [{ type: i0.Output, args: ["columnsChange"] }], root: [{ type: i0.ViewChild, args: ['root', { isSignal: true }] }] } });
458
+ 'window:resize': 'onWindowResize()',
459
+ }, imports: [NgTemplateOutlet, EyeIcon, CrossIcon, PinIcon], template: "<div class=\"re-dg-cm\" #root>\n <button\n type=\"button\"\n class=\"re-dg-cm__trigger\"\n [class.re-dg-cm__trigger--open]=\"opened()\"\n [attr.aria-expanded]=\"opened()\"\n [attr.aria-haspopup]=\"'dialog'\"\n (click)=\"toggleOpen()\"\n >\n @if (hasCustomTrigger()) {\n <ng-content select=\"[reDataGridColumnManagerTrigger]\" />\n } @else {\n <span class=\"re-dg-cm__trigger-label\">{{ triggerLabel() }}</span>\n <span class=\"re-dg-cm__trigger-count\">{{ visibleColumnsCount() }}/{{ state().length }}</span>\n }\n </button>\n\n @if (opened()) {\n <div class=\"re-dg-cm__panel\" #panel role=\"dialog\" [style.left.px]=\"panelLeft()\">\n @let list = filteredColumns();\n\n @if (controlsVisible() && searchable()) {\n <label class=\"re-dg-cm__search\">\n <input\n type=\"search\"\n [value]=\"searchQuery()\"\n [placeholder]=\"searchPlaceholder()\"\n (input)=\"onSearch($event)\"\n />\n </label>\n }\n\n <div class=\"re-dg-cm__title-row\">\n @if (controlsVisible()) {\n <div class=\"re-dg-cm__tools\">\n <button type=\"button\" (click)=\"showAll()\">Show all</button>\n <button type=\"button\" (click)=\"hideOptional()\">Hide All</button>\n </div>\n } @else {\n <span></span>\n }\n\n <span class=\"re-dg-cm__meta\">{{ visibleColumnsCount() }} / {{ state().length }}</span>\n </div>\n\n <div class=\"re-dg-cm__list\">\n @for (column of list; track column.key) {\n @let currentPin = pin(column.key);\n @let disabled = !!column.disabled;\n @let canHideValue = canHideColumn(column.key);\n\n <div\n class=\"re-dg-cm__row\"\n [attr.draggable]=\"allowReorder() && !disabled\"\n [class.re-dg-cm__row--disabled]=\"disabled\"\n [class.re-dg-cm__row--dragging]=\"draggingKey() === column.key\"\n (dragstart)=\"onDragStart($event, column.key)\"\n (dragover)=\"onDragOver($event)\"\n (drop)=\"onDrop($event, column.key)\"\n (dragend)=\"draggingKey.set(null)\"\n >\n <span class=\"re-dg-cm__drag\" title=\"Reorder\">::</span>\n\n <label class=\"re-dg-cm__checkbox\">\n <button\n [class.active]=\"column.visible !== false\"\n [disabled]=\"disabled || !canHideValue\"\n (click)=\"onVisibleChange(column.key)\"\n >\n <re-eye-ic [open]=\"column.visible !== false\" />\n </button>\n @if (columnTitleTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"columnTitleTemplate()!.template\"\n [ngTemplateOutletContext]=\"buildColumnTitleContext(column)\"\n />\n } @else {\n <span>{{ column.header || column.key }}</span>\n }\n </label>\n\n <div class=\"re-dg-cm__actions\">\n @if (allowPin()) {\n <div class=\"re-dg-cm__pin-menu\" data-pin-menu>\n <button\n type=\"button\"\n class=\"re-dg-cm__pin-current\"\n [disabled]=\"disabled\"\n [class.re-dg-cm__action--active]=\"currentPin !== 'none'\"\n [attr.aria-expanded]=\"openedPinMenuKey() === column.key\"\n (click)=\"togglePinMenu($event, column.key)\"\n [title]=\"pinLabel(currentPin)\"\n >\n @if (currentPin === 'left') {\n <re-pin-ic />\n } @else if (currentPin === 'right') {\n <re-pin-ic toRight />\n } @else {\n <re-cross-ic />\n }\n </button>\n\n @if (openedPinMenuKey() === column.key && !disabled) {\n <div class=\"re-dg-cm__pin-popover\" data-pin-menu role=\"menu\">\n <button\n type=\"button\"\n class=\"pin-button\"\n [class.re-dg-cm__action--active]=\"currentPin === 'left'\"\n (click)=\"selectPin(column.key, 'left')\"\n title=\"Pin left\"\n >\n <re-pin-ic />\n </button>\n\n <button\n type=\"button\"\n class=\"pin-button\"\n [class.re-dg-cm__action--active]=\"currentPin === 'none'\"\n (click)=\"selectPin(column.key, 'none')\"\n title=\"Unpin\"\n >\n <re-cross-ic />\n </button>\n\n <button\n type=\"button\"\n class=\"pin-button\"\n [class.re-dg-cm__action--active]=\"currentPin === 'right'\"\n (click)=\"selectPin(column.key, 'right')\"\n title=\"Pin right\"\n >\n <re-pin-ic toRight />\n </button>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n }\n</div>\n", styles: [":host{--re-data-grid-cm-gap: .5rem;--re-data-grid-cm-rounded: .625rem;--re-data-grid-cm-border: 1px solid var(--surface-border, #dfe1e6);--re-data-grid-cm-surface: var(--surface-neutral, #fff);--re-data-grid-cm-muted: var(--text-muted, #64748b);--re-data-grid-cm-active: var(--primary-color, #2a90f4);--re-data-grid-cm-shadow: 0 12px 30px rgba(15, 23, 42, .18);display:inline-block;position:relative}.re-dg-cm{position:relative;display:inline-flex;flex-direction:column;gap:var(--re-data-grid-cm-gap)}.re-dg-cm__trigger{display:inline-flex;align-items:center;gap:.5rem;height:2.25rem;padding:0 .75rem;border:var(--re-data-grid-cm-border);border-radius:999px;background:var(--re-data-grid-cm-surface);color:inherit;cursor:pointer}.re-dg-cm__trigger--open{box-shadow:0 0 0 2px color-mix(in srgb,var(--re-data-grid-cm-active) 25%,transparent)}.re-dg-cm__trigger-label{font-size:.8125rem;font-weight:600}.re-dg-cm__trigger-count{font-size:.75rem;color:var(--re-data-grid-cm-muted)}.re-dg-cm__panel{position:absolute;top:calc(100% + .5rem);left:0;z-index:50;min-width:18rem;width:max-content;max-width:min(24rem,85vw);display:grid;gap:var(--re-data-grid-cm-gap);padding:.75rem;border:var(--re-data-grid-cm-border);border-radius:var(--re-data-grid-cm-rounded);background:var(--re-data-grid-cm-surface);box-shadow:var(--re-data-grid-cm-shadow)}.re-dg-cm__tools,.re-dg-cm__row,.re-dg-cm__actions{display:flex;align-items:center}.re-dg-cm__meta{color:var(--re-data-grid-cm-muted);font-size:.75rem}.re-dg-cm__search input{width:100%;height:2rem;border-radius:.5rem;border:var(--re-data-grid-cm-border);padding:0 .625rem;background:var(--re-data-grid-cm-surface);color:inherit}.re-dg-cm__tools{gap:.5rem}.re-dg-cm__title-row{display:flex;justify-content:space-between}.re-dg-cm__tools button,.re-dg-cm__actions button{color:inherit;cursor:pointer;font-size:.75rem;line-height:1}.re-dg-cm__tools button{height:1.8rem;padding:0 .5rem}.re-dg-cm__actions button{width:1.7rem;height:1.7rem}.re-dg-cm__list{display:grid;gap:.375rem;max-height:22rem;overflow:auto;padding-right:.125rem}.re-dg-cm__row{gap:.5rem;padding:.375rem .5rem;border:var(--re-data-grid-cm-border);border-radius:.5rem;background:color-mix(in srgb,var(--re-data-grid-cm-surface) 88%,#f8fafc)}.re-dg-cm__row--dragging{opacity:.55}.re-dg-cm__row--disabled{opacity:.6}.re-dg-cm__drag{width:1rem;color:var(--re-data-grid-cm-muted);cursor:grab;-webkit-user-select:none;user-select:none}.re-dg-cm__checkbox{display:inline-flex;align-items:center;gap:.5rem;flex:1 1 auto;min-width:0;font-size:.8125rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.re-dg-cm__checkbox>button{color:var(--re-data-grid-cm-muted)}.re-dg-cm__checkbox>button.active{color:var(--re-data-grid-cm-active)}.re-dg-cm__actions{gap:.25rem;margin-left:auto}.re-dg-cm__pin-menu{position:relative}.re-dg-cm__pin-current{width:1.7rem;height:1.7rem}.re-dg-cm__pin-popover{position:absolute;right:0;top:calc(100% + .25rem);z-index:2;display:flex;align-items:center;gap:.25rem;padding:.25rem;border:var(--re-data-grid-cm-border);border-radius:.5rem;background:var(--re-data-grid-cm-surface);box-shadow:var(--re-data-grid-cm-shadow)}.re-dg-cm__action--active{color:var(--re-data-grid-cm-active)!important;font-weight:700}\n"] }]
460
+ }], ctorParameters: () => [], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], triggerLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerLabel", required: false }] }], controlsVisible: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlsVisible", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], allowReorder: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowReorder", required: false }] }], allowPin: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowPin", required: false }] }], allowVisibility: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowVisibility", required: false }] }], columnsChange: [{ type: i0.Output, args: ["columnsChange"] }], triggerDirective: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DataGridColumnManagerTriggerDirective), { isSignal: true }] }], columnTitleTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DataGridColumnManagerColumnTitleDirective), { isSignal: true }] }], root: [{ type: i0.ViewChild, args: ['root', { isSignal: true }] }], panel: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }] } });
603
461
 
604
462
  /**
605
463
  * Generated bundle index. Do not edit.
606
464
  */
607
465
 
608
- export { DataGridColumnManager };
466
+ export { DataGridColumnManager, DataGridColumnManagerColumnTitleDirective, DataGridColumnManagerTriggerDirective };
609
467
  //# sourceMappingURL=reforgium-data-grid-column-manager.mjs.map
@@ -1,4 +1,4 @@
1
- import { c as computeScrollbarState, a as clampThumbTop, m as mapThumbTopToScrollTop } from './reforgium-data-grid-reforgium-data-grid-uZ3onkWO.mjs';
1
+ import { c as computeScrollbarState, a as clampThumbTop, m as mapThumbTopToScrollTop } from './reforgium-data-grid-reforgium-data-grid-YSzBRJ5h.mjs';
2
2
 
3
3
  function createGridOverlayScrollFeature(ctx) {
4
4
  const showScrollbar = () => {
@@ -76,4 +76,4 @@ function createGridOverlayScrollFeature(ctx) {
76
76
  }
77
77
 
78
78
  export { createGridOverlayScrollFeature };
79
- //# sourceMappingURL=reforgium-data-grid-grid-overlay-scroll.feature-B3hwiKYh.mjs.map
79
+ //# sourceMappingURL=reforgium-data-grid-grid-overlay-scroll.feature-C-_Cnt4M.mjs.map
@@ -1,3 +1,4 @@
1
+ // noinspection ES6PreferShortImport
1
2
  function createGridTooltipFeature(ctx) {
2
3
  const resolveCellValue = (row, col) => {
3
4
  return 'value' in col ? col.value(row) : row[col.key];
@@ -86,4 +87,4 @@ function createGridTooltipFeature(ctx) {
86
87
  }
87
88
 
88
89
  export { createGridTooltipFeature };
89
- //# sourceMappingURL=reforgium-data-grid-grid-tooltip.feature-CMo88m8o.mjs.map
90
+ //# sourceMappingURL=reforgium-data-grid-grid-tooltip.feature-i-k8F-1I.mjs.map
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, inject, TemplateRef, Directive, booleanAttribute, contentChild, Component, numberAttribute, InjectionToken, makeEnvironmentProviders, signal, computed, effect, Injectable, ChangeDetectionStrategy, output, untracked, DestroyRef, afterRenderEffect, viewChild, NgZone, contentChildren } from '@angular/core';
2
+ import { input, inject, TemplateRef, Directive, booleanAttribute, contentChild, Component, numberAttribute, InjectionToken, makeEnvironmentProviders, signal, computed, effect, Injectable, ChangeDetectionStrategy, output, untracked, DestroyRef, afterRenderEffect, viewChild, NgZone, contentChildren, afterNextRender } from '@angular/core';
3
3
  import { NgTemplateOutlet, DatePipe, DecimalPipe } from '@angular/common';
4
4
  import { Subject, debounceTime, fromEvent, Subscription } from 'rxjs';
5
5
 
@@ -912,6 +912,7 @@ function splitSticky(cols) {
912
912
  return { left, right, visible };
913
913
  }
914
914
 
915
+ // noinspection ES6PreferShortImport
915
916
  /**
916
917
  * View model for the data grid component.
917
918
  *
@@ -1495,6 +1496,7 @@ function createGridHeaderMeasureFeature(ctx) {
1495
1496
  };
1496
1497
  }
1497
1498
 
1499
+ // noinspection ES6PreferShortImport
1498
1500
  function createGridInfinityPageRequestFeature(ctx) {
1499
1501
  const PREFETCH_FACTOR = 1.25;
1500
1502
  let lastRequestedPage = null;
@@ -1937,6 +1939,7 @@ function createGridVirtualScrollFeature(ctx) {
1937
1939
  return { onVerticalScroll };
1938
1940
  }
1939
1941
 
1942
+ // noinspection ES6PreferShortImport
1940
1943
  const COLUMN_STATE_PRIORITY_KEYS = new Set(['disabled', 'visible', 'sticky']);
1941
1944
  function mergeDeclarativeColumns(declarative, columns) {
1942
1945
  if (!declarative.length) {
@@ -2745,8 +2748,14 @@ class DataGrid {
2745
2748
  return rows[index];
2746
2749
  }, ...(ngDevMode ? [{ debugName: "stickyRowData" }] : []));
2747
2750
  stickyIndexes = signal([], ...(ngDevMode ? [{ debugName: "stickyIndexes" }] : []));
2751
+ contentInitialized = signal(false, ...(ngDevMode ? [{ debugName: "contentInitialized" }] : []));
2748
2752
  expanderMap = signal(new Map(), ...(ngDevMode ? [{ debugName: "expanderMap" }] : []));
2749
- declarativeColumns = computed(() => normalizeDeclarativeColumns(this.declarativeColumnRefs().map((columnRef) => columnRef.toDeclarativeColumn()), this.rowKey()), ...(ngDevMode ? [{ debugName: "declarativeColumns" }] : []));
2753
+ declarativeColumns = computed(() => {
2754
+ if (!this.contentInitialized()) {
2755
+ return normalizeDeclarativeColumns([], this.rowKey());
2756
+ }
2757
+ return normalizeDeclarativeColumns(this.declarativeColumnRefs().map((columnRef) => columnRef.toDeclarativeColumn()), this.rowKey());
2758
+ }, ...(ngDevMode ? [{ debugName: "declarativeColumns" }] : []));
2750
2759
  sourceColumns = computed(() => mergeDeclarativeColumns(this.declarativeColumns().columns, this.columns()), ...(ngDevMode ? [{ debugName: "sourceColumns" }] : []));
2751
2760
  slotsFeature = createGridSlotsFeature({
2752
2761
  clearTypeTemplates: () => this.vm.globalTypeCellTpls.clear(),
@@ -2791,6 +2800,7 @@ class DataGrid {
2791
2800
  currentSortMap = new Map();
2792
2801
  subscription = new Subscription();
2793
2802
  constructor() {
2803
+ afterNextRender(() => this.contentInitialized.set(true));
2794
2804
  this.lifecycleInitFeature.init({
2795
2805
  afterRender: [
2796
2806
  () => {
@@ -2856,7 +2866,7 @@ class DataGrid {
2856
2866
  clearSelection() {
2857
2867
  this.gridApiFeature.clearSelection();
2858
2868
  }
2859
- /** Selects all currently loaded rows (multi mode only) and emits `selectChange`. */
2869
+ /** Selects all currently loaded rows (multimode only) and emits `selectChange`. */
2860
2870
  selectAllLoaded() {
2861
2871
  this.gridApiFeature.selectAllLoaded();
2862
2872
  }
@@ -3087,12 +3097,6 @@ class DataGrid {
3087
3097
  this.currentSortOrder = last.order;
3088
3098
  return;
3089
3099
  }
3090
- const firstSortable = this.extendedColumns()?.find((c) => !!c.sortKey);
3091
- if (firstSortable) {
3092
- this.currentSortField = firstSortable.sortKey;
3093
- this.currentSortOrder = 'asc';
3094
- this.setCurrentSorts([{ key: firstSortable.sortKey, order: 'asc' }]);
3095
- }
3096
3100
  }
3097
3101
  initScroll() {
3098
3102
  void this.loadOverlayScrollFeature();
@@ -3136,7 +3140,7 @@ class DataGrid {
3136
3140
  if (this.tooltipFeaturePromise) {
3137
3141
  return this.tooltipFeaturePromise;
3138
3142
  }
3139
- this.tooltipFeaturePromise = import('./reforgium-data-grid-grid-tooltip.feature-CMo88m8o.mjs').then(({ createGridTooltipFeature }) => {
3143
+ this.tooltipFeaturePromise = import('./reforgium-data-grid-grid-tooltip.feature-i-k8F-1I.mjs').then(({ createGridTooltipFeature }) => {
3140
3144
  const feature = createGridTooltipFeature({
3141
3145
  getTooltipState: () => this.tooltipState(),
3142
3146
  setTooltipState: (state) => this.tooltipState.set(state),
@@ -3155,7 +3159,7 @@ class DataGrid {
3155
3159
  if (this.overlayScrollFeaturePromise) {
3156
3160
  return this.overlayScrollFeaturePromise;
3157
3161
  }
3158
- this.overlayScrollFeaturePromise = import('./reforgium-data-grid-grid-overlay-scroll.feature-B3hwiKYh.mjs').then(({ createGridOverlayScrollFeature }) => {
3162
+ this.overlayScrollFeaturePromise = import('./reforgium-data-grid-grid-overlay-scroll.feature-C-_Cnt4M.mjs').then(({ createGridOverlayScrollFeature }) => {
3159
3163
  const feature = createGridOverlayScrollFeature({
3160
3164
  getScrollElement: () => this.scrollEl()?.nativeElement ?? null,
3161
3165
  getThumbTop: () => this.vm.thumbTopPx(),
@@ -3280,4 +3284,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
3280
3284
  */
3281
3285
 
3282
3286
  export { DataGridTypeCellTemplateDirective as D, clampThumbTop as a, DataGridCellTemplateDirective as b, computeScrollbarState as c, DataGridHeaderTemplateDirective as d, DataGridRowDirective as e, DataGridDeclarativeColumn as f, DataGridDeclarativeHeaderDirective as g, DataGridDeclarativeCellDirective as h, DataGridCellEmptyDirective as i, DataGridCellLoadingDirective as j, DataGridStickyRowDirective as k, DataGridSortIconDirective as l, mapThumbTopToScrollTop as m, DataGridExpanderIconDirective as n, DATA_GRID_CONFIG as o, DEFAULT_DATA_GRID_DEFAULTS as p, provideDataGridDefaults as q, DataGrid as r };
3283
- //# sourceMappingURL=reforgium-data-grid-reforgium-data-grid-uZ3onkWO.mjs.map
3287
+ //# sourceMappingURL=reforgium-data-grid-reforgium-data-grid-YSzBRJ5h.mjs.map
@@ -1,2 +1,2 @@
1
- export { o as DATA_GRID_CONFIG, p as DEFAULT_DATA_GRID_DEFAULTS, r as DataGrid, i as DataGridCellEmptyDirective, j as DataGridCellLoadingDirective, b as DataGridCellTemplateDirective, h as DataGridDeclarativeCellDirective, f as DataGridDeclarativeColumn, g as DataGridDeclarativeHeaderDirective, n as DataGridExpanderIconDirective, d as DataGridHeaderTemplateDirective, e as DataGridRowDirective, l as DataGridSortIconDirective, k as DataGridStickyRowDirective, D as DataGridTypeCellTemplateDirective, q as provideDataGridDefaults } from './reforgium-data-grid-reforgium-data-grid-uZ3onkWO.mjs';
1
+ export { o as DATA_GRID_CONFIG, p as DEFAULT_DATA_GRID_DEFAULTS, r as DataGrid, i as DataGridCellEmptyDirective, j as DataGridCellLoadingDirective, b as DataGridCellTemplateDirective, h as DataGridDeclarativeCellDirective, f as DataGridDeclarativeColumn, g as DataGridDeclarativeHeaderDirective, n as DataGridExpanderIconDirective, d as DataGridHeaderTemplateDirective, e as DataGridRowDirective, l as DataGridSortIconDirective, k as DataGridStickyRowDirective, D as DataGridTypeCellTemplateDirective, q as provideDataGridDefaults } from './reforgium-data-grid-reforgium-data-grid-YSzBRJ5h.mjs';
2
2
  //# sourceMappingURL=reforgium-data-grid.mjs.map
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.2.2",
2
+ "version": "2.3.0",
3
3
  "name": "@reforgium/data-grid",
4
4
  "description": "reforgium DataGrid component",
5
5
  "author": "rtommievich",
@@ -1,18 +1,26 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { TemplateRef } from '@angular/core';
2
+ import { TemplateRef, AfterContentChecked } from '@angular/core';
3
3
  import { GridColumn } from '@reforgium/data-grid';
4
4
 
5
5
  type GridColumnPin = 'none' | 'left' | 'right';
6
6
 
7
+ type RowLike$1 = Record<string, unknown>;
8
+ type DataGridColumnManagerColumnTitleContext<Data extends RowLike$1 = RowLike$1> = {
9
+ $implicit: string;
10
+ title: string;
11
+ column: GridColumn<Data>;
12
+ };
13
+ declare class DataGridColumnManagerColumnTitleDirective<Data extends RowLike$1 = RowLike$1> {
14
+ readonly template: TemplateRef<any>;
15
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DataGridColumnManagerColumnTitleDirective<any>, never>;
16
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<DataGridColumnManagerColumnTitleDirective<any>, "ng-template[reDataGridColumnManagerColumnTitle]", never, {}, {}, never, never, true, never>;
17
+ }
18
+
7
19
  type RowLike = Record<string, unknown>;
8
- declare class DataGridColumnManager<Data extends RowLike = RowLike> {
20
+ declare class DataGridColumnManager<Data extends RowLike = RowLike> implements AfterContentChecked {
21
+ private host;
9
22
  columns: _angular_core.InputSignal<GridColumn<Data>[]>;
10
23
  triggerLabel: _angular_core.InputSignal<string>;
11
- triggerTemplate: _angular_core.InputSignal<TemplateRef<{
12
- $implicit: string;
13
- visible: number;
14
- total: number;
15
- }> | undefined>;
16
24
  controlsVisible: _angular_core.InputSignalWithTransform<boolean, unknown>;
17
25
  searchable: _angular_core.InputSignalWithTransform<boolean, unknown>;
18
26
  searchPlaceholder: _angular_core.InputSignal<string>;
@@ -20,17 +28,28 @@ declare class DataGridColumnManager<Data extends RowLike = RowLike> {
20
28
  allowPin: _angular_core.InputSignalWithTransform<boolean, unknown>;
21
29
  allowVisibility: _angular_core.InputSignalWithTransform<boolean, unknown>;
22
30
  columnsChange: _angular_core.OutputEmitterRef<GridColumn<Data>[]>;
31
+ private triggerDirective;
32
+ protected columnTitleTemplate: _angular_core.Signal<DataGridColumnManagerColumnTitleDirective<any> | undefined>;
23
33
  protected state: _angular_core.WritableSignal<GridColumn<Data>[]>;
24
34
  protected searchQuery: _angular_core.WritableSignal<string>;
25
35
  protected draggingKey: _angular_core.WritableSignal<string | null>;
26
36
  protected opened: _angular_core.WritableSignal<boolean>;
37
+ protected openedPinMenuKey: _angular_core.WritableSignal<string | null>;
38
+ protected panelLeft: _angular_core.WritableSignal<number>;
39
+ protected hasCustomTrigger: _angular_core.WritableSignal<boolean>;
27
40
  private root;
41
+ private panel;
28
42
  protected filteredColumns: _angular_core.Signal<GridColumn<Data>[]>;
29
43
  protected visibleColumnsCount: _angular_core.Signal<number>;
30
44
  constructor();
45
+ ngAfterContentChecked(): void;
31
46
  protected pin: (key: string) => GridColumnPin;
32
47
  protected toggleOpen(): void;
48
+ protected onWindowResize(): void;
33
49
  protected onDocumentMouseDown(target: EventTarget | null): void;
50
+ protected togglePinMenu(event: MouseEvent, key: string): void;
51
+ protected selectPin(key: string, pin: GridColumnPin): void;
52
+ protected pinLabel(pin: GridColumnPin): string;
34
53
  protected onSearch(event: Event): void;
35
54
  protected canHideColumn(key: string): boolean;
36
55
  protected onVisibleChange(key: string): void;
@@ -44,10 +63,21 @@ declare class DataGridColumnManager<Data extends RowLike = RowLike> {
44
63
  private reorderByKey;
45
64
  private findColumn;
46
65
  private commit;
66
+ private hasProjectedTrigger;
67
+ private syncCustomTriggerState;
68
+ private isInsidePinMenu;
69
+ protected buildColumnTitleContext(column: GridColumn<Data>): DataGridColumnManagerColumnTitleContext<Data>;
70
+ private schedulePanelPositioning;
71
+ private positionPanel;
47
72
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DataGridColumnManager<any>, never>;
48
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DataGridColumnManager<any>, "re-data-grid-column-manager", never, { "columns": { "alias": "columns"; "required": false; "isSignal": true; }; "triggerLabel": { "alias": "triggerLabel"; "required": false; "isSignal": true; }; "triggerTemplate": { "alias": "triggerTemplate"; "required": false; "isSignal": true; }; "controlsVisible": { "alias": "controlsVisible"; "required": false; "isSignal": true; }; "searchable": { "alias": "searchable"; "required": false; "isSignal": true; }; "searchPlaceholder": { "alias": "searchPlaceholder"; "required": false; "isSignal": true; }; "allowReorder": { "alias": "allowReorder"; "required": false; "isSignal": true; }; "allowPin": { "alias": "allowPin"; "required": false; "isSignal": true; }; "allowVisibility": { "alias": "allowVisibility"; "required": false; "isSignal": true; }; }, { "columnsChange": "columnsChange"; }, never, never, true, never>;
73
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DataGridColumnManager<any>, "re-data-grid-column-manager", never, { "columns": { "alias": "columns"; "required": false; "isSignal": true; }; "triggerLabel": { "alias": "triggerLabel"; "required": false; "isSignal": true; }; "controlsVisible": { "alias": "controlsVisible"; "required": false; "isSignal": true; }; "searchable": { "alias": "searchable"; "required": false; "isSignal": true; }; "searchPlaceholder": { "alias": "searchPlaceholder"; "required": false; "isSignal": true; }; "allowReorder": { "alias": "allowReorder"; "required": false; "isSignal": true; }; "allowPin": { "alias": "allowPin"; "required": false; "isSignal": true; }; "allowVisibility": { "alias": "allowVisibility"; "required": false; "isSignal": true; }; }, { "columnsChange": "columnsChange"; }, ["triggerDirective", "columnTitleTemplate"], ["[reDataGridColumnManagerTrigger]"], true, never>;
74
+ }
75
+
76
+ declare class DataGridColumnManagerTriggerDirective {
77
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DataGridColumnManagerTriggerDirective, never>;
78
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<DataGridColumnManagerTriggerDirective, "[reDataGridColumnManagerTrigger]", never, {}, {}, never, never, true, never>;
49
79
  }
50
80
 
51
- export { DataGridColumnManager };
52
- export type { GridColumnPin };
81
+ export { DataGridColumnManager, DataGridColumnManagerColumnTitleDirective, DataGridColumnManagerTriggerDirective };
82
+ export type { DataGridColumnManagerColumnTitleContext, GridColumnPin };
53
83
  //# sourceMappingURL=reforgium-data-grid-column-manager.d.ts.map
@@ -1420,6 +1420,7 @@ declare class DataGrid<Data extends AnyDict> {
1420
1420
  protected stickyRowTopPx: _angular_core.WritableSignal<number>;
1421
1421
  protected stickyRowData: _angular_core.Signal<Data | null>;
1422
1422
  private stickyIndexes;
1423
+ private contentInitialized;
1423
1424
  protected expanderMap: _angular_core.WritableSignal<Map<DataKey<Data>, boolean>>;
1424
1425
  protected declarativeColumns: _angular_core.Signal<DeclarativeColumnsResult<Data>>;
1425
1426
  protected sourceColumns: _angular_core.Signal<GridColumn<Data>[]>;
@@ -1440,7 +1441,7 @@ declare class DataGrid<Data extends AnyDict> {
1440
1441
  constructor();
1441
1442
  /** Clears current selection and emits `selectChange`. */
1442
1443
  clearSelection(): void;
1443
- /** Selects all currently loaded rows (multi mode only) and emits `selectChange`. */
1444
+ /** Selects all currently loaded rows (multimode only) and emits `selectChange`. */
1444
1445
  selectAllLoaded(): void;
1445
1446
  /** Resets sorting state and emits sort events. */
1446
1447
  resetSort(): void;