@alaarab/ogrid-vue 2.3.0 → 2.4.1
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 +408 -57
- package/dist/types/components/FormulaBar.d.ts +52 -0
- package/dist/types/components/FormulaRefOverlay.d.ts +39 -0
- package/dist/types/components/SheetTabs.d.ts +45 -0
- package/dist/types/composables/index.d.ts +2 -0
- package/dist/types/composables/useFormulaBar.d.ts +44 -0
- package/dist/types/composables/useOGrid.d.ts +4 -0
- package/dist/types/index.d.ts +5 -2
- 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,4 +1,4 @@
|
|
|
1
|
-
import { injectGlobalStyles, Z_INDEX, getStatusBarParts, measureRange, flattenColumns, getMultiSelectFilterFields, deriveFilterOptionsFromData, processClientSideData, processClientSideDataAsync, validateColumns, validateRowIds, computeRowSelectionState, buildCellIndex, UndoRedoStack, CHECKBOX_COLUMN_WIDTH, DEFAULT_MIN_COLUMN_WIDTH, CELL_PADDING, computeAggregations, getDataGridStatusBarConfig, validateVirtualScrollConfig, computeVisibleRange, computeTotalHeight, computeVisibleColumnRange, partitionColumnsForVirtualization, formatCellReference, buildHeaderRows, indexToColumnLetter, ROW_NUMBER_COLUMN_WIDTH, getHeaderFilterConfig, getCellRenderDescriptor, buildInlineEditorProps, buildPopoverEditorProps, resolveCellDisplayContent, resolveCellStyle, rangesEqual, normalizeSelectionRange, formatSelectionAsTsv, parseTsvClipboard, applyPastedValues, applyCutClear, measureColumnContentWidth, getPinStateForColumn, parseValue, applyFillValues, applyCellDeletion, computeTabNavigation, computeArrowNavigation, computeNextSortState, mergeFilter, applyRangeRowSelection, getScrollTopForRow, FormulaEngine,
|
|
1
|
+
import { injectGlobalStyles, Z_INDEX, getStatusBarParts, FORMULA_BAR_STYLES, handleFormulaBarKeyDown, measureRange, FORMULA_REF_COLORS, deriveFormulaBarText, extractFormulaReferences, flattenColumns, getMultiSelectFilterFields, deriveFilterOptionsFromData, processClientSideData, processClientSideDataAsync, validateColumns, validateRowIds, computeRowSelectionState, buildCellIndex, UndoRedoStack, CHECKBOX_COLUMN_WIDTH, DEFAULT_MIN_COLUMN_WIDTH, CELL_PADDING, computeAggregations, getDataGridStatusBarConfig, validateVirtualScrollConfig, computeVisibleRange, computeTotalHeight, computeVisibleColumnRange, partitionColumnsForVirtualization, formatCellReference, buildHeaderRows, indexToColumnLetter, ROW_NUMBER_COLUMN_ID, ROW_NUMBER_COLUMN_WIDTH, getHeaderFilterConfig, getCellRenderDescriptor, buildInlineEditorProps, buildPopoverEditorProps, resolveCellDisplayContent, resolveCellStyle, rangesEqual, normalizeSelectionRange, formatSelectionAsTsv, parseTsvClipboard, applyPastedValues, applyCutClear, measureColumnContentWidth, getPinStateForColumn, parseValue, applyFillValues, processFormulaBarCommit, applyCellDeletion, computeTabNavigation, computeArrowNavigation, computeNextSortState, mergeFilter, columnLetterToIndex, getCellValue, applyRangeRowSelection, getScrollTopForRow, FormulaEngine, calculateDropTarget, reorderColumnArray, ROW_NUMBER_COLUMN_MIN_WIDTH, createGridDataAccessor, computeAutoScrollSpeed } from '@alaarab/ogrid-core';
|
|
2
2
|
export * from '@alaarab/ogrid-core';
|
|
3
3
|
export { buildInlineEditorProps, buildPopoverEditorProps, getCellRenderDescriptor, getHeaderFilterConfig, isInSelectionRange, normalizeSelectionRange, resolveCellDisplayContent, resolveCellStyle, toUserLike } from '@alaarab/ogrid-core';
|
|
4
4
|
import { defineComponent, ref, computed, onMounted, watch, toValue, onUnmounted, h, shallowRef, triggerRef, nextTick, Teleport, isRef, isReadonly, unref, customRef } from 'vue';
|
|
@@ -173,6 +173,211 @@ var StatusBar = defineComponent({
|
|
|
173
173
|
};
|
|
174
174
|
}
|
|
175
175
|
});
|
|
176
|
+
var FormulaBar = defineComponent({
|
|
177
|
+
name: "FormulaBar",
|
|
178
|
+
props: {
|
|
179
|
+
cellRef: { type: [String, null], default: null },
|
|
180
|
+
formulaText: { type: String, required: true },
|
|
181
|
+
isEditing: { type: Boolean, required: true }
|
|
182
|
+
},
|
|
183
|
+
emits: ["inputChange", "commit", "cancel", "startEditing"],
|
|
184
|
+
setup(props, { emit }) {
|
|
185
|
+
const inputRef = ref(null);
|
|
186
|
+
watch(() => props.isEditing, (editing) => {
|
|
187
|
+
if (editing && inputRef.value) {
|
|
188
|
+
inputRef.value.focus();
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
return () => h("div", { style: FORMULA_BAR_STYLES.bar, role: "toolbar", "aria-label": "Formula bar" }, [
|
|
192
|
+
h(
|
|
193
|
+
"div",
|
|
194
|
+
{ style: FORMULA_BAR_STYLES.nameBox, "aria-label": "Active cell reference" },
|
|
195
|
+
props.cellRef ?? "\u2014"
|
|
196
|
+
),
|
|
197
|
+
h("div", { style: FORMULA_BAR_STYLES.fxLabel, "aria-hidden": "true" }, "fx"),
|
|
198
|
+
h("input", {
|
|
199
|
+
ref: inputRef,
|
|
200
|
+
type: "text",
|
|
201
|
+
style: FORMULA_BAR_STYLES.input,
|
|
202
|
+
value: props.formulaText,
|
|
203
|
+
readonly: !props.isEditing,
|
|
204
|
+
onInput: (e) => emit("inputChange", e.target.value),
|
|
205
|
+
onKeydown: (e) => handleFormulaBarKeyDown(e.key, () => e.preventDefault(), () => emit("commit"), () => emit("cancel")),
|
|
206
|
+
onClick: () => {
|
|
207
|
+
if (!props.isEditing) emit("startEditing");
|
|
208
|
+
},
|
|
209
|
+
onDblclick: () => {
|
|
210
|
+
if (!props.isEditing) emit("startEditing");
|
|
211
|
+
},
|
|
212
|
+
"aria-label": "Formula input",
|
|
213
|
+
spellcheck: false,
|
|
214
|
+
autocomplete: "off"
|
|
215
|
+
})
|
|
216
|
+
]);
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
var barStyle = {
|
|
220
|
+
display: "flex",
|
|
221
|
+
alignItems: "center",
|
|
222
|
+
borderTop: "1px solid var(--ogrid-border, #e0e0e0)",
|
|
223
|
+
background: "var(--ogrid-header-bg, #f5f5f5)",
|
|
224
|
+
minHeight: "30px",
|
|
225
|
+
overflowX: "auto",
|
|
226
|
+
overflowY: "hidden",
|
|
227
|
+
gap: "0",
|
|
228
|
+
fontSize: "12px"
|
|
229
|
+
};
|
|
230
|
+
var addBtnStyle = {
|
|
231
|
+
background: "none",
|
|
232
|
+
border: "none",
|
|
233
|
+
cursor: "pointer",
|
|
234
|
+
padding: "4px 10px",
|
|
235
|
+
fontSize: "16px",
|
|
236
|
+
lineHeight: "22px",
|
|
237
|
+
color: "var(--ogrid-fg-secondary, #666)",
|
|
238
|
+
flexShrink: 0
|
|
239
|
+
};
|
|
240
|
+
var tabBaseStyle = {
|
|
241
|
+
background: "none",
|
|
242
|
+
border: "none",
|
|
243
|
+
borderBottom: "2px solid transparent",
|
|
244
|
+
cursor: "pointer",
|
|
245
|
+
padding: "4px 16px",
|
|
246
|
+
fontSize: "12px",
|
|
247
|
+
lineHeight: "22px",
|
|
248
|
+
color: "var(--ogrid-fg, #242424)",
|
|
249
|
+
whiteSpace: "nowrap",
|
|
250
|
+
position: "relative"
|
|
251
|
+
};
|
|
252
|
+
var activeTabStyle = {
|
|
253
|
+
...tabBaseStyle,
|
|
254
|
+
fontWeight: 600,
|
|
255
|
+
borderBottomColor: "var(--ogrid-primary, #217346)",
|
|
256
|
+
background: "var(--ogrid-bg, #fff)"
|
|
257
|
+
};
|
|
258
|
+
var SheetTabs = defineComponent({
|
|
259
|
+
name: "SheetTabs",
|
|
260
|
+
props: {
|
|
261
|
+
sheets: { type: Array, required: true },
|
|
262
|
+
activeSheet: { type: String, required: true },
|
|
263
|
+
showAddButton: { type: Boolean, default: false }
|
|
264
|
+
},
|
|
265
|
+
emits: ["sheetChange", "sheetAdd"],
|
|
266
|
+
setup(props, { emit }) {
|
|
267
|
+
return () => h("div", { style: barStyle, role: "tablist", "aria-label": "Sheet tabs" }, [
|
|
268
|
+
props.showAddButton ? h("button", {
|
|
269
|
+
type: "button",
|
|
270
|
+
style: addBtnStyle,
|
|
271
|
+
onClick: () => emit("sheetAdd"),
|
|
272
|
+
title: "Add sheet",
|
|
273
|
+
"aria-label": "Add sheet"
|
|
274
|
+
}, "+") : null,
|
|
275
|
+
...props.sheets.map((sheet) => {
|
|
276
|
+
const isActive = sheet.id === props.activeSheet;
|
|
277
|
+
const base = isActive ? activeTabStyle : tabBaseStyle;
|
|
278
|
+
const style = isActive && sheet.color ? { ...base, borderBottomColor: sheet.color } : base;
|
|
279
|
+
return h("button", {
|
|
280
|
+
key: sheet.id,
|
|
281
|
+
type: "button",
|
|
282
|
+
role: "tab",
|
|
283
|
+
"aria-selected": isActive,
|
|
284
|
+
style,
|
|
285
|
+
onClick: () => emit("sheetChange", sheet.id)
|
|
286
|
+
}, sheet.name);
|
|
287
|
+
})
|
|
288
|
+
]);
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
function measureRef(container, r, colOffset) {
|
|
292
|
+
const startCol = r.col + colOffset;
|
|
293
|
+
const endCol = (r.endCol ?? r.col) + colOffset;
|
|
294
|
+
const endRow = r.endRow ?? r.row;
|
|
295
|
+
const tl = container.querySelector(
|
|
296
|
+
`[data-row-index="${r.row}"][data-col-index="${startCol}"]`
|
|
297
|
+
);
|
|
298
|
+
const br = container.querySelector(
|
|
299
|
+
`[data-row-index="${endRow}"][data-col-index="${endCol}"]`
|
|
300
|
+
);
|
|
301
|
+
if (!tl || !br) return null;
|
|
302
|
+
const cRect = container.getBoundingClientRect();
|
|
303
|
+
const tlRect = tl.getBoundingClientRect();
|
|
304
|
+
const brRect = br.getBoundingClientRect();
|
|
305
|
+
return {
|
|
306
|
+
top: Math.round(tlRect.top - cRect.top),
|
|
307
|
+
left: Math.round(tlRect.left - cRect.left),
|
|
308
|
+
width: Math.round(brRect.right - tlRect.left),
|
|
309
|
+
height: Math.round(brRect.bottom - tlRect.top),
|
|
310
|
+
color: FORMULA_REF_COLORS[r.colorIndex % FORMULA_REF_COLORS.length]
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
var FormulaRefOverlay = defineComponent({
|
|
314
|
+
name: "FormulaRefOverlay",
|
|
315
|
+
props: {
|
|
316
|
+
containerEl: { type: Object, default: null },
|
|
317
|
+
references: { type: Array, required: true },
|
|
318
|
+
colOffset: { type: Number, required: true }
|
|
319
|
+
},
|
|
320
|
+
setup(props) {
|
|
321
|
+
const rects = ref([]);
|
|
322
|
+
let rafId = 0;
|
|
323
|
+
function measureAll() {
|
|
324
|
+
const container = props.containerEl;
|
|
325
|
+
const refs = props.references;
|
|
326
|
+
if (!container || refs.length === 0) {
|
|
327
|
+
rects.value = [];
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const measured = [];
|
|
331
|
+
for (const r of refs) {
|
|
332
|
+
const rect = measureRef(container, r, props.colOffset);
|
|
333
|
+
if (rect) measured.push(rect);
|
|
334
|
+
}
|
|
335
|
+
rects.value = measured;
|
|
336
|
+
}
|
|
337
|
+
watch(
|
|
338
|
+
() => [props.references, props.containerEl, props.colOffset],
|
|
339
|
+
() => {
|
|
340
|
+
cancelAnimationFrame(rafId);
|
|
341
|
+
if (!props.containerEl || props.references.length === 0) {
|
|
342
|
+
rects.value = [];
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
rafId = requestAnimationFrame(measureAll);
|
|
346
|
+
},
|
|
347
|
+
{ immediate: true }
|
|
348
|
+
);
|
|
349
|
+
return () => {
|
|
350
|
+
if (rects.value.length === 0) return null;
|
|
351
|
+
return rects.value.map(
|
|
352
|
+
(r, i) => h("svg", {
|
|
353
|
+
key: i,
|
|
354
|
+
style: {
|
|
355
|
+
position: "absolute",
|
|
356
|
+
top: `${r.top}px`,
|
|
357
|
+
left: `${r.left}px`,
|
|
358
|
+
width: `${r.width}px`,
|
|
359
|
+
height: `${r.height}px`,
|
|
360
|
+
pointerEvents: "none",
|
|
361
|
+
zIndex: 3,
|
|
362
|
+
overflow: "visible"
|
|
363
|
+
},
|
|
364
|
+
"aria-hidden": "true"
|
|
365
|
+
}, [
|
|
366
|
+
h("rect", {
|
|
367
|
+
x: "1",
|
|
368
|
+
y: "1",
|
|
369
|
+
width: Math.max(0, r.width - 2),
|
|
370
|
+
height: Math.max(0, r.height - 2),
|
|
371
|
+
fill: "none",
|
|
372
|
+
stroke: r.color,
|
|
373
|
+
"stroke-width": "2",
|
|
374
|
+
style: "shape-rendering: crispEdges"
|
|
375
|
+
})
|
|
376
|
+
])
|
|
377
|
+
);
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
});
|
|
176
381
|
function useFilterOptions(dataSource, fields) {
|
|
177
382
|
const filterOptions = ref({});
|
|
178
383
|
const loadingOptions = ref({});
|
|
@@ -245,17 +450,7 @@ function useFormulaEngine(params) {
|
|
|
245
450
|
let initialLoaded = false;
|
|
246
451
|
const enabled = computed(() => formulas?.value ?? false);
|
|
247
452
|
function createAccessor() {
|
|
248
|
-
|
|
249
|
-
const currentCols = flatColumnsRef.value;
|
|
250
|
-
return {
|
|
251
|
-
getCellValue: (col, row) => {
|
|
252
|
-
if (row < 0 || row >= currentItems.length) return null;
|
|
253
|
-
if (col < 0 || col >= currentCols.length) return null;
|
|
254
|
-
return getCellValue(currentItems[row], currentCols[col]);
|
|
255
|
-
},
|
|
256
|
-
getRowCount: () => currentItems.length,
|
|
257
|
-
getColumnCount: () => currentCols.length
|
|
258
|
-
};
|
|
453
|
+
return createGridDataAccessor(itemsRef.value, flatColumnsRef.value);
|
|
259
454
|
}
|
|
260
455
|
watch(
|
|
261
456
|
enabled,
|
|
@@ -330,6 +525,53 @@ function useFormulaEngine(params) {
|
|
|
330
525
|
getAuditTrail
|
|
331
526
|
};
|
|
332
527
|
}
|
|
528
|
+
function useFormulaBar(params) {
|
|
529
|
+
const { activeCol, activeRow, activeCellRef, getFormula, getRawValue, setFormula, onCellValueChanged } = params;
|
|
530
|
+
const isEditing = ref(false);
|
|
531
|
+
const editText = ref("");
|
|
532
|
+
const isFormulaBarEditing = ref(false);
|
|
533
|
+
const displayText = computed(
|
|
534
|
+
() => deriveFormulaBarText(activeCol.value, activeRow.value, getFormula, getRawValue)
|
|
535
|
+
);
|
|
536
|
+
watch([activeCol, activeRow], () => {
|
|
537
|
+
isEditing.value = false;
|
|
538
|
+
isFormulaBarEditing.value = false;
|
|
539
|
+
});
|
|
540
|
+
const startEditing = () => {
|
|
541
|
+
editText.value = displayText.value;
|
|
542
|
+
isEditing.value = true;
|
|
543
|
+
isFormulaBarEditing.value = true;
|
|
544
|
+
};
|
|
545
|
+
const onInputChange = (text) => {
|
|
546
|
+
editText.value = text;
|
|
547
|
+
};
|
|
548
|
+
const onCommit = () => {
|
|
549
|
+
const col = activeCol.value;
|
|
550
|
+
const row = activeRow.value;
|
|
551
|
+
if (col == null || row == null || !setFormula) return;
|
|
552
|
+
processFormulaBarCommit(editText.value, col, row, setFormula, onCellValueChanged);
|
|
553
|
+
isEditing.value = false;
|
|
554
|
+
isFormulaBarEditing.value = false;
|
|
555
|
+
};
|
|
556
|
+
const onCancel = () => {
|
|
557
|
+
isEditing.value = false;
|
|
558
|
+
isFormulaBarEditing.value = false;
|
|
559
|
+
editText.value = "";
|
|
560
|
+
};
|
|
561
|
+
const formulaText = computed(() => isEditing.value ? editText.value : displayText.value);
|
|
562
|
+
const referencedCells = computed(() => extractFormulaReferences(formulaText.value));
|
|
563
|
+
return {
|
|
564
|
+
cellRef: activeCellRef,
|
|
565
|
+
formulaText,
|
|
566
|
+
isEditing,
|
|
567
|
+
onInputChange,
|
|
568
|
+
onCommit,
|
|
569
|
+
onCancel,
|
|
570
|
+
startEditing,
|
|
571
|
+
referencedCells,
|
|
572
|
+
isFormulaBarEditing
|
|
573
|
+
};
|
|
574
|
+
}
|
|
333
575
|
var DEFAULT_PANELS = ["columns", "filters"];
|
|
334
576
|
function useSideBarState(params) {
|
|
335
577
|
const { config } = params;
|
|
@@ -615,12 +857,17 @@ function useOGrid(props) {
|
|
|
615
857
|
() => isClientSide.value && resolvedClientItems.value ? resolvedClientItems.value.totalCount : serverTotalCount.value
|
|
616
858
|
);
|
|
617
859
|
const formulasRef = computed(() => !!props.value.formulas);
|
|
860
|
+
const formulaVersionRef = ref(0);
|
|
861
|
+
const wrappedOnFormulaRecalc = (result) => {
|
|
862
|
+
formulaVersionRef.value += 1;
|
|
863
|
+
props.value.onFormulaRecalc?.(result);
|
|
864
|
+
};
|
|
618
865
|
const formulaEngine = useFormulaEngine({
|
|
619
866
|
formulas: formulasRef,
|
|
620
867
|
items: displayItems,
|
|
621
868
|
flatColumns: columns,
|
|
622
869
|
initialFormulas: props.value.initialFormulas,
|
|
623
|
-
onFormulaRecalc:
|
|
870
|
+
onFormulaRecalc: wrappedOnFormulaRecalc,
|
|
624
871
|
formulaFunctions: props.value.formulaFunctions,
|
|
625
872
|
namedRanges: props.value.namedRanges,
|
|
626
873
|
sheets: props.value.sheets
|
|
@@ -713,9 +960,36 @@ function useOGrid(props) {
|
|
|
713
960
|
const clearAllFilters = () => setFilters({});
|
|
714
961
|
const isLoadingResolved = computed(() => isServerSide.value && loading.value || displayLoading.value);
|
|
715
962
|
const activeCellRef = ref(null);
|
|
963
|
+
const activeCellCoords = ref(null);
|
|
716
964
|
const onActiveCellChange = (cellRef) => {
|
|
717
965
|
activeCellRef.value = cellRef;
|
|
966
|
+
if (cellRef) {
|
|
967
|
+
const m = cellRef.match(/^([A-Z]+)(\d+)$/);
|
|
968
|
+
if (m) {
|
|
969
|
+
activeCellCoords.value = { col: columnLetterToIndex(m[1]), row: parseInt(m[2], 10) - 1 };
|
|
970
|
+
} else {
|
|
971
|
+
activeCellCoords.value = null;
|
|
972
|
+
}
|
|
973
|
+
} else {
|
|
974
|
+
activeCellCoords.value = null;
|
|
975
|
+
}
|
|
718
976
|
};
|
|
977
|
+
const formulaBarActiveCol = computed(() => activeCellCoords.value?.col ?? null);
|
|
978
|
+
const formulaBarActiveRow = computed(() => activeCellCoords.value?.row ?? null);
|
|
979
|
+
const getRawValue = (col, row) => {
|
|
980
|
+
const items = displayItems.value;
|
|
981
|
+
const cols = columns.value;
|
|
982
|
+
if (row < 0 || row >= items.length || col < 0 || col >= cols.length) return void 0;
|
|
983
|
+
return getCellValue(items[row], cols[col]);
|
|
984
|
+
};
|
|
985
|
+
const formulaBarState = useFormulaBar({
|
|
986
|
+
activeCol: formulaBarActiveCol,
|
|
987
|
+
activeRow: formulaBarActiveRow,
|
|
988
|
+
activeCellRef,
|
|
989
|
+
getFormula: formulaEngine.enabled.value ? formulaEngine.getFormula : void 0,
|
|
990
|
+
getRawValue,
|
|
991
|
+
setFormula: formulaEngine.enabled.value ? formulaEngine.setFormula : void 0
|
|
992
|
+
});
|
|
719
993
|
const dataGridProps = computed(() => {
|
|
720
994
|
const p = props.value;
|
|
721
995
|
const ds = dataProps.value.dataSource;
|
|
@@ -743,10 +1017,11 @@ function useOGrid(props) {
|
|
|
743
1017
|
rowSelection: p.rowSelection ?? "none",
|
|
744
1018
|
selectedRows: effectiveSelectedRows.value,
|
|
745
1019
|
onSelectionChange: handleSelectionChange,
|
|
746
|
-
showRowNumbers: p.showRowNumbers || p.cellReferences,
|
|
747
|
-
showColumnLetters: !!p.cellReferences,
|
|
748
|
-
showNameBox: !!p.cellReferences,
|
|
749
|
-
|
|
1020
|
+
showRowNumbers: p.showRowNumbers || p.cellReferences || p.formulas,
|
|
1021
|
+
showColumnLetters: !!(p.cellReferences || p.formulas),
|
|
1022
|
+
showNameBox: !!(p.cellReferences && !p.formulas),
|
|
1023
|
+
// formula bar includes name box
|
|
1024
|
+
onActiveCellChange: p.cellReferences || p.formulas ? onActiveCellChange : void 0,
|
|
750
1025
|
currentPage: page.value,
|
|
751
1026
|
pageSize: pageSize.value,
|
|
752
1027
|
statusBar: statusBarConfig.value,
|
|
@@ -773,6 +1048,7 @@ function useOGrid(props) {
|
|
|
773
1048
|
render: p.emptyState?.render
|
|
774
1049
|
},
|
|
775
1050
|
formulas: p.formulas,
|
|
1051
|
+
formulaVersion: formulaVersionRef.value,
|
|
776
1052
|
...formulaEngine.enabled.value ? {
|
|
777
1053
|
getFormulaValue: formulaEngine.getFormulaValue,
|
|
778
1054
|
hasFormula: formulaEngine.hasFormula,
|
|
@@ -782,7 +1058,8 @@ function useOGrid(props) {
|
|
|
782
1058
|
getPrecedents: formulaEngine.getPrecedents,
|
|
783
1059
|
getDependents: formulaEngine.getDependents,
|
|
784
1060
|
getAuditTrail: formulaEngine.getAuditTrail
|
|
785
|
-
} : {}
|
|
1061
|
+
} : {},
|
|
1062
|
+
formulaReferences: formulaBarState.referencedCells.value.length > 0 ? formulaBarState.referencedCells.value : void 0
|
|
786
1063
|
};
|
|
787
1064
|
});
|
|
788
1065
|
const pagination = computed(() => ({
|
|
@@ -801,8 +1078,10 @@ function useOGrid(props) {
|
|
|
801
1078
|
placement: columnChooserPlacement.value
|
|
802
1079
|
}));
|
|
803
1080
|
const layout = computed(() => {
|
|
804
|
-
const
|
|
805
|
-
|
|
1081
|
+
const p = props.value;
|
|
1082
|
+
const formulas = !!p.formulas;
|
|
1083
|
+
const showNameBox = !!p.cellReferences && !formulas;
|
|
1084
|
+
let resolvedToolbar = p.toolbar;
|
|
806
1085
|
if (showNameBox) {
|
|
807
1086
|
const nameBoxEl = h("div", {
|
|
808
1087
|
style: {
|
|
@@ -823,13 +1102,32 @@ function useOGrid(props) {
|
|
|
823
1102
|
}, activeCellRef.value ?? "\u2014");
|
|
824
1103
|
resolvedToolbar = [nameBoxEl, resolvedToolbar];
|
|
825
1104
|
}
|
|
1105
|
+
const formulaBarEl = formulas ? h(FormulaBar, {
|
|
1106
|
+
cellRef: formulaBarState.cellRef.value,
|
|
1107
|
+
formulaText: formulaBarState.formulaText.value,
|
|
1108
|
+
isEditing: formulaBarState.isEditing.value,
|
|
1109
|
+
onInputChange: formulaBarState.onInputChange,
|
|
1110
|
+
onCommit: formulaBarState.onCommit,
|
|
1111
|
+
onCancel: formulaBarState.onCancel,
|
|
1112
|
+
onStartEditing: formulaBarState.startEditing
|
|
1113
|
+
}) : void 0;
|
|
1114
|
+
const sheetTabsEl = p.sheetDefs && p.sheetDefs.length > 0 && p.activeSheet && p.onSheetChange ? h(SheetTabs, {
|
|
1115
|
+
sheets: p.sheetDefs,
|
|
1116
|
+
activeSheet: p.activeSheet,
|
|
1117
|
+
showAddButton: !!p.onSheetAdd,
|
|
1118
|
+
onSheetChange: p.onSheetChange,
|
|
1119
|
+
onSheetAdd: p.onSheetAdd ?? (() => {
|
|
1120
|
+
})
|
|
1121
|
+
}) : void 0;
|
|
826
1122
|
return {
|
|
827
1123
|
toolbar: resolvedToolbar,
|
|
828
|
-
toolbarBelow:
|
|
829
|
-
className:
|
|
830
|
-
emptyState:
|
|
1124
|
+
toolbarBelow: p.toolbarBelow,
|
|
1125
|
+
className: p.className,
|
|
1126
|
+
emptyState: p.emptyState,
|
|
831
1127
|
sideBarProps: sideBarProps.value,
|
|
832
|
-
fullScreen:
|
|
1128
|
+
fullScreen: p.fullScreen,
|
|
1129
|
+
formulaBar: formulaBarEl,
|
|
1130
|
+
sheetTabs: sheetTabsEl
|
|
833
1131
|
};
|
|
834
1132
|
});
|
|
835
1133
|
const filtersResult = computed(() => ({
|
|
@@ -1518,6 +1816,7 @@ function useKeyboardNavigation(params) {
|
|
|
1518
1816
|
case "ArrowUp":
|
|
1519
1817
|
case "ArrowRight":
|
|
1520
1818
|
case "ArrowLeft": {
|
|
1819
|
+
if (editingCell != null) break;
|
|
1521
1820
|
e.preventDefault();
|
|
1522
1821
|
const { newRowIndex, newColumnIndex, newRange } = computeArrowNavigation({
|
|
1523
1822
|
direction: e.key,
|
|
@@ -2449,7 +2748,10 @@ function useDataGridState(params) {
|
|
|
2449
2748
|
getRowId,
|
|
2450
2749
|
editable: editableProp.value,
|
|
2451
2750
|
onCellValueChanged: onCellValueChanged.value,
|
|
2452
|
-
isDragging: cellSelection.value ? isDragging.value : false
|
|
2751
|
+
isDragging: cellSelection.value ? isDragging.value : false,
|
|
2752
|
+
getFormulaValue: props.value.getFormulaValue,
|
|
2753
|
+
hasFormula: props.value.hasFormula,
|
|
2754
|
+
formulaVersion: props.value.formulaVersion
|
|
2453
2755
|
}));
|
|
2454
2756
|
const popoverAnchorEl = ref(null);
|
|
2455
2757
|
const setPopoverAnchorEl = (el) => {
|
|
@@ -2631,9 +2933,10 @@ function useColumnResize(params) {
|
|
|
2631
2933
|
[columnId]: { widthPx: latestWidth }
|
|
2632
2934
|
});
|
|
2633
2935
|
};
|
|
2936
|
+
const effectiveMinWidth = columnId === ROW_NUMBER_COLUMN_ID ? ROW_NUMBER_COLUMN_MIN_WIDTH : minWidth;
|
|
2634
2937
|
const onMove = (moveEvent) => {
|
|
2635
2938
|
const deltaX = moveEvent.clientX - startX;
|
|
2636
|
-
latestWidth = Math.max(
|
|
2939
|
+
latestWidth = Math.max(effectiveMinWidth, startWidth + deltaX);
|
|
2637
2940
|
if (!rafId) {
|
|
2638
2941
|
rafId = requestAnimationFrame(() => {
|
|
2639
2942
|
rafId = 0;
|
|
@@ -3138,9 +3441,14 @@ function useColumnChooserState(params) {
|
|
|
3138
3441
|
}
|
|
3139
3442
|
function useInlineCellEditorState(params) {
|
|
3140
3443
|
const { value, editorType, onCommit, onCancel } = params;
|
|
3141
|
-
const localValue = ref(
|
|
3142
|
-
value
|
|
3143
|
-
|
|
3444
|
+
const localValue = ref((() => {
|
|
3445
|
+
if (value === null || value === void 0) return "";
|
|
3446
|
+
if (editorType === "date") {
|
|
3447
|
+
const str = String(value);
|
|
3448
|
+
return str.match(/^\d{4}-\d{2}-\d{2}/) ? str.substring(0, 10) : str;
|
|
3449
|
+
}
|
|
3450
|
+
return String(value);
|
|
3451
|
+
})());
|
|
3144
3452
|
const setLocalValue = (v) => {
|
|
3145
3453
|
localValue.value = v;
|
|
3146
3454
|
};
|
|
@@ -3177,9 +3485,10 @@ function useInlineCellEditorState(params) {
|
|
|
3177
3485
|
};
|
|
3178
3486
|
}
|
|
3179
3487
|
function useRichSelectState(params) {
|
|
3180
|
-
const { values, formatValue, onCommit, onCancel } = params;
|
|
3488
|
+
const { values, formatValue, initialValue, onCommit, onCancel } = params;
|
|
3181
3489
|
const searchText = ref("");
|
|
3182
|
-
const
|
|
3490
|
+
const initialIndex = values.findIndex((v) => String(v) === String(initialValue));
|
|
3491
|
+
const highlightedIndex = ref(Math.max(initialIndex, 0));
|
|
3183
3492
|
const setSearchText = (text) => {
|
|
3184
3493
|
searchText.value = text;
|
|
3185
3494
|
};
|
|
@@ -3569,7 +3878,7 @@ function createDataGridTable(ui) {
|
|
|
3569
3878
|
const cb = propsRef.value.onActiveCellChange;
|
|
3570
3879
|
if (!cb) return;
|
|
3571
3880
|
if (ac) {
|
|
3572
|
-
cb(formatCellReference(ac.columnIndex, offset + ac.rowIndex + 1));
|
|
3881
|
+
cb(formatCellReference(ac.columnIndex - state.layout.value.colOffset, offset + ac.rowIndex + 1));
|
|
3573
3882
|
} else {
|
|
3574
3883
|
cb(null);
|
|
3575
3884
|
}
|
|
@@ -3740,8 +4049,6 @@ function createDataGridTable(ui) {
|
|
|
3740
4049
|
popoverAnchorEl ? h(CustomEditor, editorProps) : null
|
|
3741
4050
|
]);
|
|
3742
4051
|
}
|
|
3743
|
-
const content = resolveCellDisplayContent(col, item, descriptor.displayValue);
|
|
3744
|
-
const cellStyle = resolveCellStyle(col, item, descriptor.displayValue);
|
|
3745
4052
|
const interactionProps2 = getCellInteractionProps(descriptor, col.columnId, interactionHandlers);
|
|
3746
4053
|
const cellClasses = ["ogrid-cell-content"];
|
|
3747
4054
|
if (col.type === "numeric") cellClasses.push("ogrid-cell-content--numeric");
|
|
@@ -3751,12 +4058,25 @@ function createDataGridTable(ui) {
|
|
|
3751
4058
|
if (descriptor.isActive && descriptor.isInRange) cellClasses.push("ogrid-cell-content--active-in-range");
|
|
3752
4059
|
if (descriptor.isInRange && !descriptor.isActive) cellClasses.push("ogrid-cell-in-range");
|
|
3753
4060
|
if (descriptor.isInCutRange) cellClasses.push("ogrid-cell-cut");
|
|
3754
|
-
|
|
4061
|
+
let displayNode;
|
|
4062
|
+
if (descriptor.columnType === "boolean") {
|
|
4063
|
+
displayNode = h("input", {
|
|
4064
|
+
type: "checkbox",
|
|
4065
|
+
checked: !!descriptor.displayValue,
|
|
4066
|
+
disabled: true,
|
|
4067
|
+
style: "margin:0;pointer-events:none",
|
|
4068
|
+
"aria-label": descriptor.displayValue ? "True" : "False"
|
|
4069
|
+
});
|
|
4070
|
+
} else {
|
|
4071
|
+
const content = resolveCellDisplayContent(col, item, descriptor.displayValue);
|
|
4072
|
+
const cellStyle = resolveCellStyle(col, item, descriptor.displayValue);
|
|
4073
|
+
displayNode = cellStyle ? h("span", { style: cellStyle }, content) : content;
|
|
4074
|
+
}
|
|
3755
4075
|
return h("div", {
|
|
3756
4076
|
...interactionProps2,
|
|
3757
4077
|
class: cellClasses.join(" ")
|
|
3758
4078
|
}, [
|
|
3759
|
-
|
|
4079
|
+
displayNode,
|
|
3760
4080
|
...descriptor.canEditAny && descriptor.isSelectionEndCell ? [
|
|
3761
4081
|
h("div", {
|
|
3762
4082
|
onMousedown: handleFillHandleMouseDown,
|
|
@@ -3898,32 +4218,46 @@ function createDataGridTable(ui) {
|
|
|
3898
4218
|
})
|
|
3899
4219
|
] : [],
|
|
3900
4220
|
// Row numbers header
|
|
3901
|
-
...rowIdx === headerRows.length - 1 && hasRowNumbersCol ? [
|
|
3902
|
-
|
|
4221
|
+
...rowIdx === headerRows.length - 1 && hasRowNumbersCol ? [(() => {
|
|
4222
|
+
const rnw = layout.columnSizingOverrides[ROW_NUMBER_COLUMN_ID]?.widthPx ?? ROW_NUMBER_COLUMN_WIDTH;
|
|
4223
|
+
return h("th", {
|
|
3903
4224
|
class: "ogrid-row-number-header",
|
|
3904
4225
|
style: {
|
|
3905
|
-
width: `${
|
|
3906
|
-
minWidth: `${
|
|
3907
|
-
maxWidth: `${
|
|
4226
|
+
width: `${rnw}px`,
|
|
4227
|
+
minWidth: `${rnw}px`,
|
|
4228
|
+
maxWidth: `${rnw}px`,
|
|
3908
4229
|
position: "sticky",
|
|
3909
4230
|
left: hasCheckboxCol ? `${CHECKBOX_COLUMN_WIDTH}px` : "0",
|
|
3910
4231
|
zIndex: 3
|
|
3911
4232
|
}
|
|
3912
|
-
},
|
|
3913
|
-
|
|
4233
|
+
}, [
|
|
4234
|
+
"#",
|
|
4235
|
+
h("div", {
|
|
4236
|
+
onMousedown: (e) => {
|
|
4237
|
+
setActiveCell(null);
|
|
4238
|
+
setSelectionRange(null);
|
|
4239
|
+
wrapperRef.value?.focus({ preventScroll: true });
|
|
4240
|
+
e.stopPropagation();
|
|
4241
|
+
handleResizeStart(e, { columnId: ROW_NUMBER_COLUMN_ID, name: "#" });
|
|
4242
|
+
},
|
|
4243
|
+
class: "ogrid-resize-handle"
|
|
4244
|
+
})
|
|
4245
|
+
]);
|
|
4246
|
+
})()] : [],
|
|
3914
4247
|
// Row numbers spacer
|
|
3915
|
-
...rowIdx === 0 && rowIdx < headerRows.length - 1 && hasRowNumbersCol ? [
|
|
3916
|
-
|
|
4248
|
+
...rowIdx === 0 && rowIdx < headerRows.length - 1 && hasRowNumbersCol ? [(() => {
|
|
4249
|
+
const spacerRnw = layout.columnSizingOverrides[ROW_NUMBER_COLUMN_ID]?.widthPx ?? ROW_NUMBER_COLUMN_WIDTH;
|
|
4250
|
+
return h("th", {
|
|
3917
4251
|
rowSpan: headerRows.length - 1,
|
|
3918
4252
|
class: "ogrid-row-number-spacer",
|
|
3919
4253
|
style: {
|
|
3920
|
-
width: `${
|
|
4254
|
+
width: `${spacerRnw}px`,
|
|
3921
4255
|
position: "sticky",
|
|
3922
4256
|
left: hasCheckboxCol ? `${CHECKBOX_COLUMN_WIDTH}px` : "0",
|
|
3923
4257
|
zIndex: 3
|
|
3924
4258
|
}
|
|
3925
|
-
})
|
|
3926
|
-
] : [],
|
|
4259
|
+
});
|
|
4260
|
+
})()] : [],
|
|
3927
4261
|
// Header cells
|
|
3928
4262
|
...row.map((cell, cellIdx) => {
|
|
3929
4263
|
if (cell.isGroup) {
|
|
@@ -3954,7 +4288,11 @@ function createDataGridTable(ui) {
|
|
|
3954
4288
|
h("button", {
|
|
3955
4289
|
onClick: (e) => {
|
|
3956
4290
|
e.stopPropagation();
|
|
3957
|
-
headerMenu.
|
|
4291
|
+
if (headerMenu.isOpen && headerMenu.openForColumn === col.columnId) {
|
|
4292
|
+
headerMenu.close();
|
|
4293
|
+
} else {
|
|
4294
|
+
headerMenu.open(col.columnId, e.currentTarget);
|
|
4295
|
+
}
|
|
3958
4296
|
},
|
|
3959
4297
|
"aria-label": "Column options",
|
|
3960
4298
|
title: "Column options",
|
|
@@ -4029,20 +4367,21 @@ function createDataGridTable(ui) {
|
|
|
4029
4367
|
)
|
|
4030
4368
|
] : [],
|
|
4031
4369
|
// Row numbers cell
|
|
4032
|
-
...hasRowNumbersCol ? [
|
|
4033
|
-
|
|
4370
|
+
...hasRowNumbersCol ? [(() => {
|
|
4371
|
+
const rnw = layout.columnSizingOverrides[ROW_NUMBER_COLUMN_ID]?.widthPx ?? ROW_NUMBER_COLUMN_WIDTH;
|
|
4372
|
+
return h("td", {
|
|
4034
4373
|
class: "ogrid-row-number-cell",
|
|
4035
4374
|
style: {
|
|
4036
|
-
width: `${
|
|
4037
|
-
minWidth: `${
|
|
4038
|
-
maxWidth: `${
|
|
4375
|
+
width: `${rnw}px`,
|
|
4376
|
+
minWidth: `${rnw}px`,
|
|
4377
|
+
maxWidth: `${rnw}px`,
|
|
4039
4378
|
padding: "6px",
|
|
4040
4379
|
position: "sticky",
|
|
4041
4380
|
left: hasCheckboxCol ? `${CHECKBOX_COLUMN_WIDTH}px` : "0",
|
|
4042
4381
|
zIndex: 2
|
|
4043
4382
|
}
|
|
4044
|
-
}, String(rowNumberOffset2 + rowIndex + 1))
|
|
4045
|
-
] : [],
|
|
4383
|
+
}, String(rowNumberOffset2 + rowIndex + 1));
|
|
4384
|
+
})()] : [],
|
|
4046
4385
|
// Left spacer for column virtualization
|
|
4047
4386
|
...leftSpacerWidth > 0 ? [
|
|
4048
4387
|
h("td", { key: "__col-spacer-left", style: { width: `${leftSpacerWidth}px`, minWidth: `${leftSpacerWidth}px`, maxWidth: `${leftSpacerWidth}px`, padding: "0" } })
|
|
@@ -4112,6 +4451,14 @@ function createDataGridTable(ui) {
|
|
|
4112
4451
|
columnSizingOverrides: layout.columnSizingOverrides,
|
|
4113
4452
|
columnOrder: p.columnOrder
|
|
4114
4453
|
}),
|
|
4454
|
+
// Formula reference overlay
|
|
4455
|
+
...p.formulaReferences && p.formulaReferences.length > 0 ? [
|
|
4456
|
+
h(FormulaRefOverlay, {
|
|
4457
|
+
containerEl: tableContainerRef.value,
|
|
4458
|
+
references: p.formulaReferences,
|
|
4459
|
+
colOffset: _colOffset
|
|
4460
|
+
})
|
|
4461
|
+
] : [],
|
|
4115
4462
|
// Column header menu
|
|
4116
4463
|
h(ui.ColumnHeaderMenu, {
|
|
4117
4464
|
isOpen: headerMenu.isOpen,
|
|
@@ -4713,8 +5060,12 @@ function createOGrid(ui) {
|
|
|
4713
5060
|
style: { padding: "8px 12px", borderBottom: "1px solid var(--ogrid-border, rgba(0,0,0,0.12))" }
|
|
4714
5061
|
}, [layout.value.toolbarBelow])
|
|
4715
5062
|
] : [],
|
|
5063
|
+
// Formula bar (between toolbar and grid)
|
|
5064
|
+
...layout.value.formulaBar ? [layout.value.formulaBar] : [],
|
|
4716
5065
|
// Main content area (sidebar + grid)
|
|
4717
5066
|
h("div", { style: { display: "flex", flex: "1", minHeight: "0" } }, mainAreaChildren),
|
|
5067
|
+
// Sheet tabs (between grid and footer)
|
|
5068
|
+
...layout.value.sheetTabs ? [layout.value.sheetTabs] : [],
|
|
4718
5069
|
// Footer strip (pagination)
|
|
4719
5070
|
h("div", {
|
|
4720
5071
|
style: {
|
|
@@ -4731,4 +5082,4 @@ function createOGrid(ui) {
|
|
|
4731
5082
|
});
|
|
4732
5083
|
}
|
|
4733
5084
|
|
|
4734
|
-
export { MarchingAntsOverlay, StatusBar, createDataGridTable, createInlineCellEditor, createOGrid, getCellInteractionProps, useActiveCell, useCellEditing, useCellSelection, useClipboard, useColumnChooserState, useColumnHeaderFilterState, useColumnHeaderMenuState, useColumnPinning, useColumnReorder, useColumnResize, useContextMenu, useDataGridState, useDataGridTableSetup, useDateFilterState, useDebounce, useDebouncedCallback, useFillHandle, useFilterOptions, useInlineCellEditorState, useKeyboardNavigation, useMultiSelectFilterState, useOGrid, usePeopleFilterState, useRichSelectState, useRowSelection, useSideBarState, useTableLayout, useTextFilterState, useUndoRedo, useVirtualScroll };
|
|
5085
|
+
export { FormulaBar, FormulaRefOverlay, MarchingAntsOverlay, SheetTabs, StatusBar, createDataGridTable, createInlineCellEditor, createOGrid, getCellInteractionProps, useActiveCell, useCellEditing, useCellSelection, useClipboard, useColumnChooserState, useColumnHeaderFilterState, useColumnHeaderMenuState, useColumnPinning, useColumnReorder, useColumnResize, useContextMenu, useDataGridState, useDataGridTableSetup, useDateFilterState, useDebounce, useDebouncedCallback, useFillHandle, useFilterOptions, useFormulaBar, useInlineCellEditorState, useKeyboardNavigation, useMultiSelectFilterState, useOGrid, usePeopleFilterState, useRichSelectState, useRowSelection, useSideBarState, useTableLayout, useTextFilterState, useUndoRedo, useVirtualScroll };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FormulaBar — Headless Excel-style formula bar component.
|
|
3
|
+
*
|
|
4
|
+
* Layout: [Name Box] [fx] [Formula Input]
|
|
5
|
+
*
|
|
6
|
+
* Uses --ogrid-* CSS variables for theming.
|
|
7
|
+
*/
|
|
8
|
+
import { type PropType } from 'vue';
|
|
9
|
+
export interface FormulaBarProps {
|
|
10
|
+
/** Active cell reference (e.g. "A1"). */
|
|
11
|
+
cellRef: string | null;
|
|
12
|
+
/** Text displayed/edited in the formula input. */
|
|
13
|
+
formulaText: string;
|
|
14
|
+
/** Whether the input is in editing mode. */
|
|
15
|
+
isEditing: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare const FormulaBar: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
18
|
+
cellRef: {
|
|
19
|
+
type: PropType<string | null>;
|
|
20
|
+
default: null;
|
|
21
|
+
};
|
|
22
|
+
formulaText: {
|
|
23
|
+
type: StringConstructor;
|
|
24
|
+
required: true;
|
|
25
|
+
};
|
|
26
|
+
isEditing: {
|
|
27
|
+
type: BooleanConstructor;
|
|
28
|
+
required: true;
|
|
29
|
+
};
|
|
30
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
31
|
+
[key: string]: any;
|
|
32
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("cancel" | "inputChange" | "commit" | "startEditing")[], "cancel" | "inputChange" | "commit" | "startEditing", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
33
|
+
cellRef: {
|
|
34
|
+
type: PropType<string | null>;
|
|
35
|
+
default: null;
|
|
36
|
+
};
|
|
37
|
+
formulaText: {
|
|
38
|
+
type: StringConstructor;
|
|
39
|
+
required: true;
|
|
40
|
+
};
|
|
41
|
+
isEditing: {
|
|
42
|
+
type: BooleanConstructor;
|
|
43
|
+
required: true;
|
|
44
|
+
};
|
|
45
|
+
}>> & Readonly<{
|
|
46
|
+
onCancel?: ((...args: any[]) => any) | undefined;
|
|
47
|
+
onInputChange?: ((...args: any[]) => any) | undefined;
|
|
48
|
+
onCommit?: ((...args: any[]) => any) | undefined;
|
|
49
|
+
onStartEditing?: ((...args: any[]) => any) | undefined;
|
|
50
|
+
}>, {
|
|
51
|
+
cellRef: string | null;
|
|
52
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FormulaRefOverlay — Renders colored border overlays on cells referenced by
|
|
3
|
+
* the active formula, like Excel's reference highlighting.
|
|
4
|
+
*
|
|
5
|
+
* Port of React's FormulaRefOverlay component.
|
|
6
|
+
*/
|
|
7
|
+
import { type PropType } from 'vue';
|
|
8
|
+
import { type FormulaReference } from '@alaarab/ogrid-core';
|
|
9
|
+
export declare const FormulaRefOverlay: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
10
|
+
containerEl: {
|
|
11
|
+
type: PropType<HTMLElement | null>;
|
|
12
|
+
default: null;
|
|
13
|
+
};
|
|
14
|
+
references: {
|
|
15
|
+
type: PropType<FormulaReference[]>;
|
|
16
|
+
required: true;
|
|
17
|
+
};
|
|
18
|
+
colOffset: {
|
|
19
|
+
type: NumberConstructor;
|
|
20
|
+
required: true;
|
|
21
|
+
};
|
|
22
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
23
|
+
[key: string]: any;
|
|
24
|
+
}>[] | null, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
25
|
+
containerEl: {
|
|
26
|
+
type: PropType<HTMLElement | null>;
|
|
27
|
+
default: null;
|
|
28
|
+
};
|
|
29
|
+
references: {
|
|
30
|
+
type: PropType<FormulaReference[]>;
|
|
31
|
+
required: true;
|
|
32
|
+
};
|
|
33
|
+
colOffset: {
|
|
34
|
+
type: NumberConstructor;
|
|
35
|
+
required: true;
|
|
36
|
+
};
|
|
37
|
+
}>> & Readonly<{}>, {
|
|
38
|
+
containerEl: HTMLElement | null;
|
|
39
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SheetTabs — Excel-style sheet tab bar at the bottom of the grid.
|
|
3
|
+
*
|
|
4
|
+
* Layout: [+] [Sheet1] [Sheet2] [Sheet3]
|
|
5
|
+
*/
|
|
6
|
+
import { type PropType } from 'vue';
|
|
7
|
+
import type { ISheetDef } from '@alaarab/ogrid-core';
|
|
8
|
+
export interface SheetTabsProps {
|
|
9
|
+
sheets: ISheetDef[];
|
|
10
|
+
activeSheet: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const SheetTabs: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
13
|
+
sheets: {
|
|
14
|
+
type: PropType<ISheetDef[]>;
|
|
15
|
+
required: true;
|
|
16
|
+
};
|
|
17
|
+
activeSheet: {
|
|
18
|
+
type: StringConstructor;
|
|
19
|
+
required: true;
|
|
20
|
+
};
|
|
21
|
+
showAddButton: {
|
|
22
|
+
type: BooleanConstructor;
|
|
23
|
+
default: boolean;
|
|
24
|
+
};
|
|
25
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
26
|
+
[key: string]: any;
|
|
27
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("sheetChange" | "sheetAdd")[], "sheetChange" | "sheetAdd", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
28
|
+
sheets: {
|
|
29
|
+
type: PropType<ISheetDef[]>;
|
|
30
|
+
required: true;
|
|
31
|
+
};
|
|
32
|
+
activeSheet: {
|
|
33
|
+
type: StringConstructor;
|
|
34
|
+
required: true;
|
|
35
|
+
};
|
|
36
|
+
showAddButton: {
|
|
37
|
+
type: BooleanConstructor;
|
|
38
|
+
default: boolean;
|
|
39
|
+
};
|
|
40
|
+
}>> & Readonly<{
|
|
41
|
+
onSheetChange?: ((...args: any[]) => any) | undefined;
|
|
42
|
+
onSheetAdd?: ((...args: any[]) => any) | undefined;
|
|
43
|
+
}>, {
|
|
44
|
+
showAddButton: boolean;
|
|
45
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
@@ -32,6 +32,8 @@ export { useTableLayout } from './useTableLayout';
|
|
|
32
32
|
export type { UseTableLayoutParams, UseTableLayoutResult } from './useTableLayout';
|
|
33
33
|
export { useFormulaEngine } from './useFormulaEngine';
|
|
34
34
|
export type { UseFormulaEngineParams, UseFormulaEngineResult } from './useFormulaEngine';
|
|
35
|
+
export { useFormulaBar } from './useFormulaBar';
|
|
36
|
+
export type { UseFormulaBarParams, UseFormulaBarResult } from './useFormulaBar';
|
|
35
37
|
export { useColumnHeaderFilterState } from './useColumnHeaderFilterState';
|
|
36
38
|
export type { UseColumnHeaderFilterStateParams, UseColumnHeaderFilterStateResult, } from './useColumnHeaderFilterState';
|
|
37
39
|
export { useTextFilterState } from './useTextFilterState';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useFormulaBar — Vue composable for formula bar state.
|
|
3
|
+
*
|
|
4
|
+
* Manages the formula bar text, editing mode, and reference extraction.
|
|
5
|
+
*/
|
|
6
|
+
import { type Ref } from 'vue';
|
|
7
|
+
import { type FormulaReference } from '@alaarab/ogrid-core';
|
|
8
|
+
export interface UseFormulaBarParams {
|
|
9
|
+
/** Active cell column index (0-based). */
|
|
10
|
+
activeCol: Ref<number | null>;
|
|
11
|
+
/** Active cell row index (0-based). */
|
|
12
|
+
activeRow: Ref<number | null>;
|
|
13
|
+
/** Active cell reference string (e.g. "A1"). */
|
|
14
|
+
activeCellRef: Ref<string | null>;
|
|
15
|
+
/** Get formula string for a cell. */
|
|
16
|
+
getFormula?: (col: number, row: number) => string | undefined;
|
|
17
|
+
/** Get raw display value for a cell. */
|
|
18
|
+
getRawValue?: (col: number, row: number) => unknown;
|
|
19
|
+
/** Set formula for a cell. */
|
|
20
|
+
setFormula?: (col: number, row: number, formula: string | null) => void;
|
|
21
|
+
/** Commit a non-formula value change. */
|
|
22
|
+
onCellValueChanged?: (col: number, row: number, value: unknown) => void;
|
|
23
|
+
}
|
|
24
|
+
export interface UseFormulaBarResult {
|
|
25
|
+
/** Cell reference string (e.g. "A1"). */
|
|
26
|
+
cellRef: Ref<string | null>;
|
|
27
|
+
/** Text shown in the formula bar input. */
|
|
28
|
+
formulaText: Ref<string>;
|
|
29
|
+
/** Whether the formula bar input is being edited. */
|
|
30
|
+
isEditing: Ref<boolean>;
|
|
31
|
+
/** Update the formula bar input text. */
|
|
32
|
+
onInputChange: (text: string) => void;
|
|
33
|
+
/** Commit the current edit. */
|
|
34
|
+
onCommit: () => void;
|
|
35
|
+
/** Cancel the current edit. */
|
|
36
|
+
onCancel: () => void;
|
|
37
|
+
/** Start editing the formula bar. */
|
|
38
|
+
startEditing: () => void;
|
|
39
|
+
/** References extracted from the current formula text (for highlighting). */
|
|
40
|
+
referencedCells: Ref<FormulaReference[]>;
|
|
41
|
+
/** Whether the formula bar is actively being edited (for click-to-insert-ref guards). */
|
|
42
|
+
isFormulaBarEditing: Ref<boolean>;
|
|
43
|
+
}
|
|
44
|
+
export declare function useFormulaBar(params: UseFormulaBarParams): UseFormulaBarResult;
|
|
@@ -31,6 +31,10 @@ export interface UseOGridLayout {
|
|
|
31
31
|
};
|
|
32
32
|
sideBarProps: SideBarProps | null;
|
|
33
33
|
fullScreen?: boolean;
|
|
34
|
+
/** Formula bar element (rendered between toolbar and grid). */
|
|
35
|
+
formulaBar?: unknown;
|
|
36
|
+
/** Sheet tabs element (rendered between grid and footer). */
|
|
37
|
+
sheetTabs?: unknown;
|
|
34
38
|
}
|
|
35
39
|
/** Filter state. */
|
|
36
40
|
export interface UseOGridFilters {
|
package/dist/types/index.d.ts
CHANGED
|
@@ -4,8 +4,11 @@ export type { ColumnFilterType, IColumnFilterDef, IColumnMeta, IColumnGroupDef,
|
|
|
4
4
|
export { toUserLike, isInSelectionRange, normalizeSelectionRange } from './types';
|
|
5
5
|
export { MarchingAntsOverlay } from './components/MarchingAntsOverlay';
|
|
6
6
|
export { StatusBar, type StatusBarProps } from './components/StatusBar';
|
|
7
|
-
export {
|
|
8
|
-
export
|
|
7
|
+
export { FormulaBar, type FormulaBarProps } from './components/FormulaBar';
|
|
8
|
+
export { SheetTabs, type SheetTabsProps } from './components/SheetTabs';
|
|
9
|
+
export { FormulaRefOverlay } from './components/FormulaRefOverlay';
|
|
10
|
+
export { useOGrid, useDataGridState, useActiveCell, useCellEditing, useCellSelection, useClipboard, useRowSelection, useKeyboardNavigation, useFillHandle, useUndoRedo, useContextMenu, useColumnResize, useColumnReorder, useVirtualScroll, useFilterOptions, useDebounce, useDebouncedCallback, useTableLayout, useColumnHeaderFilterState, useTextFilterState, useMultiSelectFilterState, usePeopleFilterState, useDateFilterState, useColumnChooserState, useInlineCellEditorState, useRichSelectState, useSideBarState, useColumnPinning, useColumnHeaderMenuState, useDataGridTableSetup, useFormulaBar, } from './composables';
|
|
11
|
+
export type { UseOGridResult, UseOGridPagination, UseOGridColumnChooser, UseOGridLayout, UseOGridFilters, ColumnChooserPlacement, UseDataGridStateParams, UseDataGridStateResult, DataGridLayoutState, DataGridRowSelectionState, DataGridEditingState, DataGridCellInteractionState, DataGridContextMenuState, DataGridViewModelState, DataGridPinningState, UseActiveCellResult, EditingCell, UseCellEditingParams, UseCellEditingResult, UseCellSelectionParams, UseCellSelectionResult, UseClipboardParams, UseClipboardResult, UseRowSelectionParams, UseRowSelectionResult, UseKeyboardNavigationParams, UseKeyboardNavigationResult, UseFillHandleParams, UseFillHandleResult, UseUndoRedoParams, UseUndoRedoResult, ContextMenuPosition, UseContextMenuResult, UseColumnResizeParams, UseColumnResizeResult, UseColumnReorderParams, UseColumnReorderResult, UseVirtualScrollParams, UseVirtualScrollResult, UseFilterOptionsResult, UseTableLayoutParams, UseTableLayoutResult, UseColumnHeaderFilterStateParams, UseColumnHeaderFilterStateResult, UseTextFilterStateParams, UseTextFilterStateResult, UseMultiSelectFilterStateParams, UseMultiSelectFilterStateResult, UsePeopleFilterStateParams, UsePeopleFilterStateResult, UseDateFilterStateParams, UseDateFilterStateResult, UseColumnChooserStateParams, UseColumnChooserStateResult, InlineCellEditorType, UseInlineCellEditorStateParams, UseInlineCellEditorStateResult, UseRichSelectStateParams, UseRichSelectStateResult, UseSideBarStateParams, UseSideBarStateResult, DebouncedFn, UseColumnPinningParams, UseColumnPinningResult, UseColumnHeaderMenuStateParams, UseColumnHeaderMenuStateResult, UseDataGridTableSetupParams, UseDataGridTableSetupResult, MaybeShallowRef, UseFormulaBarParams, UseFormulaBarResult, } from './composables';
|
|
9
12
|
export { getHeaderFilterConfig, getCellRenderDescriptor, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, getCellInteractionProps, } from './utils';
|
|
10
13
|
export type { HeaderFilterConfigInput, HeaderFilterConfig, CellRenderDescriptorInput, CellRenderDescriptor, CellRenderMode, CellInteractionHandlers, CellInteractionProps, } from './utils';
|
|
11
14
|
export { createDataGridTable, type IDataGridTableUIBindings } from './components/createDataGridTable';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { IColumnDef, IColumnGroupDef, ICellValueChangedEvent } from './columnTypes';
|
|
2
|
-
export type { RowId, UserLike, UserLikeInput, FilterValue, IFilters, IFetchParams, IPageResult, IDataSource, IGridColumnState, RowSelectionMode, IRowSelectionChangeEvent, StatusBarPanel, IStatusBarProps, IActiveCell, ISelectionRange, SideBarPanelId, ISideBarDef, IOGridApi, IVirtualScrollConfig, IFormulaFunction, IRecalcResult, IGridDataAccessor, IAuditEntry, IAuditTrail, } from '@alaarab/ogrid-core';
|
|
2
|
+
export type { RowId, UserLike, UserLikeInput, FilterValue, IFilters, IFetchParams, IPageResult, IDataSource, IGridColumnState, RowSelectionMode, IRowSelectionChangeEvent, StatusBarPanel, IStatusBarProps, IActiveCell, ISelectionRange, SideBarPanelId, ISideBarDef, IOGridApi, IVirtualScrollConfig, IFormulaFunction, IRecalcResult, IGridDataAccessor, IAuditEntry, IAuditTrail, ISheetDef, FormulaReference, } from '@alaarab/ogrid-core';
|
|
3
3
|
export { toUserLike, isInSelectionRange, normalizeSelectionRange } from '@alaarab/ogrid-core';
|
|
4
|
-
import type { RowId, UserLike, IFilters, FilterValue, RowSelectionMode, IRowSelectionChangeEvent, IStatusBarProps, IDataSource, ISideBarDef, IVirtualScrollConfig, IFormulaFunction, IRecalcResult, IGridDataAccessor, IAuditEntry, IAuditTrail } from '@alaarab/ogrid-core';
|
|
4
|
+
import type { RowId, UserLike, IFilters, FilterValue, RowSelectionMode, IRowSelectionChangeEvent, IStatusBarProps, IDataSource, ISideBarDef, IVirtualScrollConfig, IFormulaFunction, IRecalcResult, IGridDataAccessor, IAuditEntry, IAuditTrail, ISheetDef, FormulaReference } from '@alaarab/ogrid-core';
|
|
5
5
|
/** Base props shared by both client-side and server-side OGrid modes. */
|
|
6
6
|
interface IOGridBaseProps<T> {
|
|
7
7
|
columns: (IColumnDef<T> | IColumnGroupDef<T>)[];
|
|
@@ -105,6 +105,14 @@ interface IOGridBaseProps<T> {
|
|
|
105
105
|
namedRanges?: Record<string, string>;
|
|
106
106
|
/** Sheet accessors for cross-sheet formula references (e.g. { Sheet2: accessor }). */
|
|
107
107
|
sheets?: Record<string, IGridDataAccessor>;
|
|
108
|
+
/** Sheet definitions for the tab bar at grid bottom. */
|
|
109
|
+
sheetDefs?: ISheetDef[];
|
|
110
|
+
/** Active sheet ID (controlled). */
|
|
111
|
+
activeSheet?: string;
|
|
112
|
+
/** Called when user clicks a sheet tab. */
|
|
113
|
+
onSheetChange?: (sheetId: string) => void;
|
|
114
|
+
/** Called when user clicks the "+" add sheet button. */
|
|
115
|
+
onSheetAdd?: () => void;
|
|
108
116
|
'aria-label'?: string;
|
|
109
117
|
'aria-labelledby'?: string;
|
|
110
118
|
}
|
|
@@ -215,4 +223,8 @@ export interface IOGridDataGridProps<T> {
|
|
|
215
223
|
getDependents?: (col: number, row: number) => IAuditEntry[];
|
|
216
224
|
/** Get full audit trail for a cell. */
|
|
217
225
|
getAuditTrail?: (col: number, row: number) => IAuditTrail | null;
|
|
226
|
+
/** Monotonic counter incremented on each formula recalculation — used for cache invalidation. */
|
|
227
|
+
formulaVersion?: number;
|
|
228
|
+
/** Cell references to highlight (from active formula in formula bar). */
|
|
229
|
+
formulaReferences?: FormulaReference[];
|
|
218
230
|
}
|
|
@@ -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, } 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, 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-vue",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"description": "OGrid Vue – Vue 3 composables, headless components, and utilities for OGrid data grids.",
|
|
5
5
|
"main": "dist/esm/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"node": ">=18"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@alaarab/ogrid-core": "2.
|
|
39
|
+
"@alaarab/ogrid-core": "2.4.1"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"vue": "^3.3.0"
|