@alaarab/ogrid-angular 2.3.0 → 2.4.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/dist/esm/index.js +538 -26
- package/dist/types/components/base-column-header-menu.component.d.ts +30 -0
- package/dist/types/components/base-datagrid-table.component.d.ts +3 -0
- package/dist/types/components/formula-bar.component.d.ts +29 -0
- package/dist/types/components/formula-ref-overlay.component.d.ts +27 -0
- package/dist/types/components/ogrid-layout.component.d.ts +7 -0
- package/dist/types/components/sheet-tabs.component.d.ts +16 -0
- package/dist/types/index.d.ts +5 -1
- package/dist/types/services/datagrid-state.service.d.ts +3 -0
- package/dist/types/services/formula-engine.service.d.ts +1 -3
- package/dist/types/services/ogrid.service.d.ts +41 -1
- package/dist/types/types/dataGridTypes.d.ts +14 -2
- package/dist/types/types/index.d.ts +1 -1
- package/package.json +2 -2
package/dist/esm/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { FormulaEngine,
|
|
1
|
+
import { handleFormulaBarKeyDown, FormulaEngine, createGridDataAccessor, columnLetterToIndex, flattenColumns, getMultiSelectFilterFields, deriveFilterOptionsFromData, processClientSideData, deriveFormulaBarText, extractFormulaReferences, validateColumns, processClientSideDataAsync, validateRowIds, computeNextSortState, mergeFilter, CHECKBOX_COLUMN_WIDTH, DEFAULT_MIN_COLUMN_WIDTH, CELL_PADDING, parseValue, UndoRedoStack, rangesEqual, normalizeSelectionRange, formatSelectionAsTsv, parseTsvClipboard, getCellValue, applyCellDeletion, getScrollTopForRow, computeTabNavigation, applyFillValues, computeAggregations, getDataGridStatusBarConfig, computeVisibleRange, computeTotalHeight, computeVisibleColumnRange, validateVirtualScrollConfig, GRID_BORDER_RADIUS, getStatusBarParts, GRID_CONTEXT_MENU_ITEMS, formatShortcut, injectGlobalStyles, partitionColumnsForVirtualization, buildHeaderRows, getHeaderFilterConfig, getCellRenderDescriptor, resolveCellDisplayContent, resolveCellStyle, buildPopoverEditorProps, measureColumnContentWidth, getPaginationViewModel, getColumnHeaderMenuItems, ROW_NUMBER_COLUMN_WIDTH, reorderColumnArray, findCtrlArrowTarget, measureRange, FORMULA_REF_COLORS } from '@alaarab/ogrid-core';
|
|
2
2
|
export * from '@alaarab/ogrid-core';
|
|
3
3
|
export { CELL_PADDING, CHECKBOX_COLUMN_WIDTH, DEFAULT_DEBOUNCE_MS, DEFAULT_MIN_COLUMN_WIDTH, GRID_BORDER_RADIUS, PEOPLE_SEARCH_DEBOUNCE_MS, ROW_NUMBER_COLUMN_WIDTH, SIDEBAR_TRANSITION_MS, Z_INDEX, debounce, getCellRenderDescriptor, getHeaderFilterConfig, isInSelectionRange, normalizeSelectionRange, resolveCellDisplayContent, resolveCellStyle, toUserLike } from '@alaarab/ogrid-core';
|
|
4
|
-
import { Injectable, Input, Component, ChangeDetectionStrategy, ViewEncapsulation, Output, ViewChild, inject, DestroyRef, signal, computed,
|
|
4
|
+
import { Injectable, Input, Component, ChangeDetectionStrategy, ViewEncapsulation, Output, ViewChild, input, output, viewChild, effect, inject, DestroyRef, signal, computed, NgZone, EventEmitter, Injector, EnvironmentInjector, createComponent } from '@angular/core';
|
|
5
5
|
import { NgTemplateOutlet } from '@angular/common';
|
|
6
6
|
|
|
7
7
|
var __defProp = Object.defineProperty;
|
|
@@ -199,21 +199,9 @@ var FormulaEngineService = class {
|
|
|
199
199
|
return this.engine?.getAuditTrail(col, row) ?? null;
|
|
200
200
|
}
|
|
201
201
|
// --- Private helpers ---
|
|
202
|
-
/**
|
|
203
|
-
* Create a data accessor that bridges grid data to formula coordinates.
|
|
204
|
-
*/
|
|
202
|
+
/** Create a data accessor that bridges grid data to formula coordinates. */
|
|
205
203
|
createAccessor() {
|
|
206
|
-
|
|
207
|
-
const cols = this.flatColumns;
|
|
208
|
-
return {
|
|
209
|
-
getCellValue: (col, row) => {
|
|
210
|
-
if (row < 0 || row >= items.length) return null;
|
|
211
|
-
if (col < 0 || col >= cols.length) return null;
|
|
212
|
-
return getCellValue(items[row], cols[col]);
|
|
213
|
-
},
|
|
214
|
-
getRowCount: () => items.length,
|
|
215
|
-
getColumnCount: () => cols.length
|
|
216
|
-
};
|
|
204
|
+
return createGridDataAccessor(this.items, this.flatColumns);
|
|
217
205
|
}
|
|
218
206
|
};
|
|
219
207
|
FormulaEngineService = __decorateClass([
|
|
@@ -291,14 +279,35 @@ var OGridService = class {
|
|
|
291
279
|
this.formulaFunctions = signal(void 0);
|
|
292
280
|
this.namedRanges = signal(void 0);
|
|
293
281
|
this.sheets = signal(void 0);
|
|
282
|
+
this.sheetDefs = signal(void 0);
|
|
283
|
+
this.activeSheet = signal(void 0);
|
|
284
|
+
this.onSheetChange = signal(void 0);
|
|
285
|
+
this.onSheetAdd = signal(void 0);
|
|
294
286
|
/** Active cell reference string (e.g. 'A1') updated by DataGridTable when cellReferences is enabled. */
|
|
295
287
|
this.activeCellRef = signal(null);
|
|
296
|
-
/**
|
|
288
|
+
/** Active cell coordinates (0-based col/row). */
|
|
289
|
+
this.activeCellCoords = signal(null);
|
|
290
|
+
/** Stable callback passed to DataGridTable to update activeCellRef + coords. */
|
|
297
291
|
this.handleActiveCellChange = (ref) => {
|
|
298
292
|
this.activeCellRef.set(ref);
|
|
293
|
+
if (ref) {
|
|
294
|
+
const m = ref.match(/^([A-Z]+)(\d+)$/);
|
|
295
|
+
if (m) {
|
|
296
|
+
this.activeCellCoords.set({ col: columnLetterToIndex(m[1]), row: parseInt(m[2], 10) - 1 });
|
|
297
|
+
} else {
|
|
298
|
+
this.activeCellCoords.set(null);
|
|
299
|
+
}
|
|
300
|
+
} else {
|
|
301
|
+
this.activeCellCoords.set(null);
|
|
302
|
+
}
|
|
299
303
|
};
|
|
304
|
+
// --- Formula bar state ---
|
|
305
|
+
this.formulaBarEditing = signal(false);
|
|
306
|
+
this.formulaBarEditText = signal("");
|
|
300
307
|
// --- Formula engine ---
|
|
301
308
|
this.formulaService = new FormulaEngineService();
|
|
309
|
+
/** Monotonic counter incremented on formula recalculation — drives cache invalidation. */
|
|
310
|
+
this.formulaVersion = signal(0);
|
|
302
311
|
// Stable formula method references for dataGridProps (avoid per-recompute arrow functions)
|
|
303
312
|
this.getFormulaValueFn = (col, row) => this.formulaService.getValue(col, row);
|
|
304
313
|
this.hasFormulaFn = (col, row) => this.formulaService.hasFormula(col, row);
|
|
@@ -460,6 +469,52 @@ var OGridService = class {
|
|
|
460
469
|
toggle: (panel) => this.sideBarActivePanel.update((p) => p === panel ? null : panel),
|
|
461
470
|
close: () => this.sideBarActivePanel.set(null)
|
|
462
471
|
}));
|
|
472
|
+
// --- Formula bar derived state ---
|
|
473
|
+
/** Display text derived from active cell (formula string or raw value). */
|
|
474
|
+
this.formulaBarDisplayText = computed(() => {
|
|
475
|
+
const coords = this.activeCellCoords();
|
|
476
|
+
if (!coords) return "";
|
|
477
|
+
const getFormula = this.formulaService.enabled() ? (c, r) => this.formulaService.getFormula(c, r) : void 0;
|
|
478
|
+
const items = this.displayItems();
|
|
479
|
+
const cols = this.columns();
|
|
480
|
+
const getRawValue = (c, r) => {
|
|
481
|
+
if (r < 0 || r >= items.length || c < 0 || c >= cols.length) return void 0;
|
|
482
|
+
return getCellValue(items[r], cols[c]);
|
|
483
|
+
};
|
|
484
|
+
return deriveFormulaBarText(coords.col, coords.row, getFormula, getRawValue);
|
|
485
|
+
});
|
|
486
|
+
/** Formula text shown in the bar: edit text when editing, display text otherwise. */
|
|
487
|
+
this.formulaBarText = computed(
|
|
488
|
+
() => this.formulaBarEditing() ? this.formulaBarEditText() : this.formulaBarDisplayText()
|
|
489
|
+
);
|
|
490
|
+
/** References extracted from the current formula text (for highlighting). */
|
|
491
|
+
this.formulaBarReferences = computed(
|
|
492
|
+
() => extractFormulaReferences(this.formulaBarText())
|
|
493
|
+
);
|
|
494
|
+
// Stable formula bar callbacks (avoid new closures per computed)
|
|
495
|
+
this.formulaBarOnInputChangeFn = (text) => {
|
|
496
|
+
this.formulaBarEditText.set(text);
|
|
497
|
+
};
|
|
498
|
+
this.formulaBarOnCommitFn = () => {
|
|
499
|
+
this.commitFormulaBar();
|
|
500
|
+
};
|
|
501
|
+
this.formulaBarOnCancelFn = () => {
|
|
502
|
+
this.cancelFormulaBar();
|
|
503
|
+
};
|
|
504
|
+
this.formulaBarStartEditingFn = () => {
|
|
505
|
+
this.startFormulaBarEditing();
|
|
506
|
+
};
|
|
507
|
+
/** Aggregate formula bar state for template consumption. */
|
|
508
|
+
this.formulaBarState = computed(() => ({
|
|
509
|
+
cellRef: this.activeCellRef(),
|
|
510
|
+
formulaText: this.formulaBarText(),
|
|
511
|
+
isEditing: this.formulaBarEditing(),
|
|
512
|
+
onInputChange: this.formulaBarOnInputChangeFn,
|
|
513
|
+
onCommit: this.formulaBarOnCommitFn,
|
|
514
|
+
onCancel: this.formulaBarOnCancelFn,
|
|
515
|
+
startEditing: this.formulaBarStartEditingFn,
|
|
516
|
+
referencedCells: this.formulaBarReferences()
|
|
517
|
+
}));
|
|
463
518
|
// --- Pre-computed stable callback references for dataGridProps ---
|
|
464
519
|
// These avoid recreating arrow functions on every dataGridProps recomputation.
|
|
465
520
|
this.handleSortFn = (columnKey, direction) => this.handleSort(columnKey, direction);
|
|
@@ -499,10 +554,10 @@ var OGridService = class {
|
|
|
499
554
|
rowSelection: this.rowSelection(),
|
|
500
555
|
selectedRows: this.effectiveSelectedRows(),
|
|
501
556
|
onSelectionChange: this.handleSelectionChangeFn,
|
|
502
|
-
showRowNumbers: this.showRowNumbers() || this.cellReferences(),
|
|
503
|
-
showColumnLetters: !!this.cellReferences(),
|
|
504
|
-
showNameBox: !!this.cellReferences(),
|
|
505
|
-
onActiveCellChange: this.cellReferences() ? this.handleActiveCellChange : void 0,
|
|
557
|
+
showRowNumbers: this.showRowNumbers() || this.cellReferences() || this.formulasEnabled(),
|
|
558
|
+
showColumnLetters: !!(this.cellReferences() || this.formulasEnabled()),
|
|
559
|
+
showNameBox: !!(this.cellReferences() && !this.formulasEnabled()),
|
|
560
|
+
onActiveCellChange: this.cellReferences() || this.formulasEnabled() ? this.handleActiveCellChange : void 0,
|
|
506
561
|
currentPage: this.page(),
|
|
507
562
|
pageSize: this.pageSize(),
|
|
508
563
|
statusBar: this.statusBarConfig(),
|
|
@@ -527,6 +582,8 @@ var OGridService = class {
|
|
|
527
582
|
render: this.emptyState()?.render
|
|
528
583
|
},
|
|
529
584
|
formulas: this.formulasEnabled(),
|
|
585
|
+
formulaVersion: this.formulaVersion(),
|
|
586
|
+
formulaReferences: this.formulaBarReferences().length > 0 ? this.formulaBarReferences() : void 0,
|
|
530
587
|
...this.formulaService.enabled() ? {
|
|
531
588
|
getFormulaValue: this.getFormulaValueFn,
|
|
532
589
|
hasFormula: this.hasFormulaFn,
|
|
@@ -694,11 +751,19 @@ var OGridService = class {
|
|
|
694
751
|
}
|
|
695
752
|
});
|
|
696
753
|
effect(() => {
|
|
754
|
+
this.activeCellCoords();
|
|
755
|
+
this.formulaBarEditing.set(false);
|
|
756
|
+
});
|
|
757
|
+
effect(() => {
|
|
758
|
+
const userRecalcCb = this.onFormulaRecalc();
|
|
697
759
|
this.formulaService.configure({
|
|
698
760
|
formulas: this.formulasEnabled(),
|
|
699
761
|
initialFormulas: this.initialFormulas(),
|
|
700
762
|
formulaFunctions: this.formulaFunctions(),
|
|
701
|
-
onFormulaRecalc:
|
|
763
|
+
onFormulaRecalc: (result) => {
|
|
764
|
+
this.formulaVersion.update((v) => v + 1);
|
|
765
|
+
userRecalcCb?.(result);
|
|
766
|
+
},
|
|
702
767
|
namedRanges: this.namedRanges(),
|
|
703
768
|
sheets: this.sheets()
|
|
704
769
|
});
|
|
@@ -786,6 +851,33 @@ var OGridService = class {
|
|
|
786
851
|
});
|
|
787
852
|
this.onColumnPinned()?.(columnId, pinned);
|
|
788
853
|
}
|
|
854
|
+
// --- Formula bar methods ---
|
|
855
|
+
startFormulaBarEditing() {
|
|
856
|
+
this.formulaBarEditText.set(this.formulaBarDisplayText());
|
|
857
|
+
this.formulaBarEditing.set(true);
|
|
858
|
+
}
|
|
859
|
+
commitFormulaBar() {
|
|
860
|
+
const coords = this.activeCellCoords();
|
|
861
|
+
if (!coords) return;
|
|
862
|
+
const text = this.formulaBarEditText().trim();
|
|
863
|
+
if (text.startsWith("=")) {
|
|
864
|
+
this.formulaService.setFormula(coords.col, coords.row, text);
|
|
865
|
+
this.formulaVersion.update((v) => v + 1);
|
|
866
|
+
} else {
|
|
867
|
+
this.formulaService.setFormula(coords.col, coords.row, null);
|
|
868
|
+
this.onCellValueChanged()?.({
|
|
869
|
+
rowIndex: coords.row,
|
|
870
|
+
columnId: this.columns()[coords.col]?.columnId ?? "",
|
|
871
|
+
oldValue: void 0,
|
|
872
|
+
newValue: text
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
this.formulaBarEditing.set(false);
|
|
876
|
+
}
|
|
877
|
+
cancelFormulaBar() {
|
|
878
|
+
this.formulaBarEditing.set(false);
|
|
879
|
+
this.formulaBarEditText.set("");
|
|
880
|
+
}
|
|
789
881
|
// --- Configure from props ---
|
|
790
882
|
configure(props) {
|
|
791
883
|
this.columnsProp.set(props.columns);
|
|
@@ -847,6 +939,10 @@ var OGridService = class {
|
|
|
847
939
|
if (props.formulaFunctions !== void 0) this.formulaFunctions.set(props.formulaFunctions);
|
|
848
940
|
if (props.namedRanges !== void 0) this.namedRanges.set(props.namedRanges);
|
|
849
941
|
if (props.sheets !== void 0) this.sheets.set(props.sheets);
|
|
942
|
+
if (props.sheetDefs !== void 0) this.sheetDefs.set(props.sheetDefs);
|
|
943
|
+
if (props.activeSheet !== void 0) this.activeSheet.set(props.activeSheet);
|
|
944
|
+
if (props.onSheetChange) this.onSheetChange.set(props.onSheetChange);
|
|
945
|
+
if (props.onSheetAdd) this.onSheetAdd.set(props.onSheetAdd);
|
|
850
946
|
if (props.entityLabelPlural !== void 0) this.entityLabelPlural.set(props.entityLabelPlural);
|
|
851
947
|
if (props.className !== void 0) this.className.set(props.className);
|
|
852
948
|
if (props.layoutMode !== void 0) this.layoutMode.set(props.layoutMode);
|
|
@@ -2277,7 +2373,10 @@ var DataGridStateService = class {
|
|
|
2277
2373
|
getRowId: p?.getRowId ?? ((item) => item["id"]),
|
|
2278
2374
|
editable: p?.editable,
|
|
2279
2375
|
onCellValueChanged: this.wrappedOnCellValueChanged(),
|
|
2280
|
-
isDragging: cellSel ? this.interactionHelper.isDraggingSig() : false
|
|
2376
|
+
isDragging: cellSel ? this.interactionHelper.isDraggingSig() : false,
|
|
2377
|
+
getFormulaValue: p?.getFormulaValue,
|
|
2378
|
+
hasFormula: p?.hasFormula,
|
|
2379
|
+
formulaVersion: p?.formulaVersion
|
|
2281
2380
|
},
|
|
2282
2381
|
statusBarConfig: this.statusBarConfig(),
|
|
2283
2382
|
showEmptyInGrid: this.showEmptyInGrid(),
|
|
@@ -2924,6 +3023,205 @@ SideBarComponent = __decorateClass([
|
|
|
2924
3023
|
`
|
|
2925
3024
|
})
|
|
2926
3025
|
], SideBarComponent);
|
|
3026
|
+
var FormulaBarComponent = class {
|
|
3027
|
+
constructor() {
|
|
3028
|
+
/** Active cell reference (e.g. "A1"). */
|
|
3029
|
+
this.cellRef = input(null);
|
|
3030
|
+
/** Text displayed/edited in the formula input. */
|
|
3031
|
+
this.formulaText = input("");
|
|
3032
|
+
/** Whether the input is in editing mode. */
|
|
3033
|
+
this.isEditing = input(false);
|
|
3034
|
+
/** Called when the user changes the input text. */
|
|
3035
|
+
this.inputChange = output();
|
|
3036
|
+
/** Commit the formula bar value. */
|
|
3037
|
+
this.commit = output();
|
|
3038
|
+
/** Cancel editing. */
|
|
3039
|
+
this.cancel = output();
|
|
3040
|
+
/** Start editing the formula bar. */
|
|
3041
|
+
this.startEditing = output();
|
|
3042
|
+
this.inputEl = viewChild("formulaInput");
|
|
3043
|
+
effect(() => {
|
|
3044
|
+
if (this.isEditing()) {
|
|
3045
|
+
const el = this.inputEl()?.nativeElement;
|
|
3046
|
+
if (el) el.focus();
|
|
3047
|
+
}
|
|
3048
|
+
});
|
|
3049
|
+
}
|
|
3050
|
+
onInput(event) {
|
|
3051
|
+
this.inputChange.emit(event.target.value);
|
|
3052
|
+
}
|
|
3053
|
+
onKeyDown(event) {
|
|
3054
|
+
handleFormulaBarKeyDown(
|
|
3055
|
+
event.key,
|
|
3056
|
+
() => event.preventDefault(),
|
|
3057
|
+
() => this.commit.emit(),
|
|
3058
|
+
() => this.cancel.emit()
|
|
3059
|
+
);
|
|
3060
|
+
}
|
|
3061
|
+
onClick() {
|
|
3062
|
+
if (!this.isEditing()) {
|
|
3063
|
+
this.startEditing.emit();
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
};
|
|
3067
|
+
FormulaBarComponent = __decorateClass([
|
|
3068
|
+
Component({
|
|
3069
|
+
selector: "ogrid-formula-bar",
|
|
3070
|
+
standalone: true,
|
|
3071
|
+
encapsulation: ViewEncapsulation.None,
|
|
3072
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
3073
|
+
styles: [`
|
|
3074
|
+
.ogrid-formula-bar {
|
|
3075
|
+
display: flex;
|
|
3076
|
+
align-items: center;
|
|
3077
|
+
border-bottom: 1px solid var(--ogrid-border, #e0e0e0);
|
|
3078
|
+
background: var(--ogrid-bg, #fff);
|
|
3079
|
+
min-height: 28px;
|
|
3080
|
+
font-size: 13px;
|
|
3081
|
+
}
|
|
3082
|
+
.ogrid-formula-bar__name-box {
|
|
3083
|
+
font-family: monospace;
|
|
3084
|
+
font-size: 12px;
|
|
3085
|
+
font-weight: 500;
|
|
3086
|
+
padding: 2px 8px;
|
|
3087
|
+
border-right: 1px solid var(--ogrid-border, #e0e0e0);
|
|
3088
|
+
background: var(--ogrid-bg, #fff);
|
|
3089
|
+
color: var(--ogrid-fg, #242424);
|
|
3090
|
+
min-width: 52px;
|
|
3091
|
+
text-align: center;
|
|
3092
|
+
line-height: 24px;
|
|
3093
|
+
user-select: none;
|
|
3094
|
+
white-space: nowrap;
|
|
3095
|
+
}
|
|
3096
|
+
.ogrid-formula-bar__fx {
|
|
3097
|
+
padding: 2px 8px;
|
|
3098
|
+
font-style: italic;
|
|
3099
|
+
font-weight: 600;
|
|
3100
|
+
color: var(--ogrid-muted-fg, #888);
|
|
3101
|
+
user-select: none;
|
|
3102
|
+
border-right: 1px solid var(--ogrid-border, #e0e0e0);
|
|
3103
|
+
line-height: 24px;
|
|
3104
|
+
font-size: 12px;
|
|
3105
|
+
}
|
|
3106
|
+
.ogrid-formula-bar__input {
|
|
3107
|
+
flex: 1;
|
|
3108
|
+
border: none;
|
|
3109
|
+
outline: none;
|
|
3110
|
+
padding: 2px 8px;
|
|
3111
|
+
font-family: monospace;
|
|
3112
|
+
font-size: 12px;
|
|
3113
|
+
line-height: 24px;
|
|
3114
|
+
background: transparent;
|
|
3115
|
+
color: var(--ogrid-fg, #242424);
|
|
3116
|
+
min-width: 0;
|
|
3117
|
+
}
|
|
3118
|
+
`],
|
|
3119
|
+
template: `
|
|
3120
|
+
<div class="ogrid-formula-bar" role="toolbar" aria-label="Formula bar">
|
|
3121
|
+
<div class="ogrid-formula-bar__name-box" aria-label="Active cell reference">
|
|
3122
|
+
{{ cellRef() ?? '\u2014' }}
|
|
3123
|
+
</div>
|
|
3124
|
+
<div class="ogrid-formula-bar__fx" aria-hidden="true">fx</div>
|
|
3125
|
+
<input
|
|
3126
|
+
#formulaInput
|
|
3127
|
+
type="text"
|
|
3128
|
+
class="ogrid-formula-bar__input"
|
|
3129
|
+
[value]="formulaText()"
|
|
3130
|
+
[readOnly]="!isEditing()"
|
|
3131
|
+
(input)="onInput($event)"
|
|
3132
|
+
(keydown)="onKeyDown($event)"
|
|
3133
|
+
(click)="onClick()"
|
|
3134
|
+
(dblclick)="onClick()"
|
|
3135
|
+
aria-label="Formula input"
|
|
3136
|
+
[attr.spellcheck]="false"
|
|
3137
|
+
autocomplete="off"
|
|
3138
|
+
/>
|
|
3139
|
+
</div>
|
|
3140
|
+
`
|
|
3141
|
+
})
|
|
3142
|
+
], FormulaBarComponent);
|
|
3143
|
+
var SheetTabsComponent = class {
|
|
3144
|
+
constructor() {
|
|
3145
|
+
this.sheets = input.required();
|
|
3146
|
+
this.activeSheet = input.required();
|
|
3147
|
+
this.showAddButton = input(false);
|
|
3148
|
+
this.sheetChange = output();
|
|
3149
|
+
this.sheetAdd = output();
|
|
3150
|
+
}
|
|
3151
|
+
};
|
|
3152
|
+
SheetTabsComponent = __decorateClass([
|
|
3153
|
+
Component({
|
|
3154
|
+
selector: "ogrid-sheet-tabs",
|
|
3155
|
+
standalone: true,
|
|
3156
|
+
encapsulation: ViewEncapsulation.None,
|
|
3157
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
3158
|
+
styles: [`
|
|
3159
|
+
.ogrid-sheet-tabs {
|
|
3160
|
+
display: flex;
|
|
3161
|
+
align-items: center;
|
|
3162
|
+
border-top: 1px solid var(--ogrid-border, #e0e0e0);
|
|
3163
|
+
background: var(--ogrid-header-bg, #f5f5f5);
|
|
3164
|
+
min-height: 30px;
|
|
3165
|
+
overflow-x: auto;
|
|
3166
|
+
overflow-y: hidden;
|
|
3167
|
+
gap: 0;
|
|
3168
|
+
font-size: 12px;
|
|
3169
|
+
}
|
|
3170
|
+
.ogrid-sheet-tabs__add-btn {
|
|
3171
|
+
background: none;
|
|
3172
|
+
border: none;
|
|
3173
|
+
cursor: pointer;
|
|
3174
|
+
padding: 4px 10px;
|
|
3175
|
+
font-size: 16px;
|
|
3176
|
+
line-height: 22px;
|
|
3177
|
+
color: var(--ogrid-fg-secondary, #666);
|
|
3178
|
+
flex-shrink: 0;
|
|
3179
|
+
}
|
|
3180
|
+
.ogrid-sheet-tabs__tab {
|
|
3181
|
+
background: none;
|
|
3182
|
+
border: none;
|
|
3183
|
+
border-bottom: 2px solid transparent;
|
|
3184
|
+
cursor: pointer;
|
|
3185
|
+
padding: 4px 16px;
|
|
3186
|
+
font-size: 12px;
|
|
3187
|
+
line-height: 22px;
|
|
3188
|
+
color: var(--ogrid-fg, #242424);
|
|
3189
|
+
white-space: nowrap;
|
|
3190
|
+
position: relative;
|
|
3191
|
+
}
|
|
3192
|
+
.ogrid-sheet-tabs__tab--active {
|
|
3193
|
+
font-weight: 600;
|
|
3194
|
+
border-bottom-color: var(--ogrid-primary, #217346);
|
|
3195
|
+
background: var(--ogrid-bg, #fff);
|
|
3196
|
+
}
|
|
3197
|
+
`],
|
|
3198
|
+
template: `
|
|
3199
|
+
<div class="ogrid-sheet-tabs" role="tablist" aria-label="Sheet tabs">
|
|
3200
|
+
@if (showAddButton()) {
|
|
3201
|
+
<button
|
|
3202
|
+
type="button"
|
|
3203
|
+
class="ogrid-sheet-tabs__add-btn"
|
|
3204
|
+
(click)="sheetAdd.emit()"
|
|
3205
|
+
title="Add sheet"
|
|
3206
|
+
aria-label="Add sheet"
|
|
3207
|
+
>+</button>
|
|
3208
|
+
}
|
|
3209
|
+
@for (sheet of sheets(); track sheet.id) {
|
|
3210
|
+
@let isActive = sheet.id === activeSheet();
|
|
3211
|
+
<button
|
|
3212
|
+
type="button"
|
|
3213
|
+
role="tab"
|
|
3214
|
+
class="ogrid-sheet-tabs__tab"
|
|
3215
|
+
[class.ogrid-sheet-tabs__tab--active]="isActive"
|
|
3216
|
+
[attr.aria-selected]="isActive"
|
|
3217
|
+
[style.border-bottom-color]="isActive && sheet.color ? sheet.color : null"
|
|
3218
|
+
(click)="sheetChange.emit(sheet.id)"
|
|
3219
|
+
>{{ sheet.name }}</button>
|
|
3220
|
+
}
|
|
3221
|
+
</div>
|
|
3222
|
+
`
|
|
3223
|
+
})
|
|
3224
|
+
], SheetTabsComponent);
|
|
2927
3225
|
|
|
2928
3226
|
// src/styles/ogrid-theme-vars.ts
|
|
2929
3227
|
var OGRID_THEME_VARS_CSS = `
|
|
@@ -3042,6 +3340,7 @@ var OGridLayoutComponent = class {
|
|
|
3042
3340
|
this.fullScreen = false;
|
|
3043
3341
|
this.showNameBox = false;
|
|
3044
3342
|
this.activeCellRef = null;
|
|
3343
|
+
this.formulaBar = null;
|
|
3045
3344
|
this.isFullScreen = false;
|
|
3046
3345
|
this.borderRadius = GRID_BORDER_RADIUS;
|
|
3047
3346
|
this.escListener = null;
|
|
@@ -3095,13 +3394,28 @@ __decorateClass([
|
|
|
3095
3394
|
__decorateClass([
|
|
3096
3395
|
Input()
|
|
3097
3396
|
], OGridLayoutComponent.prototype, "activeCellRef", 2);
|
|
3397
|
+
__decorateClass([
|
|
3398
|
+
Input()
|
|
3399
|
+
], OGridLayoutComponent.prototype, "formulaBar", 2);
|
|
3400
|
+
__decorateClass([
|
|
3401
|
+
Input()
|
|
3402
|
+
], OGridLayoutComponent.prototype, "sheetDefs", 2);
|
|
3403
|
+
__decorateClass([
|
|
3404
|
+
Input()
|
|
3405
|
+
], OGridLayoutComponent.prototype, "activeSheet", 2);
|
|
3406
|
+
__decorateClass([
|
|
3407
|
+
Input()
|
|
3408
|
+
], OGridLayoutComponent.prototype, "onSheetChange", 2);
|
|
3409
|
+
__decorateClass([
|
|
3410
|
+
Input()
|
|
3411
|
+
], OGridLayoutComponent.prototype, "onSheetAdd", 2);
|
|
3098
3412
|
OGridLayoutComponent = __decorateClass([
|
|
3099
3413
|
Component({
|
|
3100
3414
|
selector: "ogrid-layout",
|
|
3101
3415
|
standalone: true,
|
|
3102
3416
|
encapsulation: ViewEncapsulation.None,
|
|
3103
3417
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
3104
|
-
imports: [SideBarComponent],
|
|
3418
|
+
imports: [SideBarComponent, FormulaBarComponent, SheetTabsComponent],
|
|
3105
3419
|
styles: [OGRID_THEME_VARS_CSS, `
|
|
3106
3420
|
:host { display: block; height: 100%; }
|
|
3107
3421
|
.ogrid-layout-root { display: flex; flex-direction: column; height: 100%; }
|
|
@@ -3203,6 +3517,19 @@ OGridLayoutComponent = __decorateClass([
|
|
|
3203
3517
|
</div>
|
|
3204
3518
|
}
|
|
3205
3519
|
|
|
3520
|
+
<!-- Formula bar (between toolbar and grid) -->
|
|
3521
|
+
@if (formulaBar) {
|
|
3522
|
+
<ogrid-formula-bar
|
|
3523
|
+
[cellRef]="formulaBar.cellRef"
|
|
3524
|
+
[formulaText]="formulaBar.formulaText"
|
|
3525
|
+
[isEditing]="formulaBar.isEditing"
|
|
3526
|
+
(inputChange)="formulaBar.onInputChange($event)"
|
|
3527
|
+
(commit)="formulaBar.onCommit()"
|
|
3528
|
+
(cancel)="formulaBar.onCancel()"
|
|
3529
|
+
(startEditing)="formulaBar.startEditing()"
|
|
3530
|
+
/>
|
|
3531
|
+
}
|
|
3532
|
+
|
|
3206
3533
|
<!-- Grid area -->
|
|
3207
3534
|
<div class="ogrid-layout-grid-area">
|
|
3208
3535
|
@if (sideBar && sideBar.position === 'left') {
|
|
@@ -3216,6 +3543,17 @@ OGridLayoutComponent = __decorateClass([
|
|
|
3216
3543
|
}
|
|
3217
3544
|
</div>
|
|
3218
3545
|
|
|
3546
|
+
<!-- Sheet tabs (between grid and footer) -->
|
|
3547
|
+
@if (sheetDefs && sheetDefs.length > 0 && activeSheet) {
|
|
3548
|
+
<ogrid-sheet-tabs
|
|
3549
|
+
[sheets]="sheetDefs"
|
|
3550
|
+
[activeSheet]="activeSheet"
|
|
3551
|
+
[showAddButton]="!!onSheetAdd"
|
|
3552
|
+
(sheetChange)="onSheetChange?.($event)"
|
|
3553
|
+
(sheetAdd)="onSheetAdd?.()"
|
|
3554
|
+
/>
|
|
3555
|
+
}
|
|
3556
|
+
|
|
3219
3557
|
<!-- Footer strip (pagination) -->
|
|
3220
3558
|
@if (hasPagination) {
|
|
3221
3559
|
<div class="ogrid-layout-footer">
|
|
@@ -3579,6 +3917,94 @@ MarchingAntsOverlayComponent = __decorateClass([
|
|
|
3579
3917
|
`
|
|
3580
3918
|
})
|
|
3581
3919
|
], MarchingAntsOverlayComponent);
|
|
3920
|
+
function measureRef(container, ref, colOffset) {
|
|
3921
|
+
const startCol = ref.col + colOffset;
|
|
3922
|
+
const endCol = (ref.endCol ?? ref.col) + colOffset;
|
|
3923
|
+
const endRow = ref.endRow ?? ref.row;
|
|
3924
|
+
const tl = container.querySelector(
|
|
3925
|
+
`[data-row-index="${ref.row}"][data-col-index="${startCol}"]`
|
|
3926
|
+
);
|
|
3927
|
+
const br = container.querySelector(
|
|
3928
|
+
`[data-row-index="${endRow}"][data-col-index="${endCol}"]`
|
|
3929
|
+
);
|
|
3930
|
+
if (!tl || !br) return null;
|
|
3931
|
+
const cRect = container.getBoundingClientRect();
|
|
3932
|
+
const tlRect = tl.getBoundingClientRect();
|
|
3933
|
+
const brRect = br.getBoundingClientRect();
|
|
3934
|
+
return {
|
|
3935
|
+
top: Math.round(tlRect.top - cRect.top),
|
|
3936
|
+
left: Math.round(tlRect.left - cRect.left),
|
|
3937
|
+
width: Math.round(brRect.right - tlRect.left),
|
|
3938
|
+
height: Math.round(brRect.bottom - tlRect.top),
|
|
3939
|
+
color: FORMULA_REF_COLORS[ref.colorIndex % FORMULA_REF_COLORS.length]
|
|
3940
|
+
};
|
|
3941
|
+
}
|
|
3942
|
+
var FormulaRefOverlayComponent = class {
|
|
3943
|
+
constructor() {
|
|
3944
|
+
/** The positioned container that wraps the table. */
|
|
3945
|
+
this.containerEl = input(null);
|
|
3946
|
+
/** References to highlight. */
|
|
3947
|
+
this.references = input([]);
|
|
3948
|
+
/** Column offset (1 when checkbox/row-number columns are present). */
|
|
3949
|
+
this.colOffset = input(0);
|
|
3950
|
+
this.rects = signal([]);
|
|
3951
|
+
this.rafId = 0;
|
|
3952
|
+
effect(() => {
|
|
3953
|
+
const refs = this.references();
|
|
3954
|
+
const container = this.containerEl();
|
|
3955
|
+
const colOff = this.colOffset();
|
|
3956
|
+
cancelAnimationFrame(this.rafId);
|
|
3957
|
+
if (!container || refs.length === 0) {
|
|
3958
|
+
this.rects.set([]);
|
|
3959
|
+
return;
|
|
3960
|
+
}
|
|
3961
|
+
this.rafId = requestAnimationFrame(() => {
|
|
3962
|
+
const measured = [];
|
|
3963
|
+
for (const ref of refs) {
|
|
3964
|
+
const r = measureRef(container, ref, colOff);
|
|
3965
|
+
if (r) measured.push(r);
|
|
3966
|
+
}
|
|
3967
|
+
this.rects.set(measured);
|
|
3968
|
+
});
|
|
3969
|
+
});
|
|
3970
|
+
}
|
|
3971
|
+
max0(v) {
|
|
3972
|
+
return Math.max(0, v);
|
|
3973
|
+
}
|
|
3974
|
+
};
|
|
3975
|
+
FormulaRefOverlayComponent = __decorateClass([
|
|
3976
|
+
Component({
|
|
3977
|
+
selector: "ogrid-formula-ref-overlay",
|
|
3978
|
+
standalone: true,
|
|
3979
|
+
encapsulation: ViewEncapsulation.None,
|
|
3980
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
3981
|
+
template: `
|
|
3982
|
+
@for (r of rects(); track $index) {
|
|
3983
|
+
<svg
|
|
3984
|
+
[style.position]="'absolute'"
|
|
3985
|
+
[style.top.px]="r.top"
|
|
3986
|
+
[style.left.px]="r.left"
|
|
3987
|
+
[style.width.px]="r.width"
|
|
3988
|
+
[style.height.px]="r.height"
|
|
3989
|
+
[style.pointerEvents]="'none'"
|
|
3990
|
+
[style.zIndex]="3"
|
|
3991
|
+
[style.overflow]="'visible'"
|
|
3992
|
+
aria-hidden="true"
|
|
3993
|
+
>
|
|
3994
|
+
<rect
|
|
3995
|
+
x="1" y="1"
|
|
3996
|
+
[attr.width]="max0(r.width - 2)"
|
|
3997
|
+
[attr.height]="max0(r.height - 2)"
|
|
3998
|
+
fill="none"
|
|
3999
|
+
[attr.stroke]="r.color"
|
|
4000
|
+
stroke-width="2"
|
|
4001
|
+
style="shape-rendering: crispEdges"
|
|
4002
|
+
/>
|
|
4003
|
+
</svg>
|
|
4004
|
+
}
|
|
4005
|
+
`
|
|
4006
|
+
})
|
|
4007
|
+
], FormulaRefOverlayComponent);
|
|
3582
4008
|
var EmptyStateComponent = class {
|
|
3583
4009
|
constructor() {
|
|
3584
4010
|
this.message = void 0;
|
|
@@ -4803,7 +5229,11 @@ var BaseInlineCellEditorComponent = class {
|
|
|
4803
5229
|
}
|
|
4804
5230
|
syncFromInputs() {
|
|
4805
5231
|
const v = this.value;
|
|
4806
|
-
|
|
5232
|
+
let strVal = v != null ? String(v) : "";
|
|
5233
|
+
if (this.editorType === "date" && strVal.match(/^\d{4}-\d{2}-\d{2}/)) {
|
|
5234
|
+
strVal = strVal.substring(0, 10);
|
|
5235
|
+
}
|
|
5236
|
+
this.localValue.set(strVal);
|
|
4807
5237
|
const col = this.column;
|
|
4808
5238
|
if (col?.cellEditorParams?.values) {
|
|
4809
5239
|
const vals = col.cellEditorParams.values;
|
|
@@ -5014,6 +5444,88 @@ __decorateClass([
|
|
|
5014
5444
|
__decorateClass([
|
|
5015
5445
|
ViewChild("richSelectDropdown")
|
|
5016
5446
|
], BaseInlineCellEditorComponent.prototype, "richSelectDropdown", 2);
|
|
5447
|
+
var BaseColumnHeaderMenuComponent = class {
|
|
5448
|
+
constructor() {
|
|
5449
|
+
// Signal-backed inputs so computed() tracks changes reactively
|
|
5450
|
+
this._canPinLeft = signal(true);
|
|
5451
|
+
this._canPinRight = signal(true);
|
|
5452
|
+
this._canUnpin = signal(false);
|
|
5453
|
+
this._currentSort = signal(null);
|
|
5454
|
+
this._isSortable = signal(true);
|
|
5455
|
+
this._isResizable = signal(true);
|
|
5456
|
+
this.handlers = {};
|
|
5457
|
+
this.menuItems = computed(
|
|
5458
|
+
() => getColumnHeaderMenuItems({
|
|
5459
|
+
canPinLeft: this._canPinLeft(),
|
|
5460
|
+
canPinRight: this._canPinRight(),
|
|
5461
|
+
canUnpin: this._canUnpin(),
|
|
5462
|
+
currentSort: this._currentSort(),
|
|
5463
|
+
isSortable: this._isSortable(),
|
|
5464
|
+
isResizable: this._isResizable()
|
|
5465
|
+
})
|
|
5466
|
+
);
|
|
5467
|
+
}
|
|
5468
|
+
set canPinLeft(v) {
|
|
5469
|
+
this._canPinLeft.set(v);
|
|
5470
|
+
}
|
|
5471
|
+
set canPinRight(v) {
|
|
5472
|
+
this._canPinRight.set(v);
|
|
5473
|
+
}
|
|
5474
|
+
set canUnpin(v) {
|
|
5475
|
+
this._canUnpin.set(v);
|
|
5476
|
+
}
|
|
5477
|
+
set currentSort(v) {
|
|
5478
|
+
this._currentSort.set(v);
|
|
5479
|
+
}
|
|
5480
|
+
set isSortable(v) {
|
|
5481
|
+
this._isSortable.set(v);
|
|
5482
|
+
}
|
|
5483
|
+
set isResizable(v) {
|
|
5484
|
+
this._isResizable.set(v);
|
|
5485
|
+
}
|
|
5486
|
+
handleMenuItemClick(itemId) {
|
|
5487
|
+
const h = this.handlers;
|
|
5488
|
+
const actionMap = {
|
|
5489
|
+
pinLeft: h.onPinLeft,
|
|
5490
|
+
pinRight: h.onPinRight,
|
|
5491
|
+
unpin: h.onUnpin,
|
|
5492
|
+
sortAsc: h.onSortAsc,
|
|
5493
|
+
sortDesc: h.onSortDesc,
|
|
5494
|
+
clearSort: h.onClearSort,
|
|
5495
|
+
autosizeThis: h.onAutosizeThis,
|
|
5496
|
+
autosizeAll: h.onAutosizeAll
|
|
5497
|
+
};
|
|
5498
|
+
const action = actionMap[itemId];
|
|
5499
|
+
if (action) {
|
|
5500
|
+
action();
|
|
5501
|
+
h.onClose?.();
|
|
5502
|
+
}
|
|
5503
|
+
}
|
|
5504
|
+
};
|
|
5505
|
+
__decorateClass([
|
|
5506
|
+
Input({ required: true })
|
|
5507
|
+
], BaseColumnHeaderMenuComponent.prototype, "columnId", 2);
|
|
5508
|
+
__decorateClass([
|
|
5509
|
+
Input()
|
|
5510
|
+
], BaseColumnHeaderMenuComponent.prototype, "canPinLeft", 1);
|
|
5511
|
+
__decorateClass([
|
|
5512
|
+
Input()
|
|
5513
|
+
], BaseColumnHeaderMenuComponent.prototype, "canPinRight", 1);
|
|
5514
|
+
__decorateClass([
|
|
5515
|
+
Input()
|
|
5516
|
+
], BaseColumnHeaderMenuComponent.prototype, "canUnpin", 1);
|
|
5517
|
+
__decorateClass([
|
|
5518
|
+
Input()
|
|
5519
|
+
], BaseColumnHeaderMenuComponent.prototype, "currentSort", 1);
|
|
5520
|
+
__decorateClass([
|
|
5521
|
+
Input()
|
|
5522
|
+
], BaseColumnHeaderMenuComponent.prototype, "isSortable", 1);
|
|
5523
|
+
__decorateClass([
|
|
5524
|
+
Input()
|
|
5525
|
+
], BaseColumnHeaderMenuComponent.prototype, "isResizable", 1);
|
|
5526
|
+
__decorateClass([
|
|
5527
|
+
Input()
|
|
5528
|
+
], BaseColumnHeaderMenuComponent.prototype, "handlers", 2);
|
|
5017
5529
|
|
|
5018
5530
|
// src/components/inline-cell-editor-template.ts
|
|
5019
5531
|
var INLINE_CELL_EDITOR_TEMPLATE = `
|
|
@@ -5206,4 +5718,4 @@ __decorateClass([
|
|
|
5206
5718
|
ViewChild("editorContainer")
|
|
5207
5719
|
], BasePopoverCellEditorComponent.prototype, "editorContainerRef", 2);
|
|
5208
5720
|
|
|
5209
|
-
export { BaseColumnChooserComponent, BaseColumnHeaderFilterComponent, BaseDataGridTableComponent, BaseInlineCellEditorComponent, BaseOGridComponent, BasePaginationControlsComponent, BasePopoverCellEditorComponent, ColumnReorderService, DataGridEditingHelper, DataGridInteractionHelper, DataGridLayoutHelper, DataGridStateService, EmptyStateComponent, FormulaEngineService, GridContextMenuComponent, INLINE_CELL_EDITOR_STYLES, INLINE_CELL_EDITOR_TEMPLATE, MarchingAntsOverlayComponent, OGRID_THEME_VARS_CSS, OGridLayoutComponent, OGridService, POPOVER_CELL_EDITOR_OVERLAY_STYLES, POPOVER_CELL_EDITOR_TEMPLATE, SideBarComponent, StatusBarComponent, VirtualScrollService, createDebouncedCallback, createDebouncedSignal, createLatestCallback };
|
|
5721
|
+
export { BaseColumnChooserComponent, BaseColumnHeaderFilterComponent, BaseColumnHeaderMenuComponent, BaseDataGridTableComponent, BaseInlineCellEditorComponent, BaseOGridComponent, BasePaginationControlsComponent, BasePopoverCellEditorComponent, ColumnReorderService, DataGridEditingHelper, DataGridInteractionHelper, DataGridLayoutHelper, DataGridStateService, EmptyStateComponent, FormulaBarComponent, FormulaEngineService, FormulaRefOverlayComponent, GridContextMenuComponent, INLINE_CELL_EDITOR_STYLES, INLINE_CELL_EDITOR_TEMPLATE, MarchingAntsOverlayComponent, OGRID_THEME_VARS_CSS, OGridLayoutComponent, OGridService, POPOVER_CELL_EDITOR_OVERLAY_STYLES, POPOVER_CELL_EDITOR_TEMPLATE, SheetTabsComponent, SideBarComponent, StatusBarComponent, VirtualScrollService, createDebouncedCallback, createDebouncedSignal, createLatestCallback };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type IColumnHeaderMenuItem, type ColumnHeaderMenuHandlers } from '@alaarab/ogrid-core';
|
|
2
|
+
/**
|
|
3
|
+
* Abstract base class containing all shared TypeScript logic for ColumnHeaderMenu components.
|
|
4
|
+
* Framework-specific UI packages extend this with their templates and style overrides.
|
|
5
|
+
*
|
|
6
|
+
* Uses signal-backed @Input setters so that computed() tracks input changes reactively
|
|
7
|
+
* (plain @Input properties are not reactive in Angular signals).
|
|
8
|
+
*
|
|
9
|
+
* Subclasses must:
|
|
10
|
+
* 1. Provide a @Component decorator with template and styles
|
|
11
|
+
* 2. Implement their own menu open/close mechanism (mat-menu, p-menu, or native dropdown)
|
|
12
|
+
*/
|
|
13
|
+
export declare abstract class BaseColumnHeaderMenuComponent {
|
|
14
|
+
columnId: string;
|
|
15
|
+
private readonly _canPinLeft;
|
|
16
|
+
private readonly _canPinRight;
|
|
17
|
+
private readonly _canUnpin;
|
|
18
|
+
private readonly _currentSort;
|
|
19
|
+
private readonly _isSortable;
|
|
20
|
+
private readonly _isResizable;
|
|
21
|
+
set canPinLeft(v: boolean);
|
|
22
|
+
set canPinRight(v: boolean);
|
|
23
|
+
set canUnpin(v: boolean);
|
|
24
|
+
set currentSort(v: 'asc' | 'desc' | null);
|
|
25
|
+
set isSortable(v: boolean);
|
|
26
|
+
set isResizable(v: boolean);
|
|
27
|
+
handlers: Partial<ColumnHeaderMenuHandlers>;
|
|
28
|
+
readonly menuItems: import("@angular/core").Signal<IColumnHeaderMenuItem[]>;
|
|
29
|
+
handleMenuItemClick(itemId: string): void;
|
|
30
|
+
}
|
|
@@ -126,6 +126,9 @@ export declare abstract class BaseDataGridTableComponent<T = unknown> {
|
|
|
126
126
|
editable?: boolean;
|
|
127
127
|
onCellValueChanged?: ((event: import("@alaarab/ogrid-core").ICellValueChangedEvent<T>) => void) | undefined;
|
|
128
128
|
isDragging: boolean;
|
|
129
|
+
getFormulaValue?: (col: number, row: number) => unknown;
|
|
130
|
+
hasFormula?: (col: number, row: number) => boolean;
|
|
131
|
+
formulaVersion?: number;
|
|
129
132
|
}>;
|
|
130
133
|
readonly pinnedColumnsMap: import("@angular/core").Signal<Record<string, "left" | "right">>;
|
|
131
134
|
readonly vsEnabled: import("@angular/core").Signal<boolean>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FormulaBarComponent -- Standalone Angular formula bar component.
|
|
3
|
+
*
|
|
4
|
+
* Layout: [Name Box] [fx] [Formula Input]
|
|
5
|
+
*
|
|
6
|
+
* Uses --ogrid-* CSS variables for theming.
|
|
7
|
+
* Port of React's FormulaBar component.
|
|
8
|
+
*/
|
|
9
|
+
export declare class FormulaBarComponent {
|
|
10
|
+
/** Active cell reference (e.g. "A1"). */
|
|
11
|
+
readonly cellRef: import("@angular/core").InputSignal<string | null>;
|
|
12
|
+
/** Text displayed/edited in the formula input. */
|
|
13
|
+
readonly formulaText: import("@angular/core").InputSignal<string>;
|
|
14
|
+
/** Whether the input is in editing mode. */
|
|
15
|
+
readonly isEditing: import("@angular/core").InputSignal<boolean>;
|
|
16
|
+
/** Called when the user changes the input text. */
|
|
17
|
+
readonly inputChange: import("@angular/core").OutputEmitterRef<string>;
|
|
18
|
+
/** Commit the formula bar value. */
|
|
19
|
+
readonly commit: import("@angular/core").OutputEmitterRef<void>;
|
|
20
|
+
/** Cancel editing. */
|
|
21
|
+
readonly cancel: import("@angular/core").OutputEmitterRef<void>;
|
|
22
|
+
/** Start editing the formula bar. */
|
|
23
|
+
readonly startEditing: import("@angular/core").OutputEmitterRef<void>;
|
|
24
|
+
private readonly inputEl;
|
|
25
|
+
constructor();
|
|
26
|
+
onInput(event: Event): void;
|
|
27
|
+
onKeyDown(event: KeyboardEvent): void;
|
|
28
|
+
onClick(): void;
|
|
29
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FormulaRefOverlayComponent -- Renders colored border overlays on cells
|
|
3
|
+
* referenced by the active formula, like Excel's reference highlighting.
|
|
4
|
+
*
|
|
5
|
+
* Port of React's FormulaRefOverlay component.
|
|
6
|
+
*/
|
|
7
|
+
import { type FormulaReference } from '@alaarab/ogrid-core';
|
|
8
|
+
interface RefRect {
|
|
9
|
+
top: number;
|
|
10
|
+
left: number;
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
color: string;
|
|
14
|
+
}
|
|
15
|
+
export declare class FormulaRefOverlayComponent {
|
|
16
|
+
/** The positioned container that wraps the table. */
|
|
17
|
+
readonly containerEl: import("@angular/core").InputSignal<HTMLElement | null>;
|
|
18
|
+
/** References to highlight. */
|
|
19
|
+
readonly references: import("@angular/core").InputSignal<FormulaReference[]>;
|
|
20
|
+
/** Column offset (1 when checkbox/row-number columns are present). */
|
|
21
|
+
readonly colOffset: import("@angular/core").InputSignal<number>;
|
|
22
|
+
readonly rects: import("@angular/core").WritableSignal<RefRect[]>;
|
|
23
|
+
private rafId;
|
|
24
|
+
constructor();
|
|
25
|
+
max0(v: number): number;
|
|
26
|
+
}
|
|
27
|
+
export {};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { SideBarProps } from './sidebar.component';
|
|
2
|
+
import type { OGridFormulaBarState } from '../services/ogrid.service';
|
|
3
|
+
import type { ISheetDef } from '@alaarab/ogrid-core';
|
|
2
4
|
export declare class OGridLayoutComponent {
|
|
3
5
|
className?: string;
|
|
4
6
|
hasToolbar: boolean;
|
|
@@ -8,6 +10,11 @@ export declare class OGridLayoutComponent {
|
|
|
8
10
|
fullScreen: boolean;
|
|
9
11
|
showNameBox: boolean;
|
|
10
12
|
activeCellRef: string | null;
|
|
13
|
+
formulaBar: OGridFormulaBarState | null;
|
|
14
|
+
sheetDefs: ISheetDef[] | undefined;
|
|
15
|
+
activeSheet: string | undefined;
|
|
16
|
+
onSheetChange: ((sheetId: string) => void) | undefined;
|
|
17
|
+
onSheetAdd: (() => void) | undefined;
|
|
11
18
|
isFullScreen: boolean;
|
|
12
19
|
readonly borderRadius = 6;
|
|
13
20
|
private escListener;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SheetTabsComponent -- Excel-style sheet tab bar at the bottom of the grid.
|
|
3
|
+
*
|
|
4
|
+
* Layout: [+] [Sheet1] [Sheet2] [Sheet3]
|
|
5
|
+
*
|
|
6
|
+
* Uses --ogrid-* CSS variables for theming.
|
|
7
|
+
* Port of React's SheetTabs component.
|
|
8
|
+
*/
|
|
9
|
+
import type { ISheetDef } from '@alaarab/ogrid-core';
|
|
10
|
+
export declare class SheetTabsComponent {
|
|
11
|
+
readonly sheets: import("@angular/core").InputSignal<ISheetDef[]>;
|
|
12
|
+
readonly activeSheet: import("@angular/core").InputSignal<string>;
|
|
13
|
+
readonly showAddButton: import("@angular/core").InputSignal<boolean>;
|
|
14
|
+
readonly sheetChange: import("@angular/core").OutputEmitterRef<string>;
|
|
15
|
+
readonly sheetAdd: import("@angular/core").OutputEmitterRef<void>;
|
|
16
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export type { IOGridProps, IOGridClientProps, IOGridServerProps, IOGridDataGridP
|
|
|
5
5
|
export type { ColumnFilterType, IColumnFilterDef, IColumnMeta, ICellValueChangedEvent, CellEditorParams, IValueParserParams, IDateFilterValue, HeaderCell, HeaderRow, RowId, UserLike, UserLikeInput, FilterValue, IFilters, IFetchParams, IPageResult, IDataSource, IGridColumnState, IOGridApi, RowSelectionMode, IRowSelectionChangeEvent, StatusBarPanel, IStatusBarProps, IActiveCell, ISelectionRange, SideBarPanelId, ISideBarDef, } from './types';
|
|
6
6
|
export { toUserLike, isInSelectionRange, normalizeSelectionRange } from './types';
|
|
7
7
|
export { OGridService } from './services/ogrid.service';
|
|
8
|
-
export type { ColumnChooserPlacement, OGridPagination, OGridColumnChooser, OGridFilters, OGridSideBarState, } from './services/ogrid.service';
|
|
8
|
+
export type { ColumnChooserPlacement, OGridPagination, OGridColumnChooser, OGridFilters, OGridSideBarState, OGridFormulaBarState, } from './services/ogrid.service';
|
|
9
9
|
export { DataGridStateService } from './services/datagrid-state.service';
|
|
10
10
|
export type { DataGridLayoutState, DataGridRowSelectionState, DataGridEditingState, DataGridCellInteractionState, DataGridContextMenuState, DataGridViewModelState, DataGridPinningState, DataGridStateResult, } from './services/datagrid-state.service';
|
|
11
11
|
export { DataGridLayoutHelper } from './services/datagrid-layout.service';
|
|
@@ -21,6 +21,9 @@ export { GridContextMenuComponent } from './components/grid-context-menu.compone
|
|
|
21
21
|
export { SideBarComponent } from './components/sidebar.component';
|
|
22
22
|
export type { SideBarProps, SideBarFilterColumn } from './components/sidebar.component';
|
|
23
23
|
export { MarchingAntsOverlayComponent } from './components/marching-ants-overlay.component';
|
|
24
|
+
export { FormulaBarComponent } from './components/formula-bar.component';
|
|
25
|
+
export { SheetTabsComponent } from './components/sheet-tabs.component';
|
|
26
|
+
export { FormulaRefOverlayComponent } from './components/formula-ref-overlay.component';
|
|
24
27
|
export { EmptyStateComponent } from './components/empty-state.component';
|
|
25
28
|
export { BaseOGridComponent } from './components/base-ogrid.component';
|
|
26
29
|
export { BaseDataGridTableComponent } from './components/base-datagrid-table.component';
|
|
@@ -30,6 +33,7 @@ export { BaseColumnChooserComponent } from './components/base-column-chooser.com
|
|
|
30
33
|
export type { IColumnChooserProps } from './components/base-column-chooser.component';
|
|
31
34
|
export { BasePaginationControlsComponent } from './components/base-pagination-controls.component';
|
|
32
35
|
export { BaseInlineCellEditorComponent } from './components/base-inline-cell-editor.component';
|
|
36
|
+
export { BaseColumnHeaderMenuComponent } from './components/base-column-header-menu.component';
|
|
33
37
|
export { INLINE_CELL_EDITOR_TEMPLATE, INLINE_CELL_EDITOR_STYLES } from './components/inline-cell-editor-template';
|
|
34
38
|
export { BasePopoverCellEditorComponent, POPOVER_CELL_EDITOR_TEMPLATE, POPOVER_CELL_EDITOR_OVERLAY_STYLES } from './components/base-popover-cell-editor.component';
|
|
35
39
|
export { OGRID_THEME_VARS_CSS } from './styles/ogrid-theme-vars';
|
|
@@ -119,6 +119,9 @@ export interface DataGridViewModelState<T> {
|
|
|
119
119
|
editable?: boolean;
|
|
120
120
|
onCellValueChanged?: (event: ICellValueChangedEvent<T>) => void;
|
|
121
121
|
isDragging: boolean;
|
|
122
|
+
getFormulaValue?: (col: number, row: number) => unknown;
|
|
123
|
+
hasFormula?: (col: number, row: number) => boolean;
|
|
124
|
+
formulaVersion?: number;
|
|
122
125
|
};
|
|
123
126
|
statusBarConfig: IStatusBarProps | null;
|
|
124
127
|
showEmptyInGrid: boolean;
|
|
@@ -126,8 +126,6 @@ export declare class FormulaEngineService<T = unknown> {
|
|
|
126
126
|
* Get full audit trail for a cell.
|
|
127
127
|
*/
|
|
128
128
|
getAuditTrail(col: number, row: number): IAuditTrail | null;
|
|
129
|
-
/**
|
|
130
|
-
* Create a data accessor that bridges grid data to formula coordinates.
|
|
131
|
-
*/
|
|
129
|
+
/** Create a data accessor that bridges grid data to formula coordinates. */
|
|
132
130
|
private createAccessor;
|
|
133
131
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FormulaReference } from '@alaarab/ogrid-core';
|
|
1
2
|
import type { RowId, IOGridApi, IFilters, FilterValue, IRowSelectionChangeEvent, IStatusBarProps, IColumnDefinition, IDataSource, ISideBarDef, IVirtualScrollConfig, SideBarPanelId, IFormulaFunction, IRecalcResult, IGridDataAccessor } from '../types';
|
|
2
3
|
import type { IOGridProps, IOGridDataGridProps } from '../types';
|
|
3
4
|
import type { IColumnDef, IColumnGroupDef, ICellValueChangedEvent } from '../types';
|
|
@@ -26,6 +27,17 @@ export interface OGridFilters {
|
|
|
26
27
|
hasActiveFilters: boolean;
|
|
27
28
|
setFilters: (f: IFilters) => void;
|
|
28
29
|
}
|
|
30
|
+
/** Formula bar state and handlers. */
|
|
31
|
+
export interface OGridFormulaBarState {
|
|
32
|
+
cellRef: string | null;
|
|
33
|
+
formulaText: string;
|
|
34
|
+
isEditing: boolean;
|
|
35
|
+
onInputChange: (text: string) => void;
|
|
36
|
+
onCommit: () => void;
|
|
37
|
+
onCancel: () => void;
|
|
38
|
+
startEditing: () => void;
|
|
39
|
+
referencedCells: FormulaReference[];
|
|
40
|
+
}
|
|
29
41
|
/** Side bar state. */
|
|
30
42
|
export interface OGridSideBarState {
|
|
31
43
|
isEnabled: boolean;
|
|
@@ -121,11 +133,24 @@ export declare class OGridService<T> {
|
|
|
121
133
|
readonly formulaFunctions: import("@angular/core").WritableSignal<Record<string, IFormulaFunction> | undefined>;
|
|
122
134
|
readonly namedRanges: import("@angular/core").WritableSignal<Record<string, string> | undefined>;
|
|
123
135
|
readonly sheets: import("@angular/core").WritableSignal<Record<string, IGridDataAccessor> | undefined>;
|
|
136
|
+
readonly sheetDefs: import("@angular/core").WritableSignal<import("@alaarab/ogrid-core").ISheetDef[] | undefined>;
|
|
137
|
+
readonly activeSheet: import("@angular/core").WritableSignal<string | undefined>;
|
|
138
|
+
readonly onSheetChange: import("@angular/core").WritableSignal<((sheetId: string) => void) | undefined>;
|
|
139
|
+
readonly onSheetAdd: import("@angular/core").WritableSignal<(() => void) | undefined>;
|
|
124
140
|
/** Active cell reference string (e.g. 'A1') updated by DataGridTable when cellReferences is enabled. */
|
|
125
141
|
readonly activeCellRef: import("@angular/core").WritableSignal<string | null>;
|
|
126
|
-
/**
|
|
142
|
+
/** Active cell coordinates (0-based col/row). */
|
|
143
|
+
readonly activeCellCoords: import("@angular/core").WritableSignal<{
|
|
144
|
+
col: number;
|
|
145
|
+
row: number;
|
|
146
|
+
} | null>;
|
|
147
|
+
/** Stable callback passed to DataGridTable to update activeCellRef + coords. */
|
|
127
148
|
private readonly handleActiveCellChange;
|
|
149
|
+
private readonly formulaBarEditing;
|
|
150
|
+
private readonly formulaBarEditText;
|
|
128
151
|
private readonly formulaService;
|
|
152
|
+
/** Monotonic counter incremented on formula recalculation — drives cache invalidation. */
|
|
153
|
+
readonly formulaVersion: import("@angular/core").WritableSignal<number>;
|
|
129
154
|
private readonly getFormulaValueFn;
|
|
130
155
|
private readonly hasFormulaFn;
|
|
131
156
|
private readonly getFormulaFn;
|
|
@@ -204,6 +229,18 @@ export declare class OGridService<T> {
|
|
|
204
229
|
filterType: "text" | "multiSelect" | "people" | "date";
|
|
205
230
|
}[]>;
|
|
206
231
|
readonly sideBarState: import("@angular/core").Signal<OGridSideBarState>;
|
|
232
|
+
/** Display text derived from active cell (formula string or raw value). */
|
|
233
|
+
private readonly formulaBarDisplayText;
|
|
234
|
+
/** Formula text shown in the bar: edit text when editing, display text otherwise. */
|
|
235
|
+
readonly formulaBarText: import("@angular/core").Signal<string>;
|
|
236
|
+
/** References extracted from the current formula text (for highlighting). */
|
|
237
|
+
readonly formulaBarReferences: import("@angular/core").Signal<FormulaReference[]>;
|
|
238
|
+
private readonly formulaBarOnInputChangeFn;
|
|
239
|
+
private readonly formulaBarOnCommitFn;
|
|
240
|
+
private readonly formulaBarOnCancelFn;
|
|
241
|
+
private readonly formulaBarStartEditingFn;
|
|
242
|
+
/** Aggregate formula bar state for template consumption. */
|
|
243
|
+
readonly formulaBarState: import("@angular/core").Signal<OGridFormulaBarState>;
|
|
207
244
|
private readonly handleSortFn;
|
|
208
245
|
private readonly handleColumnResizedFn;
|
|
209
246
|
private readonly handleColumnPinnedFn;
|
|
@@ -233,6 +270,9 @@ export declare class OGridService<T> {
|
|
|
233
270
|
handleSelectionChange(event: IRowSelectionChangeEvent<T>): void;
|
|
234
271
|
handleColumnResized(columnId: string, width: number): void;
|
|
235
272
|
handleColumnPinned(columnId: string, pinned: 'left' | 'right' | null): void;
|
|
273
|
+
private startFormulaBarEditing;
|
|
274
|
+
private commitFormulaBar;
|
|
275
|
+
private cancelFormulaBar;
|
|
236
276
|
configure(props: IOGridProps<T>): void;
|
|
237
277
|
/**
|
|
238
278
|
* Pin a column to the left or right edge.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { TemplateRef } from '@angular/core';
|
|
2
2
|
import type { IColumnDef, IColumnGroupDef, ICellValueChangedEvent } from './columnTypes';
|
|
3
|
-
export type { RowId, UserLike, UserLikeInput, FilterValue, IFilters, IFetchParams, IPageResult, IDataSource, IGridColumnState, RowSelectionMode, IRowSelectionChangeEvent, StatusBarPanel, IStatusBarProps, IActiveCell, ISelectionRange, SideBarPanelId, ISideBarDef, IVirtualScrollConfig, IOGridApi, IFormulaFunction, IRecalcResult, IGridDataAccessor, IAuditEntry, IAuditTrail, } from '@alaarab/ogrid-core';
|
|
3
|
+
export type { RowId, UserLike, UserLikeInput, FilterValue, IFilters, IFetchParams, IPageResult, IDataSource, IGridColumnState, RowSelectionMode, IRowSelectionChangeEvent, StatusBarPanel, IStatusBarProps, IActiveCell, ISelectionRange, SideBarPanelId, ISideBarDef, IVirtualScrollConfig, IOGridApi, IFormulaFunction, IRecalcResult, IGridDataAccessor, IAuditEntry, IAuditTrail, ISheetDef, FormulaReference, } from '@alaarab/ogrid-core';
|
|
4
4
|
export { toUserLike, isInSelectionRange, normalizeSelectionRange } from '@alaarab/ogrid-core';
|
|
5
|
-
import type { RowId, UserLike, IFilters, FilterValue, RowSelectionMode, IRowSelectionChangeEvent, IStatusBarProps, IDataSource, ISideBarDef, IVirtualScrollConfig, IFormulaFunction, IRecalcResult, IGridDataAccessor, IAuditEntry, IAuditTrail } from '@alaarab/ogrid-core';
|
|
5
|
+
import type { RowId, UserLike, IFilters, FilterValue, RowSelectionMode, IRowSelectionChangeEvent, IStatusBarProps, IDataSource, ISideBarDef, IVirtualScrollConfig, IFormulaFunction, IRecalcResult, IGridDataAccessor, IAuditEntry, IAuditTrail, ISheetDef, FormulaReference } from '@alaarab/ogrid-core';
|
|
6
6
|
/** Base props shared by both client-side and server-side OGrid modes. */
|
|
7
7
|
interface IOGridBaseProps<T> {
|
|
8
8
|
columns: (IColumnDef<T> | IColumnGroupDef<T>)[];
|
|
@@ -90,6 +90,14 @@ interface IOGridBaseProps<T> {
|
|
|
90
90
|
namedRanges?: Record<string, string>;
|
|
91
91
|
/** Sheet accessors for cross-sheet formula references (e.g. { Sheet2: accessor }). */
|
|
92
92
|
sheets?: Record<string, IGridDataAccessor>;
|
|
93
|
+
/** Sheet definitions for the tab bar at grid bottom. */
|
|
94
|
+
sheetDefs?: ISheetDef[];
|
|
95
|
+
/** Active sheet ID (controlled). */
|
|
96
|
+
activeSheet?: string;
|
|
97
|
+
/** Called when user clicks a sheet tab. */
|
|
98
|
+
onSheetChange?: (sheetId: string) => void;
|
|
99
|
+
/** Called when user clicks the "+" add sheet button. */
|
|
100
|
+
onSheetAdd?: () => void;
|
|
93
101
|
'aria-label'?: string;
|
|
94
102
|
'aria-labelledby'?: string;
|
|
95
103
|
}
|
|
@@ -186,4 +194,8 @@ export interface IOGridDataGridProps<T> {
|
|
|
186
194
|
getDependents?: (col: number, row: number) => IAuditEntry[];
|
|
187
195
|
/** Get full audit trail for a cell. */
|
|
188
196
|
getAuditTrail?: (col: number, row: number) => IAuditTrail | null;
|
|
197
|
+
/** Monotonic counter incremented on each formula recalculation — used for cache invalidation. */
|
|
198
|
+
formulaVersion?: number;
|
|
199
|
+
/** Cell references to highlight (from active formula in formula bar). */
|
|
200
|
+
formulaReferences?: FormulaReference[];
|
|
189
201
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export type { ColumnFilterType, IColumnFilterDef, IColumnMeta, IColumnDef, IColumnGroupDef, IColumnDefinition, ICellValueChangedEvent, ICellEditorProps, CellEditorParams, IValueParserParams, IDateFilterValue, HeaderCell, HeaderRow, } from './columnTypes';
|
|
2
|
-
export type { RowId, UserLike, UserLikeInput, FilterValue, IFilters, IFetchParams, IPageResult, IDataSource, IGridColumnState, IOGridApi, IOGridProps, IOGridClientProps, IOGridServerProps, IOGridDataGridProps, RowSelectionMode, IRowSelectionChangeEvent, StatusBarPanel, IStatusBarProps, IActiveCell, ISelectionRange, SideBarPanelId, ISideBarDef, IVirtualScrollConfig, IFormulaFunction, IRecalcResult, IGridDataAccessor, IAuditEntry, IAuditTrail, } from './dataGridTypes';
|
|
2
|
+
export type { RowId, UserLike, UserLikeInput, FilterValue, IFilters, IFetchParams, IPageResult, IDataSource, IGridColumnState, IOGridApi, IOGridProps, IOGridClientProps, IOGridServerProps, IOGridDataGridProps, RowSelectionMode, IRowSelectionChangeEvent, StatusBarPanel, IStatusBarProps, IActiveCell, ISelectionRange, SideBarPanelId, ISideBarDef, IVirtualScrollConfig, IFormulaFunction, IRecalcResult, IGridDataAccessor, IAuditEntry, IAuditTrail, ISheetDef, FormulaReference, } from './dataGridTypes';
|
|
3
3
|
export { toUserLike, isInSelectionRange, normalizeSelectionRange } from './dataGridTypes';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alaarab/ogrid-angular",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "OGrid Angular – Angular services, signals, and headless components for OGrid data grids.",
|
|
5
5
|
"main": "dist/esm/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"node": ">=18"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@alaarab/ogrid-core": "2.
|
|
38
|
+
"@alaarab/ogrid-core": "2.4.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"@angular/core": "^21.0.0",
|