@alaarab/ogrid-angular-radix 2.0.4

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.
Files changed (33) hide show
  1. package/README.md +76 -0
  2. package/dist/esm/column-chooser/column-chooser.component.js +199 -0
  3. package/dist/esm/column-header-filter/column-header-filter.component.js +497 -0
  4. package/dist/esm/datagrid-table/datagrid-table.component.js +573 -0
  5. package/dist/esm/index.js +14 -0
  6. package/dist/esm/ogrid/ogrid.component.js +77 -0
  7. package/dist/esm/pagination-controls/pagination-controls.component.js +189 -0
  8. package/dist/types/column-chooser/column-chooser.component.d.ts +26 -0
  9. package/dist/types/column-header-filter/column-header-filter.component.d.ts +67 -0
  10. package/dist/types/datagrid-table/datagrid-table.component.d.ts +131 -0
  11. package/dist/types/index.d.ts +12 -0
  12. package/dist/types/ogrid/ogrid.component.d.ts +14 -0
  13. package/dist/types/pagination-controls/pagination-controls.component.d.ts +15 -0
  14. package/jest-mocks/angular-cdk-overlay.cjs.js +38 -0
  15. package/jest-mocks/style-mock.js +1 -0
  16. package/jest.config.js +43 -0
  17. package/package.json +37 -0
  18. package/scripts/compile-styles.js +53 -0
  19. package/src/__tests__/column-chooser.component.spec.ts.skip +195 -0
  20. package/src/__tests__/column-header-filter.component.spec.ts.skip +401 -0
  21. package/src/__tests__/datagrid-table.component.spec.ts.skip +417 -0
  22. package/src/__tests__/exports.test.ts +54 -0
  23. package/src/__tests__/ogrid.component.spec.ts.skip +236 -0
  24. package/src/__tests__/pagination-controls.component.spec.ts.skip +190 -0
  25. package/src/column-chooser/column-chooser.component.ts +204 -0
  26. package/src/column-header-filter/column-header-filter.component.ts +528 -0
  27. package/src/datagrid-table/datagrid-table.component.scss +289 -0
  28. package/src/datagrid-table/datagrid-table.component.ts +636 -0
  29. package/src/index.ts +16 -0
  30. package/src/ogrid/ogrid.component.ts +78 -0
  31. package/src/pagination-controls/pagination-controls.component.ts +187 -0
  32. package/tsconfig.build.json +9 -0
  33. package/tsconfig.json +21 -0
@@ -0,0 +1,189 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Component, input, output, computed, ChangeDetectionStrategy } from '@angular/core';
8
+ import { getPaginationViewModel } from '@alaarab/ogrid-angular';
9
+ /**
10
+ * Pagination controls component for Angular Radix (lightweight styling).
11
+ * Standalone component with inline template and CSS variables for theming.
12
+ */
13
+ let PaginationControlsComponent = class PaginationControlsComponent {
14
+ constructor() {
15
+ this.currentPage = input.required();
16
+ this.pageSize = input.required();
17
+ this.totalCount = input.required();
18
+ this.pageSizeOptions = input(undefined);
19
+ this.entityLabelPlural = input('items');
20
+ this.pageChange = output();
21
+ this.pageSizeChange = output();
22
+ this.vm = computed(() => {
23
+ const opts = this.pageSizeOptions();
24
+ return getPaginationViewModel(this.currentPage(), this.pageSize(), this.totalCount(), opts ? { pageSizeOptions: opts } : undefined);
25
+ });
26
+ }
27
+ onPageSizeSelect(event) {
28
+ const value = Number(event.target.value);
29
+ this.pageSizeChange.emit(value);
30
+ }
31
+ };
32
+ PaginationControlsComponent = __decorate([
33
+ Component({
34
+ selector: 'ogrid-pagination-controls',
35
+ standalone: true,
36
+ changeDetection: ChangeDetectionStrategy.OnPush,
37
+ template: `
38
+ @if (vm(); as vm) {
39
+ <nav class="ogrid-pagination" role="navigation" aria-label="Pagination">
40
+ <span class="ogrid-pagination__info">
41
+ Showing {{ vm.startItem }} to {{ vm.endItem }} of {{ totalCount().toLocaleString() }} {{ entityLabelPlural() }}
42
+ </span>
43
+
44
+ <span class="ogrid-pagination__pages">
45
+ <button
46
+ class="ogrid-pagination__btn"
47
+ [disabled]="currentPage() === 1"
48
+ (click)="pageChange.emit(1)"
49
+ aria-label="First page"
50
+ >⏮</button>
51
+ <button
52
+ class="ogrid-pagination__btn"
53
+ [disabled]="currentPage() === 1"
54
+ (click)="pageChange.emit(currentPage() - 1)"
55
+ aria-label="Previous page"
56
+ >◀</button>
57
+
58
+ @if (vm.showStartEllipsis) {
59
+ <button class="ogrid-pagination__btn" (click)="pageChange.emit(1)" aria-label="Page 1">1</button>
60
+ <span class="ogrid-pagination__ellipsis" aria-hidden="true">…</span>
61
+ }
62
+
63
+ @for (pageNum of vm.pageNumbers; track pageNum) {
64
+ <button
65
+ class="ogrid-pagination__btn"
66
+ [class.ogrid-pagination__btn--active]="currentPage() === pageNum"
67
+ (click)="pageChange.emit(pageNum)"
68
+ [attr.aria-label]="'Page ' + pageNum"
69
+ [attr.aria-current]="currentPage() === pageNum ? 'page' : null"
70
+ >{{ pageNum }}</button>
71
+ }
72
+
73
+ @if (vm.showEndEllipsis) {
74
+ <span class="ogrid-pagination__ellipsis" aria-hidden="true">…</span>
75
+ <button
76
+ class="ogrid-pagination__btn"
77
+ (click)="pageChange.emit(vm.totalPages)"
78
+ [attr.aria-label]="'Page ' + vm.totalPages"
79
+ >{{ vm.totalPages }}</button>
80
+ }
81
+
82
+ <button
83
+ class="ogrid-pagination__btn"
84
+ [disabled]="currentPage() >= vm.totalPages"
85
+ (click)="pageChange.emit(currentPage() + 1)"
86
+ aria-label="Next page"
87
+ >▶</button>
88
+ <button
89
+ class="ogrid-pagination__btn"
90
+ [disabled]="currentPage() >= vm.totalPages"
91
+ (click)="pageChange.emit(vm.totalPages)"
92
+ aria-label="Last page"
93
+ >⏭</button>
94
+ </span>
95
+
96
+ <span class="ogrid-pagination__size">
97
+ <label>Rows
98
+ <select
99
+ [value]="pageSize()"
100
+ (change)="onPageSizeSelect($event)"
101
+ aria-label="Rows per page"
102
+ >
103
+ @for (n of vm.pageSizeOptions; track n) {
104
+ <option [value]="n" [selected]="pageSize() === n">{{ n }}</option>
105
+ }
106
+ </select>
107
+ </label>
108
+ </span>
109
+ </nav>
110
+ }
111
+ `,
112
+ styles: [`
113
+ :host { display: block; }
114
+ .ogrid-pagination {
115
+ display: flex;
116
+ align-items: center;
117
+ justify-content: space-between;
118
+ flex-wrap: wrap;
119
+ gap: 8px;
120
+ padding: 6px 12px;
121
+ font-size: 14px;
122
+ background: var(--ogrid-bg, #ffffff);
123
+ }
124
+ .ogrid-pagination__info {
125
+ color: var(--ogrid-fg, #242424);
126
+ opacity: 0.7;
127
+ }
128
+ .ogrid-pagination__pages {
129
+ display: flex;
130
+ align-items: center;
131
+ gap: 4px;
132
+ }
133
+ .ogrid-pagination__btn {
134
+ min-width: 32px;
135
+ height: 32px;
136
+ padding: 0 8px;
137
+ border: 1px solid var(--ogrid-border, #e0e0e0);
138
+ border-radius: 4px;
139
+ background: var(--ogrid-bg, #ffffff);
140
+ color: var(--ogrid-fg, #242424);
141
+ cursor: pointer;
142
+ font-size: 14px;
143
+ transition: all 0.15s ease;
144
+ }
145
+ .ogrid-pagination__btn:hover:not(:disabled) {
146
+ background: var(--ogrid-hover-bg, #f0f0f0);
147
+ border-color: var(--ogrid-active-border, #0078d4);
148
+ }
149
+ .ogrid-pagination__btn:disabled {
150
+ opacity: 0.4;
151
+ cursor: not-allowed;
152
+ }
153
+ .ogrid-pagination__btn--active {
154
+ background: var(--ogrid-active-border, #0078d4);
155
+ color: #ffffff;
156
+ border-color: var(--ogrid-active-border, #0078d4);
157
+ font-weight: 600;
158
+ }
159
+ .ogrid-pagination__ellipsis {
160
+ margin: 0 4px;
161
+ color: var(--ogrid-fg, #242424);
162
+ opacity: 0.6;
163
+ }
164
+ .ogrid-pagination__size {
165
+ display: flex;
166
+ align-items: center;
167
+ gap: 8px;
168
+ color: var(--ogrid-fg, #242424);
169
+ }
170
+ .ogrid-pagination__size select {
171
+ min-width: 60px;
172
+ height: 32px;
173
+ padding: 4px 8px;
174
+ border: 1px solid var(--ogrid-border, #e0e0e0);
175
+ border-radius: 4px;
176
+ background: var(--ogrid-bg, #ffffff);
177
+ color: var(--ogrid-fg, #242424);
178
+ font-size: 14px;
179
+ margin-left: 8px;
180
+ cursor: pointer;
181
+ }
182
+ .ogrid-pagination__size select:focus {
183
+ outline: 2px solid var(--ogrid-active-border, #0078d4);
184
+ outline-offset: 1px;
185
+ }
186
+ `],
187
+ })
188
+ ], PaginationControlsComponent);
189
+ export { PaginationControlsComponent };
@@ -0,0 +1,26 @@
1
+ import type { IColumnDefinition } from '@alaarab/ogrid-angular';
2
+ export interface IColumnChooserProps {
3
+ columns: IColumnDefinition[];
4
+ visibleColumns: Set<string>;
5
+ onVisibilityChange: (columnKey: string, visible: boolean) => void;
6
+ }
7
+ /**
8
+ * Column visibility chooser dropdown for Angular Radix (lightweight styling).
9
+ * Standalone component with inline template and CSS variables for theming.
10
+ */
11
+ export declare class ColumnChooserComponent {
12
+ readonly columns: import("@angular/core").InputSignal<IColumnDefinition[]>;
13
+ readonly visibleColumns: import("@angular/core").InputSignal<Set<string>>;
14
+ readonly visibilityChange: import("@angular/core").OutputEmitterRef<{
15
+ columnKey: string;
16
+ visible: boolean;
17
+ }>;
18
+ readonly isOpen: import("@angular/core").WritableSignal<boolean>;
19
+ readonly visibleCount: import("@angular/core").Signal<number>;
20
+ readonly totalCount: import("@angular/core").Signal<number>;
21
+ toggle(): void;
22
+ onCheckboxChange(columnKey: string, event: Event): void;
23
+ selectAll(): void;
24
+ clearAll(): void;
25
+ onDocumentClick(event: MouseEvent): void;
26
+ }
@@ -0,0 +1,67 @@
1
+ import type { ColumnFilterType, IDateFilterValue, UserLike } from '@alaarab/ogrid-angular';
2
+ export interface IColumnHeaderFilterProps {
3
+ columnKey: string;
4
+ columnName: string;
5
+ filterType: ColumnFilterType;
6
+ isSorted?: boolean;
7
+ isSortedDescending?: boolean;
8
+ onSort?: () => void;
9
+ selectedValues?: string[];
10
+ onFilterChange?: (values: string[]) => void;
11
+ options?: string[];
12
+ isLoadingOptions?: boolean;
13
+ textValue?: string;
14
+ onTextChange?: (value: string) => void;
15
+ selectedUser?: UserLike;
16
+ onUserChange?: (user: UserLike | undefined) => void;
17
+ peopleSearch?: (query: string) => Promise<UserLike[]>;
18
+ dateValue?: IDateFilterValue;
19
+ onDateChange?: (value: IDateFilterValue | undefined) => void;
20
+ }
21
+ /**
22
+ * Column header filter component for Angular Radix (lightweight styling).
23
+ * Standalone component with inline template and positioned popovers.
24
+ */
25
+ export declare class ColumnHeaderFilterComponent {
26
+ readonly columnKey: import("@angular/core").InputSignal<string>;
27
+ readonly columnName: import("@angular/core").InputSignal<string>;
28
+ readonly filterType: import("@angular/core").InputSignal<ColumnFilterType>;
29
+ readonly isSorted: import("@angular/core").InputSignal<boolean>;
30
+ readonly isSortedDescending: import("@angular/core").InputSignal<boolean>;
31
+ readonly onSort: import("@angular/core").InputSignal<(() => void) | undefined>;
32
+ readonly selectedValues: import("@angular/core").InputSignal<string[]>;
33
+ readonly onFilterChange: import("@angular/core").InputSignal<((values: string[]) => void) | undefined>;
34
+ readonly options: import("@angular/core").InputSignal<string[] | undefined>;
35
+ readonly isLoadingOptions: import("@angular/core").InputSignal<boolean>;
36
+ readonly textValue: import("@angular/core").InputSignal<string>;
37
+ readonly onTextChange: import("@angular/core").InputSignal<((value: string) => void) | undefined>;
38
+ readonly selectedUser: import("@angular/core").InputSignal<UserLike | undefined>;
39
+ readonly onUserChange: import("@angular/core").InputSignal<((user: UserLike | undefined) => void) | undefined>;
40
+ readonly peopleSearch: import("@angular/core").InputSignal<((query: string) => Promise<UserLike[]>) | undefined>;
41
+ readonly dateValue: import("@angular/core").InputSignal<IDateFilterValue | undefined>;
42
+ readonly onDateChange: import("@angular/core").InputSignal<((value: IDateFilterValue | undefined) => void) | undefined>;
43
+ private readonly headerRef;
44
+ readonly isFilterOpen: import("@angular/core").WritableSignal<boolean>;
45
+ readonly popoverTop: import("@angular/core").WritableSignal<number>;
46
+ readonly popoverLeft: import("@angular/core").WritableSignal<number>;
47
+ readonly tempTextValue: import("@angular/core").WritableSignal<string>;
48
+ readonly searchText: import("@angular/core").WritableSignal<string>;
49
+ readonly tempSelected: import("@angular/core").WritableSignal<Set<string>>;
50
+ readonly tempDateFrom: import("@angular/core").WritableSignal<string>;
51
+ readonly tempDateTo: import("@angular/core").WritableSignal<string>;
52
+ readonly hasActiveFilter: import("@angular/core").Signal<boolean>;
53
+ readonly filteredOptions: import("@angular/core").Signal<string[]>;
54
+ toggleFilter(event: MouseEvent): void;
55
+ onDocumentClick(event: MouseEvent): void;
56
+ asInputValue(event: Event): string;
57
+ onTextKeydown(event: KeyboardEvent): void;
58
+ handleTextApply(): void;
59
+ handleTextClear(): void;
60
+ handleCheckboxChange(option: string, event: Event): void;
61
+ handleSelectAllFiltered(): void;
62
+ handleClearSelection(): void;
63
+ handleMultiSelectApply(): void;
64
+ handleMultiSelectClear(): void;
65
+ handleDateApply(): void;
66
+ handleDateClear(): void;
67
+ }
@@ -0,0 +1,131 @@
1
+ import { ColumnReorderService, VirtualScrollService } from '@alaarab/ogrid-angular';
2
+ import type { IOGridDataGridProps, IColumnDef, RowId, CellRenderDescriptor, HeaderFilterConfig } from '@alaarab/ogrid-angular';
3
+ /**
4
+ * DataGridTable component for Angular Radix using native HTML table.
5
+ * Standalone component with lightweight styling and CSS variables.
6
+ */
7
+ export declare class DataGridTableComponent<T> {
8
+ readonly propsInput: import("@angular/core").InputSignal<IOGridDataGridProps<T>>;
9
+ private readonly wrapperRef;
10
+ private readonly tableContainerRef;
11
+ private readonly stateService;
12
+ readonly columnReorderService: ColumnReorderService<T>;
13
+ readonly virtualScrollService: VirtualScrollService;
14
+ private lastMouseShift;
15
+ private columnSizingVersion;
16
+ constructor();
17
+ private readonly state;
18
+ readonly items: import("@angular/core").Signal<T[]>;
19
+ readonly getRowId: import("@angular/core").Signal<(item: T) => RowId>;
20
+ readonly isLoading: import("@angular/core").Signal<boolean>;
21
+ readonly loadingMessage: import("@angular/core").Signal<string>;
22
+ readonly freezeRows: import("@angular/core").Signal<number | undefined>;
23
+ readonly freezeCols: import("@angular/core").Signal<number | undefined>;
24
+ readonly layoutModeFit: import("@angular/core").Signal<boolean>;
25
+ readonly ariaLabel: import("@angular/core").Signal<string>;
26
+ readonly ariaLabelledBy: import("@angular/core").Signal<string | undefined>;
27
+ readonly emptyState: import("@angular/core").Signal<{
28
+ onClearAll: () => void;
29
+ hasActiveFilters: boolean;
30
+ message?: string;
31
+ render?: import("@angular/core").TemplateRef<unknown>;
32
+ } | undefined>;
33
+ readonly visibleCols: import("@angular/core").Signal<IColumnDef<T>[]>;
34
+ readonly hasCheckboxCol: import("@angular/core").Signal<boolean>;
35
+ readonly colOffset: import("@angular/core").Signal<number>;
36
+ readonly containerWidth: import("@angular/core").Signal<number>;
37
+ readonly minTableWidth: import("@angular/core").Signal<number>;
38
+ readonly desiredTableWidth: import("@angular/core").Signal<number>;
39
+ readonly columnSizingOverrides: import("@angular/core").Signal<Record<string, {
40
+ widthPx: number;
41
+ }>>;
42
+ readonly selectedRowIds: import("@angular/core").Signal<Set<RowId>>;
43
+ readonly allSelected: import("@angular/core").Signal<boolean>;
44
+ readonly someSelected: import("@angular/core").Signal<boolean>;
45
+ readonly editingCell: import("@angular/core").Signal<{
46
+ rowId: RowId;
47
+ columnId: string;
48
+ } | null>;
49
+ readonly pendingEditorValue: import("@angular/core").Signal<unknown>;
50
+ readonly activeCell: import("@angular/core").Signal<import("@alaarab/ogrid-core").IActiveCell | null>;
51
+ readonly selectionRange: import("@angular/core").Signal<import("@alaarab/ogrid-core").ISelectionRange | null>;
52
+ readonly hasCellSelection: import("@angular/core").Signal<boolean>;
53
+ readonly cutRange: import("@angular/core").Signal<import("@alaarab/ogrid-core").ISelectionRange | null>;
54
+ readonly copyRange: import("@angular/core").Signal<import("@alaarab/ogrid-core").ISelectionRange | null>;
55
+ readonly canUndo: import("@angular/core").Signal<boolean>;
56
+ readonly canRedo: import("@angular/core").Signal<boolean>;
57
+ readonly isDragging: import("@angular/core").Signal<boolean>;
58
+ readonly menuPosition: import("@angular/core").Signal<{
59
+ x: number;
60
+ y: number;
61
+ } | null>;
62
+ readonly statusBarConfig: import("@angular/core").Signal<import("@alaarab/ogrid-core").IStatusBarProps | null>;
63
+ readonly showEmptyInGrid: import("@angular/core").Signal<boolean>;
64
+ readonly headerFilterInput: import("@angular/core").Signal<{
65
+ sortBy?: string;
66
+ sortDirection: "asc" | "desc";
67
+ onColumnSort: (columnKey: string) => void;
68
+ filters: import("@alaarab/ogrid-core").IFilters;
69
+ onFilterChange: (key: string, value: import("@alaarab/ogrid-core").FilterValue | undefined) => void;
70
+ filterOptions: Record<string, string[]>;
71
+ loadingFilterOptions: Record<string, boolean>;
72
+ peopleSearch?: (query: string) => Promise<import("@alaarab/ogrid-core").UserLike[]>;
73
+ }>;
74
+ readonly cellDescriptorInput: import("@angular/core").Signal<{
75
+ editingCell: {
76
+ rowId: RowId;
77
+ columnId: string;
78
+ } | null;
79
+ activeCell: import("@alaarab/ogrid-core").IActiveCell | null;
80
+ selectionRange: import("@alaarab/ogrid-core").ISelectionRange | null;
81
+ cutRange: import("@alaarab/ogrid-core").ISelectionRange | null;
82
+ copyRange: import("@alaarab/ogrid-core").ISelectionRange | null;
83
+ colOffset: number;
84
+ itemsLength: number;
85
+ getRowId: (item: T) => RowId;
86
+ editable?: boolean;
87
+ onCellValueChanged?: ((event: import("@alaarab/ogrid-core").ICellValueChangedEvent<T>) => void) | undefined;
88
+ isDragging: boolean;
89
+ }>;
90
+ readonly allowOverflowX: import("@angular/core").Signal<boolean>;
91
+ readonly selectionCellCount: import("@angular/core").Signal<number | undefined>;
92
+ readonly headerRows: import("@angular/core").Signal<import("@alaarab/ogrid-core").HeaderRow<T>[]>;
93
+ readonly columnLayouts: import("@angular/core").Signal<{
94
+ col: IColumnDef<T>;
95
+ pinnedLeft: boolean;
96
+ pinnedRight: boolean;
97
+ minWidth: number;
98
+ width: number;
99
+ }[]>;
100
+ asColumnDef(colDef: unknown): IColumnDef<T>;
101
+ visibleColIndex(col: IColumnDef<T>): number;
102
+ getColumnWidth(col: IColumnDef<T>): number;
103
+ getFilterConfig(col: IColumnDef<T>): HeaderFilterConfig;
104
+ getCellDescriptor(item: T, col: IColumnDef<T>, rowIndex: number, colIdx: number): CellRenderDescriptor;
105
+ resolveCellContent(col: IColumnDef<T>, item: T, displayValue: unknown): string;
106
+ resolveCellStyleFn(col: IColumnDef<T>, item: T): Record<string, string> | undefined;
107
+ getSelectValues(col: IColumnDef<T>): string[];
108
+ formatDateForInput(value: unknown): string;
109
+ onWrapperMouseDown(event: MouseEvent): void;
110
+ onGridKeyDown(event: KeyboardEvent): void;
111
+ onCellMouseDown(event: MouseEvent, rowIndex: number, globalColIndex: number): void;
112
+ onCellClick(rowIndex: number, globalColIndex: number): void;
113
+ onCellContextMenu(event: MouseEvent): void;
114
+ onCellDblClick(rowId: RowId, columnId: string): void;
115
+ onFillHandleMouseDown(event: MouseEvent): void;
116
+ onResizeStart(event: MouseEvent, col: IColumnDef<T>): void;
117
+ onSelectAllChange(event: Event): void;
118
+ onRowClick(event: MouseEvent, rowId: RowId): void;
119
+ onRowCheckboxChange(rowId: RowId, event: Event, rowIndex: number): void;
120
+ commitEdit(item: T, columnId: string, oldValue: unknown, newValue: unknown, rowIndex: number, globalColIndex: number): void;
121
+ cancelEdit(): void;
122
+ onEditorKeydown(event: KeyboardEvent, item: T, columnId: string, oldValue: unknown, rowIndex: number, globalColIndex: number): void;
123
+ closeContextMenu(): void;
124
+ handleCopy(): void;
125
+ handleCut(): void;
126
+ handlePaste(): void;
127
+ handleSelectAllCells(): void;
128
+ onUndo(): void;
129
+ onRedo(): void;
130
+ onHeaderMouseDown(columnId: string, event: MouseEvent): void;
131
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @alaarab/ogrid-angular-radix
3
+ *
4
+ * Lightweight Angular data grid using Angular CDK for overlays.
5
+ * This is the recommended "default" option for Angular developers.
6
+ */
7
+ export * from '@alaarab/ogrid-angular';
8
+ export { OGridComponent } from './ogrid/ogrid.component';
9
+ export { DataGridTableComponent } from './datagrid-table/datagrid-table.component';
10
+ export { ColumnHeaderFilterComponent } from './column-header-filter/column-header-filter.component';
11
+ export { ColumnChooserComponent } from './column-chooser/column-chooser.component';
12
+ export { PaginationControlsComponent } from './pagination-controls/pagination-controls.component';
@@ -0,0 +1,14 @@
1
+ import { OGridService } from '@alaarab/ogrid-angular';
2
+ import type { IOGridProps, IOGridDataGridProps } from '@alaarab/ogrid-angular';
3
+ /**
4
+ * Top-level OGrid component for Angular Radix (lightweight Angular CDK-based implementation).
5
+ * This is the recommended default option for Angular developers.
6
+ * Standalone component — provides OGridService and renders OGridLayout with all sub-components.
7
+ */
8
+ export declare class OGridComponent<T> {
9
+ readonly props: import("@angular/core").InputSignal<IOGridProps<T>>;
10
+ readonly ogridService: OGridService<T>;
11
+ readonly dataGridProps: import("@angular/core").Signal<IOGridDataGridProps<T>>;
12
+ constructor();
13
+ onPageSizeChange(size: number): void;
14
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Pagination controls component for Angular Radix (lightweight styling).
3
+ * Standalone component with inline template and CSS variables for theming.
4
+ */
5
+ export declare class PaginationControlsComponent {
6
+ readonly currentPage: import("@angular/core").InputSignal<number>;
7
+ readonly pageSize: import("@angular/core").InputSignal<number>;
8
+ readonly totalCount: import("@angular/core").InputSignal<number>;
9
+ readonly pageSizeOptions: import("@angular/core").InputSignal<number[] | undefined>;
10
+ readonly entityLabelPlural: import("@angular/core").InputSignal<string>;
11
+ readonly pageChange: import("@angular/core").OutputEmitterRef<number>;
12
+ readonly pageSizeChange: import("@angular/core").OutputEmitterRef<number>;
13
+ readonly vm: import("@angular/core").Signal<import("@alaarab/ogrid-core").PaginationViewModel | null>;
14
+ onPageSizeSelect(event: Event): void;
15
+ }
@@ -0,0 +1,38 @@
1
+ // Mock for @angular/cdk/overlay in tests
2
+ class MockOverlay {
3
+ position() {
4
+ return {
5
+ flexibleConnectedTo() {
6
+ return {
7
+ withPositions() {
8
+ return this;
9
+ }
10
+ };
11
+ }
12
+ };
13
+ }
14
+
15
+ create(config) {
16
+ return {
17
+ attach: jest.fn(),
18
+ detach: jest.fn(),
19
+ dispose: jest.fn(),
20
+ backdropClick: () => ({
21
+ subscribe: jest.fn()
22
+ })
23
+ };
24
+ }
25
+ }
26
+
27
+ class MockComponentPortal {
28
+ constructor(component) {
29
+ this.component = component;
30
+ }
31
+ }
32
+
33
+ module.exports = {
34
+ Overlay: MockOverlay,
35
+ OverlayModule: class MockOverlayModule {},
36
+ ComponentPortal: MockComponentPortal,
37
+ CdkOverlayOrigin: class MockCdkOverlayOrigin {},
38
+ };
@@ -0,0 +1 @@
1
+ module.exports = {};
package/jest.config.js ADDED
@@ -0,0 +1,43 @@
1
+ /** @type {import('jest').Config} */
2
+ module.exports = {
3
+ testEnvironment: 'jsdom',
4
+ roots: ['<rootDir>/src'],
5
+ testMatch: [
6
+ '**/__tests__/**/*.test.ts',
7
+ '**/__tests__/**/*.test.tsx',
8
+ '**/__tests__/**/*.spec.ts',
9
+ ],
10
+ moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
11
+ transform: {
12
+ '^.+\\.tsx?$': [
13
+ 'ts-jest',
14
+ {
15
+ useESM: false,
16
+ tsconfig: {
17
+ esModuleInterop: true,
18
+ allowSyntheticDefaultImports: true,
19
+ module: 'commonjs',
20
+ target: 'es2019',
21
+ types: ['jest', 'node'],
22
+ experimentalDecorators: true,
23
+ useDefineForClassFields: false,
24
+ },
25
+ },
26
+ ],
27
+ },
28
+ moduleNameMapper: {
29
+ '^@alaarab/ogrid-core$': '<rootDir>/../core/src/index.ts',
30
+ '^@alaarab/ogrid-core/testing$': '<rootDir>/../core/src/testing/index.ts',
31
+ '^@alaarab/ogrid-angular$': '<rootDir>/../angular/src/index.ts',
32
+ '^@angular/core/testing$': '<rootDir>/../angular/jest-mocks/angular-core-testing.cjs.js',
33
+ '^@angular/core$': '<rootDir>/../angular/jest-mocks/angular-core.cjs.js',
34
+ '^@angular/common$': '<rootDir>/../angular/jest-mocks/angular-common.cjs.js',
35
+ '^@angular/platform-browser$': '<rootDir>/../angular/jest-mocks/angular-platform-browser.cjs.js',
36
+ '^@angular/cdk/overlay$': '<rootDir>/jest-mocks/angular-cdk-overlay.cjs.js',
37
+ '\\.scss$': '<rootDir>/jest-mocks/style-mock.js',
38
+ },
39
+ transformIgnorePatterns: [
40
+ 'node_modules/(?!(@angular|primeng)/)',
41
+ ],
42
+ testTimeout: 10000,
43
+ };
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@alaarab/ogrid-angular-radix",
3
+ "version": "2.0.4",
4
+ "description": "OGrid Angular Radix – Lightweight data grid with sorting, filtering, pagination, column chooser, and CSV export. Built with Angular CDK.",
5
+ "main": "dist/esm/index.js",
6
+ "types": "dist/types/index.d.ts",
7
+ "keywords": ["ogrid", "datagrid", "angular", "angular-cdk", "data-table", "spreadsheet", "grid"],
8
+ "author": "Ala Arab",
9
+ "license": "MIT",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/alaarab/ogrid.git",
13
+ "directory": "packages/angular-radix"
14
+ },
15
+ "scripts": {
16
+ "build": "rimraf dist && tsc -p tsconfig.build.json && node scripts/compile-styles.js",
17
+ "test": "jest"
18
+ },
19
+ "dependencies": {
20
+ "@alaarab/ogrid-angular": "2.0.4",
21
+ "@angular/cdk": "^21.0.0"
22
+ },
23
+ "peerDependencies": {
24
+ "@angular/core": "^21.0.0",
25
+ "@angular/common": "^21.0.0"
26
+ },
27
+ "devDependencies": {
28
+ "@types/jest": "^29.5.0",
29
+ "jest": "^29.7.0",
30
+ "rimraf": "^5.0.0",
31
+ "sass": "^1.69.0",
32
+ "typescript": "^5.7.0"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ }
37
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Compiles all .module.scss files to .module.css and rewrites dist JS imports.
3
+ */
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const sass = require('sass');
7
+
8
+ const SRC_DIR = path.join(__dirname, '..', 'src');
9
+ const DIST_ESM = path.join(__dirname, '..', 'dist', 'esm');
10
+
11
+ function* walkDir(dir, base = dir) {
12
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
13
+ for (const e of entries) {
14
+ const full = path.join(dir, e.name);
15
+ const rel = path.relative(base, full);
16
+ if (e.isDirectory()) {
17
+ yield* walkDir(full, base);
18
+ } else if (e.isFile() && e.name.endsWith('.module.scss')) {
19
+ yield { full, rel };
20
+ }
21
+ }
22
+ }
23
+
24
+ for (const { full, rel } of walkDir(SRC_DIR)) {
25
+ const outRel = rel.replace(/\.scss$/, '.css');
26
+ const outPath = path.join(DIST_ESM, outRel);
27
+ const outDir = path.dirname(outPath);
28
+ if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
29
+ const result = sass.compile(full);
30
+ fs.writeFileSync(outPath, result.css, 'utf8');
31
+ console.log('Compiled:', rel, '→', outRel);
32
+ }
33
+
34
+ function* walkJs(dir) {
35
+ if (!fs.existsSync(dir)) return;
36
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
37
+ for (const e of entries) {
38
+ const full = path.join(dir, e.name);
39
+ if (e.isDirectory()) yield* walkJs(full);
40
+ else if (e.isFile() && e.name.endsWith('.js')) yield full;
41
+ }
42
+ }
43
+
44
+ for (const jsPath of walkJs(DIST_ESM)) {
45
+ let content = fs.readFileSync(jsPath, 'utf8');
46
+ if (content.includes('.module.scss')) {
47
+ content = content.replace(/\.module\.scss/g, '.module.css');
48
+ fs.writeFileSync(jsPath, content, 'utf8');
49
+ console.log('Rewrote imports:', path.relative(DIST_ESM, jsPath));
50
+ }
51
+ }
52
+
53
+ console.log('Styles compiled and dist JS imports updated.');