@canvas-components/pivot-table 0.1.7 → 0.1.8
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/index.cjs +431 -96
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -2
- package/dist/index.d.ts +30 -2
- package/dist/index.js +431 -96
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2592,22 +2592,6 @@ function createPivotDomHost(container) {
|
|
|
2592
2592
|
}
|
|
2593
2593
|
};
|
|
2594
2594
|
}
|
|
2595
|
-
async function writePivotClipboardText(text, ownerDocument) {
|
|
2596
|
-
const syncCopied = copyTextSync(text, ownerDocument);
|
|
2597
|
-
logPivotClipboard("sync-copy-result", { copied: syncCopied });
|
|
2598
|
-
if (syncCopied) return true;
|
|
2599
|
-
const copied = await copyText(text, ownerDocument);
|
|
2600
|
-
logPivotClipboard("copy-result", { copied });
|
|
2601
|
-
return copied;
|
|
2602
|
-
}
|
|
2603
|
-
function copyPivotClipboardTextSync(text, ownerDocument) {
|
|
2604
|
-
const copied = copyTextSync(text, ownerDocument);
|
|
2605
|
-
logPivotClipboard("sync-copy-result", { copied });
|
|
2606
|
-
return copied;
|
|
2607
|
-
}
|
|
2608
|
-
function logPivotClipboard(stage, detail) {
|
|
2609
|
-
console.info(`[PivotTable:clipboard] ${stage}`, detail);
|
|
2610
|
-
}
|
|
2611
2595
|
|
|
2612
2596
|
// src/adapters/canvas-host.ts
|
|
2613
2597
|
function resizePivotCanvas(canvas, width, height) {
|
|
@@ -2972,7 +2956,7 @@ function renderPivotTable(params) {
|
|
|
2972
2956
|
});
|
|
2973
2957
|
withClip(context, layout.cornerRect, () => {
|
|
2974
2958
|
fillRect(context, layout.cornerRect, theme.cornerBackgroundColor);
|
|
2975
|
-
drawCorner(context, layout, theme);
|
|
2959
|
+
drawCorner(context, layout, theme, params.selection?.textSelection);
|
|
2976
2960
|
});
|
|
2977
2961
|
withClip(context, layout.rowHeaderRect, () => {
|
|
2978
2962
|
layout.rowHeaderCells.forEach((cell) => {
|
|
@@ -2986,7 +2970,9 @@ function renderPivotTable(params) {
|
|
|
2986
2970
|
cell,
|
|
2987
2971
|
theme,
|
|
2988
2972
|
!areaSelection && isHeaderSelected(cell, selectionPathKeys.row),
|
|
2989
|
-
contentRect
|
|
2973
|
+
contentRect,
|
|
2974
|
+
void 0,
|
|
2975
|
+
params.selection?.textSelection
|
|
2990
2976
|
);
|
|
2991
2977
|
});
|
|
2992
2978
|
layout.rowHeaderCells.forEach(
|
|
@@ -3006,7 +2992,10 @@ function renderPivotTable(params) {
|
|
|
3006
2992
|
context,
|
|
3007
2993
|
cell,
|
|
3008
2994
|
theme,
|
|
3009
|
-
!areaSelection && isHeaderSelected(cell, selectionPathKeys.column)
|
|
2995
|
+
!areaSelection && isHeaderSelected(cell, selectionPathKeys.column),
|
|
2996
|
+
cell.rect,
|
|
2997
|
+
void 0,
|
|
2998
|
+
params.selection?.textSelection
|
|
3010
2999
|
)
|
|
3011
3000
|
);
|
|
3012
3001
|
layout.columnHeaderCells.forEach(
|
|
@@ -3041,7 +3030,8 @@ function renderPivotTable(params) {
|
|
|
3041
3030
|
activeNodePathKey
|
|
3042
3031
|
)
|
|
3043
3032
|
},
|
|
3044
|
-
visibleIndicatorMaxima.get(cell.indicatorKey) ?? 0
|
|
3033
|
+
visibleIndicatorMaxima.get(cell.indicatorKey) ?? 0,
|
|
3034
|
+
params.selection?.textSelection
|
|
3045
3035
|
)
|
|
3046
3036
|
);
|
|
3047
3037
|
layout.bodyCells.forEach(
|
|
@@ -3182,7 +3172,7 @@ function drawReportFilterCell(context, cell, theme) {
|
|
|
3182
3172
|
skipRight: true
|
|
3183
3173
|
});
|
|
3184
3174
|
}
|
|
3185
|
-
function drawCorner(context, layout, theme) {
|
|
3175
|
+
function drawCorner(context, layout, theme, textSelection) {
|
|
3186
3176
|
layout.rowFieldHeaderCells.forEach(
|
|
3187
3177
|
(cell) => drawHeaderCell(
|
|
3188
3178
|
context,
|
|
@@ -3190,7 +3180,8 @@ function drawCorner(context, layout, theme) {
|
|
|
3190
3180
|
theme,
|
|
3191
3181
|
false,
|
|
3192
3182
|
cell.rect,
|
|
3193
|
-
theme.cornerBackgroundColor
|
|
3183
|
+
theme.cornerBackgroundColor,
|
|
3184
|
+
textSelection
|
|
3194
3185
|
)
|
|
3195
3186
|
);
|
|
3196
3187
|
if (layout.rowFieldHeaderCells.length === 0) {
|
|
@@ -3207,7 +3198,7 @@ function drawCorner(context, layout, theme) {
|
|
|
3207
3198
|
})
|
|
3208
3199
|
);
|
|
3209
3200
|
}
|
|
3210
|
-
function drawHeaderCell(context, cell, theme, selected, contentRect = cell.rect, backgroundColor) {
|
|
3201
|
+
function drawHeaderCell(context, cell, theme, selected, contentRect = cell.rect, backgroundColor, textSelection) {
|
|
3211
3202
|
const background = backgroundColor ?? (selected ? theme.selectionBackgroundColor : cell.kind === "grandTotal" ? theme.grandTotalBackgroundColor : cell.kind === "subtotal" ? theme.subtotalBackgroundColor : cell.axis === "row" ? theme.rowHeaderBackgroundColor : theme.columnHeaderBackgroundColor);
|
|
3212
3203
|
fillRect(context, cell.rect, background);
|
|
3213
3204
|
const iconPadding = cell.expandable ? 18 : 0;
|
|
@@ -3229,6 +3220,13 @@ function drawHeaderCell(context, cell, theme, selected, contentRect = cell.rect,
|
|
|
3229
3220
|
cell.filterable ? 32 : 10
|
|
3230
3221
|
);
|
|
3231
3222
|
}
|
|
3223
|
+
drawHeaderTextSelectionBackground(
|
|
3224
|
+
context,
|
|
3225
|
+
cell,
|
|
3226
|
+
contentRect,
|
|
3227
|
+
textSelection,
|
|
3228
|
+
theme.fontSize
|
|
3229
|
+
);
|
|
3232
3230
|
drawText(
|
|
3233
3231
|
context,
|
|
3234
3232
|
cell.label,
|
|
@@ -3241,13 +3239,46 @@ function drawHeaderCell(context, cell, theme, selected, contentRect = cell.rect,
|
|
|
3241
3239
|
cell.align ?? "left"
|
|
3242
3240
|
);
|
|
3243
3241
|
}
|
|
3242
|
+
function drawHeaderTextSelectionBackground(context, cell, contentRect, selection, fontSize) {
|
|
3243
|
+
if (!selection) return;
|
|
3244
|
+
const index = selection.fragments.findIndex(
|
|
3245
|
+
(fragment) => fragment.region === "header" && fragment.key === `header:${cell.axis}:${cell.nodeId ?? ""}:${cell.label}`
|
|
3246
|
+
);
|
|
3247
|
+
if (index < 0) return;
|
|
3248
|
+
const range = resolveTextSelectionRange(selection, index, cell.label.length);
|
|
3249
|
+
if (!range) return;
|
|
3250
|
+
const width = context.measureText(cell.label).width;
|
|
3251
|
+
const align = cell.align ?? "left";
|
|
3252
|
+
const origin = align === "right" ? contentRect.x + contentRect.width - 10 - width : align === "center" ? contentRect.x + contentRect.width / 2 - width / 2 : contentRect.x + 10 + (cell.expandable ? 18 : 0);
|
|
3253
|
+
context.save();
|
|
3254
|
+
context.fillStyle = "#99c2ff";
|
|
3255
|
+
context.fillRect(
|
|
3256
|
+
origin + context.measureText(cell.label.slice(0, range.start)).width,
|
|
3257
|
+
contentRect.y + (contentRect.height - fontSize) / 2,
|
|
3258
|
+
context.measureText(cell.label.slice(range.start, range.end)).width,
|
|
3259
|
+
fontSize
|
|
3260
|
+
);
|
|
3261
|
+
context.restore();
|
|
3262
|
+
}
|
|
3263
|
+
function resolveTextSelectionRange(selection, index, length) {
|
|
3264
|
+
const forward = selection.anchorFragmentIndex <= selection.focusFragmentIndex;
|
|
3265
|
+
const startIndex = forward ? selection.anchorFragmentIndex : selection.focusFragmentIndex;
|
|
3266
|
+
const endIndex = forward ? selection.focusFragmentIndex : selection.anchorFragmentIndex;
|
|
3267
|
+
if (index < startIndex || index > endIndex) return null;
|
|
3268
|
+
const start = index === startIndex ? forward ? selection.anchorOffset : selection.focusOffset : 0;
|
|
3269
|
+
const end = index === endIndex ? forward ? selection.focusOffset : selection.anchorOffset : length;
|
|
3270
|
+
return {
|
|
3271
|
+
start: Math.max(0, Math.min(start, length)),
|
|
3272
|
+
end: Math.max(0, Math.min(end, length))
|
|
3273
|
+
};
|
|
3274
|
+
}
|
|
3244
3275
|
function isHeaderSelected(cell, selectedPathKey) {
|
|
3245
3276
|
if (!selectedPathKey || !cell.nodeId) {
|
|
3246
3277
|
return false;
|
|
3247
3278
|
}
|
|
3248
3279
|
return Boolean(isPathRelated2(selectedPathKey, cell.pathKey));
|
|
3249
3280
|
}
|
|
3250
|
-
function drawBodyCell(context, cell, options, theme, state, visibleMaximum) {
|
|
3281
|
+
function drawBodyCell(context, cell, options, theme, state, visibleMaximum, textSelection) {
|
|
3251
3282
|
const indicator = options.indicators.find(
|
|
3252
3283
|
(item) => item.key === cell.indicatorKey
|
|
3253
3284
|
);
|
|
@@ -3277,15 +3308,54 @@ function drawBodyCell(context, cell, options, theme, state, visibleMaximum) {
|
|
|
3277
3308
|
"#3370ff"
|
|
3278
3309
|
);
|
|
3279
3310
|
}
|
|
3311
|
+
const text = resolveBodyDisplayText(cell, indicator);
|
|
3312
|
+
const padding = 10;
|
|
3313
|
+
const align = indicator?.align ?? "right";
|
|
3314
|
+
drawTextSelectionBackground(
|
|
3315
|
+
context,
|
|
3316
|
+
cell,
|
|
3317
|
+
text,
|
|
3318
|
+
align,
|
|
3319
|
+
padding,
|
|
3320
|
+
textSelection,
|
|
3321
|
+
theme.fontSize
|
|
3322
|
+
);
|
|
3280
3323
|
drawText(
|
|
3281
3324
|
context,
|
|
3282
|
-
|
|
3325
|
+
text,
|
|
3283
3326
|
cell.rect,
|
|
3284
3327
|
theme.textColor,
|
|
3285
3328
|
10,
|
|
3286
3329
|
indicator?.align ?? "right"
|
|
3287
3330
|
);
|
|
3288
3331
|
}
|
|
3332
|
+
function drawTextSelectionBackground(context, cell, text, align, padding, selection, fontSize) {
|
|
3333
|
+
if (!selection) return;
|
|
3334
|
+
const index = selection.fragments.findIndex(
|
|
3335
|
+
(fragment) => fragment.rowIndex === cell.rowIndex && fragment.columnIndex === cell.columnIndex && fragment.text === text
|
|
3336
|
+
);
|
|
3337
|
+
if (index < 0) return;
|
|
3338
|
+
const forward = selection.anchorFragmentIndex < selection.focusFragmentIndex || selection.anchorFragmentIndex === selection.focusFragmentIndex && selection.anchorOffset <= selection.focusOffset;
|
|
3339
|
+
const startIndex = forward ? selection.anchorFragmentIndex : selection.focusFragmentIndex;
|
|
3340
|
+
const endIndex = forward ? selection.focusFragmentIndex : selection.anchorFragmentIndex;
|
|
3341
|
+
if (index < startIndex || index > endIndex) return;
|
|
3342
|
+
const start = index === startIndex ? forward ? selection.anchorOffset : selection.focusOffset : 0;
|
|
3343
|
+
const end = index === endIndex ? forward ? selection.focusOffset : selection.anchorOffset : text.length;
|
|
3344
|
+
if (start >= end) return;
|
|
3345
|
+
const availableWidth = Math.max(cell.rect.width - padding * 2, 0);
|
|
3346
|
+
const shown = truncateText(context, text, availableWidth);
|
|
3347
|
+
const textWidth = context.measureText(shown).width;
|
|
3348
|
+
const origin = align === "right" ? cell.rect.x + cell.rect.width - padding - textWidth : align === "center" ? cell.rect.x + cell.rect.width / 2 - textWidth / 2 : cell.rect.x + padding;
|
|
3349
|
+
context.save();
|
|
3350
|
+
context.fillStyle = "#99c2ff";
|
|
3351
|
+
context.fillRect(
|
|
3352
|
+
origin + context.measureText(shown.slice(0, start)).width,
|
|
3353
|
+
cell.rect.y + (cell.rect.height - fontSize) / 2,
|
|
3354
|
+
context.measureText(shown.slice(start, end)).width,
|
|
3355
|
+
fontSize
|
|
3356
|
+
);
|
|
3357
|
+
context.restore();
|
|
3358
|
+
}
|
|
3289
3359
|
function resolveSelectionPathKeys(layout, selection, activeNodePathKey) {
|
|
3290
3360
|
const activeNode = selection?.activeNode;
|
|
3291
3361
|
if (activeNode) {
|
|
@@ -3574,6 +3644,61 @@ function contains(rect, x, y) {
|
|
|
3574
3644
|
return x >= rect.x && x < rect.x + rect.width && y >= rect.y && y < rect.y + rect.height;
|
|
3575
3645
|
}
|
|
3576
3646
|
|
|
3647
|
+
// src/interaction/text-selection.ts
|
|
3648
|
+
function resolvePivotTextOffset(params) {
|
|
3649
|
+
const boundaries = [0];
|
|
3650
|
+
let offset = 0;
|
|
3651
|
+
for (const character of params.text) {
|
|
3652
|
+
offset += character.length;
|
|
3653
|
+
boundaries.push(offset);
|
|
3654
|
+
}
|
|
3655
|
+
const relativeX = params.pointerX - params.textOriginX;
|
|
3656
|
+
if (relativeX <= 0 || boundaries.length === 1) return 0;
|
|
3657
|
+
if (relativeX >= params.measureText(params.text)) return params.text.length;
|
|
3658
|
+
let low = 1;
|
|
3659
|
+
let high = boundaries.length - 1;
|
|
3660
|
+
while (low < high) {
|
|
3661
|
+
const middle = Math.floor((low + high) / 2);
|
|
3662
|
+
const boundary = boundaries[middle] ?? params.text.length;
|
|
3663
|
+
if (params.measureText(params.text.slice(0, boundary)) < relativeX) {
|
|
3664
|
+
low = middle + 1;
|
|
3665
|
+
} else {
|
|
3666
|
+
high = middle;
|
|
3667
|
+
}
|
|
3668
|
+
}
|
|
3669
|
+
const end = boundaries[low] ?? params.text.length;
|
|
3670
|
+
const start = boundaries[Math.max(low - 1, 0)] ?? 0;
|
|
3671
|
+
const startWidth = params.measureText(params.text.slice(0, start));
|
|
3672
|
+
const endWidth = params.measureText(params.text.slice(0, end));
|
|
3673
|
+
return relativeX - startWidth <= endWidth - relativeX ? start : end;
|
|
3674
|
+
}
|
|
3675
|
+
function getPivotSelectedText(selection) {
|
|
3676
|
+
const textSelection = selection.textSelection;
|
|
3677
|
+
if (!textSelection) return null;
|
|
3678
|
+
const forward = textSelection.anchorFragmentIndex < textSelection.focusFragmentIndex || textSelection.anchorFragmentIndex === textSelection.focusFragmentIndex && textSelection.anchorOffset <= textSelection.focusOffset;
|
|
3679
|
+
const startIndex = forward ? textSelection.anchorFragmentIndex : textSelection.focusFragmentIndex;
|
|
3680
|
+
const endIndex = forward ? textSelection.focusFragmentIndex : textSelection.anchorFragmentIndex;
|
|
3681
|
+
const startOffset = forward ? textSelection.anchorOffset : textSelection.focusOffset;
|
|
3682
|
+
const endOffset = forward ? textSelection.focusOffset : textSelection.anchorOffset;
|
|
3683
|
+
const selected = textSelection.fragments.slice(startIndex, endIndex + 1).map((fragment, index) => {
|
|
3684
|
+
const absoluteIndex = startIndex + index;
|
|
3685
|
+
const start = absoluteIndex === startIndex ? startOffset : 0;
|
|
3686
|
+
const end = absoluteIndex === endIndex ? endOffset : fragment.text.length;
|
|
3687
|
+
return {
|
|
3688
|
+
fragment,
|
|
3689
|
+
text: fragment.text.slice(
|
|
3690
|
+
Math.max(0, Math.min(start, fragment.text.length)),
|
|
3691
|
+
Math.max(0, Math.min(end, fragment.text.length))
|
|
3692
|
+
)
|
|
3693
|
+
};
|
|
3694
|
+
});
|
|
3695
|
+
return selected.reduce((result, item, index) => {
|
|
3696
|
+
const previous = selected[index - 1]?.fragment;
|
|
3697
|
+
const separator = previous ? previous.rowIndex === item.fragment.rowIndex ? " " : "\n" : "";
|
|
3698
|
+
return `${result}${separator}${item.text}`;
|
|
3699
|
+
}, "") || null;
|
|
3700
|
+
}
|
|
3701
|
+
|
|
3577
3702
|
// src/features/clipboard/pivot-selection-copy.ts
|
|
3578
3703
|
function createPivotSelectionText(params) {
|
|
3579
3704
|
const activeNode = params.selection.activeNode;
|
|
@@ -3877,6 +4002,8 @@ var PivotTable = class {
|
|
|
3877
4002
|
__publicField(this, "suppressNextClick", false);
|
|
3878
4003
|
__publicField(this, "scrollbarDrag", null);
|
|
3879
4004
|
__publicField(this, "cellSelectionDrag", null);
|
|
4005
|
+
__publicField(this, "textSelectionDrag", null);
|
|
4006
|
+
__publicField(this, "headerTextSelectionDrag", null);
|
|
3880
4007
|
__publicField(this, "rowHeaderSelectionDrag", null);
|
|
3881
4008
|
__publicField(this, "handlePointerMove", (event) => {
|
|
3882
4009
|
if (this.scrollbarDrag) {
|
|
@@ -3897,10 +4024,22 @@ var PivotTable = class {
|
|
|
3897
4024
|
return;
|
|
3898
4025
|
}
|
|
3899
4026
|
if (this.cellSelectionDrag?.pointerId === event.pointerId) {
|
|
4027
|
+
if (this.textSelectionDrag?.pointerId === event.pointerId) {
|
|
4028
|
+
this.updateTextSelectionDrag(event);
|
|
4029
|
+
if (this.textSelectionDrag.dragged) return;
|
|
4030
|
+
}
|
|
3900
4031
|
this.updateCellSelectionDrag(event);
|
|
3901
4032
|
return;
|
|
3902
4033
|
}
|
|
4034
|
+
if (this.headerTextSelectionDrag?.pointerId === event.pointerId) {
|
|
4035
|
+
this.updateHeaderTextSelectionDrag(event);
|
|
4036
|
+
return;
|
|
4037
|
+
}
|
|
3903
4038
|
if (this.rowHeaderSelectionDrag?.pointerId === event.pointerId) {
|
|
4039
|
+
if (this.headerTextSelectionDrag?.pointerId === event.pointerId) {
|
|
4040
|
+
this.updateHeaderTextSelectionDrag(event);
|
|
4041
|
+
if (this.headerTextSelectionDrag.dragged) return;
|
|
4042
|
+
}
|
|
3904
4043
|
this.updateRowHeaderSelectionDrag(event);
|
|
3905
4044
|
return;
|
|
3906
4045
|
}
|
|
@@ -3947,6 +4086,7 @@ var PivotTable = class {
|
|
|
3947
4086
|
this.openReportFilterPanel(hit.reportFilterCell);
|
|
3948
4087
|
return;
|
|
3949
4088
|
}
|
|
4089
|
+
if (hit.reportFilterCell) return;
|
|
3950
4090
|
if (hit.bodyCell) {
|
|
3951
4091
|
this.selectCell(toCellAddress(hit.bodyCell), event.shiftKey);
|
|
3952
4092
|
return;
|
|
@@ -3988,52 +4128,20 @@ var PivotTable = class {
|
|
|
3988
4128
|
this.scheduleRender();
|
|
3989
4129
|
return;
|
|
3990
4130
|
});
|
|
3991
|
-
__publicField(this, "
|
|
3992
|
-
const root = this.host?.root;
|
|
3993
|
-
const activeElement = this.container.ownerDocument.activeElement;
|
|
3994
|
-
const belongsToTable = Boolean(
|
|
3995
|
-
root && (activeElement === root || activeElement instanceof Element && root.contains(activeElement))
|
|
3996
|
-
);
|
|
4131
|
+
__publicField(this, "handleKeyDown", (event) => {
|
|
3997
4132
|
const isCopyShortcut = (event.ctrlKey || event.metaKey) && !event.altKey && (event.key.toLocaleLowerCase() === "c" || event.code === "KeyC");
|
|
3998
4133
|
if (isCopyShortcut) {
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
ctrlKey: event.ctrlKey,
|
|
4004
|
-
metaKey: event.metaKey,
|
|
4005
|
-
defaultPrevented: event.defaultPrevented,
|
|
4006
|
-
activeElement: describeElement(activeElement),
|
|
4007
|
-
eventTarget: describeElement(event.target),
|
|
4008
|
-
protocol: this.container.ownerDocument.location?.protocol ?? "unknown",
|
|
4009
|
-
isSecureContext: this.container.ownerDocument.defaultView?.isSecureContext ?? false
|
|
4010
|
-
});
|
|
4011
|
-
}
|
|
4012
|
-
if (!belongsToTable) return;
|
|
4013
|
-
if (isCopyShortcut) {
|
|
4014
|
-
const text = this.createSelectionTsv();
|
|
4015
|
-
const selection = this.core?.getSelection() ?? null;
|
|
4016
|
-
logPivotClipboard("selection-resolved", {
|
|
4017
|
-
hasLayout: Boolean(this.layout),
|
|
4018
|
-
selection,
|
|
4019
|
-
textLength: text.length,
|
|
4020
|
-
textPreview: text.slice(0, 120)
|
|
4021
|
-
});
|
|
4134
|
+
const text = getPivotSelectedText(
|
|
4135
|
+
this.core?.getSelection() ?? {
|
|
4136
|
+
}
|
|
4137
|
+
) ?? this.createSelectionTsv();
|
|
4022
4138
|
if (!text) {
|
|
4023
|
-
logPivotClipboard("copy-aborted", { reason: "empty-selection-text" });
|
|
4024
4139
|
return;
|
|
4025
4140
|
}
|
|
4026
4141
|
event.preventDefault();
|
|
4027
|
-
const
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
);
|
|
4031
|
-
if (!copied) {
|
|
4032
|
-
void writePivotClipboardText(text, this.container.ownerDocument).then(
|
|
4033
|
-
(fallbackCopied) => logPivotClipboard("fallback-complete", {
|
|
4034
|
-
copied: fallbackCopied
|
|
4035
|
-
})
|
|
4036
|
-
);
|
|
4142
|
+
const ownerDocument = this.host?.canvas.ownerDocument ?? globalThis.document;
|
|
4143
|
+
if (!copyTextSync(text, ownerDocument)) {
|
|
4144
|
+
void copyText(text, ownerDocument);
|
|
4037
4145
|
}
|
|
4038
4146
|
return;
|
|
4039
4147
|
}
|
|
@@ -4046,16 +4154,6 @@ var PivotTable = class {
|
|
|
4046
4154
|
event.preventDefault();
|
|
4047
4155
|
this.selectCell(next, event.shiftKey);
|
|
4048
4156
|
});
|
|
4049
|
-
__publicField(this, "handleCopy", (event) => {
|
|
4050
|
-
const text = this.createSelectionTsv();
|
|
4051
|
-
logPivotClipboard("copy-event", {
|
|
4052
|
-
textLength: text.length,
|
|
4053
|
-
hasClipboardData: Boolean(event.clipboardData)
|
|
4054
|
-
});
|
|
4055
|
-
if (!text) return;
|
|
4056
|
-
event.preventDefault();
|
|
4057
|
-
event.clipboardData?.setData("text/plain", text);
|
|
4058
|
-
});
|
|
4059
4157
|
__publicField(this, "handleWheel", (event) => {
|
|
4060
4158
|
if (!this.layout) return;
|
|
4061
4159
|
const delta = resolvePivotWheelScrollDelta({
|
|
@@ -4127,13 +4225,13 @@ var PivotTable = class {
|
|
|
4127
4225
|
endColumnIndex: hit.bodyCell.columnIndex
|
|
4128
4226
|
}) : "";
|
|
4129
4227
|
if (text) {
|
|
4130
|
-
|
|
4228
|
+
this.copyPivotText(text);
|
|
4131
4229
|
}
|
|
4132
4230
|
},
|
|
4133
4231
|
onCopySelection: selectionRange ? () => {
|
|
4134
4232
|
const text = this.createSelectionTsv();
|
|
4135
4233
|
if (text) {
|
|
4136
|
-
|
|
4234
|
+
this.copyPivotText(text);
|
|
4137
4235
|
}
|
|
4138
4236
|
} : void 0,
|
|
4139
4237
|
customSelection: {
|
|
@@ -4156,7 +4254,7 @@ var PivotTable = class {
|
|
|
4156
4254
|
endColumnIndex: range.endColumn - 1
|
|
4157
4255
|
});
|
|
4158
4256
|
if (text) {
|
|
4159
|
-
|
|
4257
|
+
this.copyPivotText(text);
|
|
4160
4258
|
}
|
|
4161
4259
|
},
|
|
4162
4260
|
onExportCsv: () => downloadBlob(
|
|
@@ -4188,6 +4286,24 @@ var PivotTable = class {
|
|
|
4188
4286
|
const address = toCellAddress(cellHit.bodyCell);
|
|
4189
4287
|
this.host.root.focus({ preventScroll: true });
|
|
4190
4288
|
const selection = this.selectCell(address, event.shiftKey);
|
|
4289
|
+
const text = this.resolveBodyText(cellHit.bodyCell);
|
|
4290
|
+
const textOriginX = this.resolveBodyTextOriginX(cellHit.bodyCell, text);
|
|
4291
|
+
const anchorOffset = text ? resolvePivotTextOffset({
|
|
4292
|
+
text,
|
|
4293
|
+
pointerX: event.clientX - this.host.root.getBoundingClientRect().left,
|
|
4294
|
+
textOriginX,
|
|
4295
|
+
measureText: (value) => this.measurePivotText(value)
|
|
4296
|
+
}) : 0;
|
|
4297
|
+
const anchorFragmentIndex = this.resolveTextFragmentIndex(
|
|
4298
|
+
`body:${cellHit.bodyCell.rowIndex}:${cellHit.bodyCell.columnIndex}`,
|
|
4299
|
+
this.createTextSelectionFragments("column")
|
|
4300
|
+
);
|
|
4301
|
+
this.textSelectionDrag = text ? {
|
|
4302
|
+
pointerId: event.pointerId,
|
|
4303
|
+
anchorFragmentIndex,
|
|
4304
|
+
anchorOffset,
|
|
4305
|
+
dragged: false
|
|
4306
|
+
} : null;
|
|
4191
4307
|
this.cellSelectionDrag = {
|
|
4192
4308
|
pointerId: event.pointerId,
|
|
4193
4309
|
anchor: selection?.anchorCell ?? address,
|
|
@@ -4199,6 +4315,37 @@ var PivotTable = class {
|
|
|
4199
4315
|
this.suppressNextClick = true;
|
|
4200
4316
|
return;
|
|
4201
4317
|
}
|
|
4318
|
+
if (cellHit?.headerCell && !cellHit.onExpandIcon && !cellHit.onFilterIcon && !cellHit.onSortIcon) {
|
|
4319
|
+
const header = cellHit.headerCell;
|
|
4320
|
+
const text = header.label;
|
|
4321
|
+
const rootRect2 = this.host.root.getBoundingClientRect();
|
|
4322
|
+
const originX = header.rect.x + 10 + (header.expandable ? 18 : 0);
|
|
4323
|
+
const fragments = this.createTextSelectionFragments(header.axis);
|
|
4324
|
+
const key = `header:${header.axis}:${header.nodeId ?? ""}:${header.label}`;
|
|
4325
|
+
const anchorFragmentIndex = fragments.findIndex(
|
|
4326
|
+
(fragment) => fragment.key === key
|
|
4327
|
+
);
|
|
4328
|
+
this.host.root.focus({ preventScroll: true });
|
|
4329
|
+
if (header.nodeId) {
|
|
4330
|
+
this.selectNode(header.axis, header.nodeId);
|
|
4331
|
+
}
|
|
4332
|
+
this.textSelectionDrag = null;
|
|
4333
|
+
this.headerTextSelectionDrag = {
|
|
4334
|
+
pointerId: event.pointerId,
|
|
4335
|
+
fragments,
|
|
4336
|
+
anchorFragmentIndex: Math.max(anchorFragmentIndex, 0),
|
|
4337
|
+
anchorOffset: resolvePivotTextOffset({
|
|
4338
|
+
text,
|
|
4339
|
+
pointerX: event.clientX - rootRect2.left,
|
|
4340
|
+
textOriginX: originX,
|
|
4341
|
+
measureText: (value) => this.measurePivotText(value)
|
|
4342
|
+
}),
|
|
4343
|
+
dragged: false
|
|
4344
|
+
};
|
|
4345
|
+
event.preventDefault();
|
|
4346
|
+
this.host.root.setPointerCapture(event.pointerId);
|
|
4347
|
+
return;
|
|
4348
|
+
}
|
|
4202
4349
|
if (cellHit?.region === "rowHeader" && cellHit.headerCell && !cellHit.onExpandIcon && !cellHit.onFilterIcon && !cellHit.onSortIcon) {
|
|
4203
4350
|
const rootRect2 = this.host.root.getBoundingClientRect();
|
|
4204
4351
|
const rowIndex = resolvePivotRowIndexAtY(
|
|
@@ -4248,6 +4395,14 @@ var PivotTable = class {
|
|
|
4248
4395
|
if (!this.host) return;
|
|
4249
4396
|
const endedCellSelection = this.cellSelectionDrag?.pointerId === event.pointerId;
|
|
4250
4397
|
if (endedCellSelection) this.cellSelectionDrag = null;
|
|
4398
|
+
if (this.textSelectionDrag?.pointerId === event.pointerId) {
|
|
4399
|
+
if (this.textSelectionDrag.dragged) this.suppressNextClick = true;
|
|
4400
|
+
this.textSelectionDrag = null;
|
|
4401
|
+
}
|
|
4402
|
+
if (this.headerTextSelectionDrag?.pointerId === event.pointerId) {
|
|
4403
|
+
if (this.headerTextSelectionDrag.dragged) this.suppressNextClick = true;
|
|
4404
|
+
this.headerTextSelectionDrag = null;
|
|
4405
|
+
}
|
|
4251
4406
|
const endedRowHeaderSelection = this.rowHeaderSelectionDrag?.pointerId === event.pointerId;
|
|
4252
4407
|
if (endedRowHeaderSelection) {
|
|
4253
4408
|
if (this.rowHeaderSelectionDrag?.dragged) this.suppressNextClick = true;
|
|
@@ -4279,12 +4434,7 @@ var PivotTable = class {
|
|
|
4279
4434
|
this.host.root.addEventListener("pointermove", this.handlePointerMove);
|
|
4280
4435
|
this.host.root.addEventListener("pointerleave", this.handlePointerLeave);
|
|
4281
4436
|
this.host.root.addEventListener("click", this.handleClick);
|
|
4282
|
-
this.
|
|
4283
|
-
"keydown",
|
|
4284
|
-
this.handleDocumentKeyDown,
|
|
4285
|
-
true
|
|
4286
|
-
);
|
|
4287
|
-
this.host.root.addEventListener("copy", this.handleCopy);
|
|
4437
|
+
this.host.root.addEventListener("keydown", this.handleKeyDown);
|
|
4288
4438
|
this.host.root.addEventListener("wheel", this.handleWheel, {
|
|
4289
4439
|
passive: false
|
|
4290
4440
|
});
|
|
@@ -4510,12 +4660,7 @@ var PivotTable = class {
|
|
|
4510
4660
|
this.handlePointerLeave
|
|
4511
4661
|
);
|
|
4512
4662
|
this.host?.root.removeEventListener("click", this.handleClick);
|
|
4513
|
-
this.
|
|
4514
|
-
"keydown",
|
|
4515
|
-
this.handleDocumentKeyDown,
|
|
4516
|
-
true
|
|
4517
|
-
);
|
|
4518
|
-
this.host?.root.removeEventListener("copy", this.handleCopy);
|
|
4663
|
+
this.host?.root.removeEventListener("keydown", this.handleKeyDown);
|
|
4519
4664
|
this.host?.root.removeEventListener("wheel", this.handleWheel);
|
|
4520
4665
|
this.host?.root.removeEventListener("contextmenu", this.handleContextMenu);
|
|
4521
4666
|
this.host?.root.removeEventListener("pointerdown", this.handlePointerDown);
|
|
@@ -4627,6 +4772,194 @@ var PivotTable = class {
|
|
|
4627
4772
|
activeNode: null
|
|
4628
4773
|
});
|
|
4629
4774
|
}
|
|
4775
|
+
updateTextSelectionDrag(event) {
|
|
4776
|
+
const drag = this.textSelectionDrag;
|
|
4777
|
+
if (!drag || !this.layout || !this.host) return;
|
|
4778
|
+
const rootRect = this.host.root.getBoundingClientRect();
|
|
4779
|
+
const x = event.clientX - rootRect.left;
|
|
4780
|
+
const y = event.clientY - rootRect.top;
|
|
4781
|
+
const hitResult = hitTestPivotLayout(this.layout, x, y);
|
|
4782
|
+
const hit = hitResult?.bodyCell;
|
|
4783
|
+
const header = hitResult?.headerCell;
|
|
4784
|
+
if (!hit && !header) return;
|
|
4785
|
+
const fragments = this.createTextSelectionFragments(
|
|
4786
|
+
header?.axis ?? "column"
|
|
4787
|
+
);
|
|
4788
|
+
const focusKey = header ? `header:${header.axis}:${header.nodeId ?? ""}:${header.label}` : `body:${hit?.rowIndex}:${hit?.columnIndex}`;
|
|
4789
|
+
const focusIndex = this.resolveTextFragmentIndex(focusKey, fragments);
|
|
4790
|
+
const text = header ? header.label : this.resolveBodyText(hit);
|
|
4791
|
+
if (!text || focusIndex < 0) return;
|
|
4792
|
+
const textOriginX = header ? header.rect.x + 10 + (header.expandable ? 18 : 0) : this.resolveBodyTextOriginX(hit, text);
|
|
4793
|
+
const focusOffset = resolvePivotTextOffset({
|
|
4794
|
+
text,
|
|
4795
|
+
pointerX: x,
|
|
4796
|
+
textOriginX,
|
|
4797
|
+
measureText: (value) => this.measurePivotText(value)
|
|
4798
|
+
});
|
|
4799
|
+
if (focusIndex === drag.anchorFragmentIndex && focusOffset === drag.anchorOffset)
|
|
4800
|
+
return;
|
|
4801
|
+
drag.dragged = true;
|
|
4802
|
+
this.setSelection({
|
|
4803
|
+
activeCell: hit ? toCellAddress(hit) : this.core?.getSelection().activeCell ?? null,
|
|
4804
|
+
anchorCell: this.core?.getSelection().anchorCell ?? (hit ? toCellAddress(hit) : null),
|
|
4805
|
+
ranges: this.core?.getSelection().ranges ?? [],
|
|
4806
|
+
activeNode: null,
|
|
4807
|
+
textSelection: {
|
|
4808
|
+
fragments: fragments.map((fragment) => ({
|
|
4809
|
+
rowIndex: fragment.rowIndex ?? -1,
|
|
4810
|
+
columnIndex: fragment.columnIndex ?? -1,
|
|
4811
|
+
text: fragment.text,
|
|
4812
|
+
region: fragment.key.startsWith("header:") ? "header" : "body",
|
|
4813
|
+
key: fragment.key
|
|
4814
|
+
})),
|
|
4815
|
+
anchorFragmentIndex: drag.anchorFragmentIndex,
|
|
4816
|
+
focusFragmentIndex: focusIndex,
|
|
4817
|
+
anchorOffset: drag.anchorOffset,
|
|
4818
|
+
focusOffset
|
|
4819
|
+
}
|
|
4820
|
+
});
|
|
4821
|
+
}
|
|
4822
|
+
updateHeaderTextSelectionDrag(event) {
|
|
4823
|
+
const drag = this.headerTextSelectionDrag;
|
|
4824
|
+
if (!drag || !this.host || !this.layout) return;
|
|
4825
|
+
const rootRect = this.host.root.getBoundingClientRect();
|
|
4826
|
+
const localX = event.clientX - rootRect.left;
|
|
4827
|
+
const localY = event.clientY - rootRect.top;
|
|
4828
|
+
const hit = hitTestPivotLayout(this.layout, localX, localY);
|
|
4829
|
+
const header = hit?.headerCell;
|
|
4830
|
+
const body = hit?.bodyCell;
|
|
4831
|
+
if (!header && !body) return;
|
|
4832
|
+
const key = header ? `header:${header.axis}:${header.nodeId ?? ""}:${header.label}` : `body:${body?.rowIndex}:${body?.columnIndex}`;
|
|
4833
|
+
const focusFragmentIndex = drag.fragments.findIndex(
|
|
4834
|
+
(fragment) => fragment.key === key
|
|
4835
|
+
);
|
|
4836
|
+
if (focusFragmentIndex < 0) return;
|
|
4837
|
+
const focusFragment = drag.fragments[focusFragmentIndex];
|
|
4838
|
+
const focusOffset = resolvePivotTextOffset({
|
|
4839
|
+
text: focusFragment.text,
|
|
4840
|
+
pointerX: localX,
|
|
4841
|
+
textOriginX: focusFragment.originX,
|
|
4842
|
+
measureText: (value) => this.measurePivotText(value)
|
|
4843
|
+
});
|
|
4844
|
+
if (focusFragmentIndex === drag.anchorFragmentIndex && focusOffset === drag.anchorOffset)
|
|
4845
|
+
return;
|
|
4846
|
+
drag.dragged = true;
|
|
4847
|
+
const selection = this.core?.getSelection();
|
|
4848
|
+
if (!selection) return;
|
|
4849
|
+
this.setSelection({
|
|
4850
|
+
...selection,
|
|
4851
|
+
textSelection: {
|
|
4852
|
+
fragments: drag.fragments.map((fragment) => ({
|
|
4853
|
+
rowIndex: fragment.rowIndex ?? -1,
|
|
4854
|
+
columnIndex: fragment.columnIndex ?? -1,
|
|
4855
|
+
text: fragment.text,
|
|
4856
|
+
region: "header",
|
|
4857
|
+
key: fragment.key
|
|
4858
|
+
})),
|
|
4859
|
+
anchorFragmentIndex: drag.anchorFragmentIndex,
|
|
4860
|
+
focusFragmentIndex,
|
|
4861
|
+
anchorOffset: drag.anchorOffset,
|
|
4862
|
+
focusOffset
|
|
4863
|
+
}
|
|
4864
|
+
});
|
|
4865
|
+
}
|
|
4866
|
+
createTextSelectionFragments(axis) {
|
|
4867
|
+
const bodyFragments = (this.layout?.bodyCells ?? []).map((cell) => ({
|
|
4868
|
+
key: `body:${cell.rowIndex}:${cell.columnIndex}`,
|
|
4869
|
+
text: this.resolveBodyText(cell),
|
|
4870
|
+
originX: this.resolveBodyTextOriginX(cell, this.resolveBodyText(cell)),
|
|
4871
|
+
rowIndex: cell.rowIndex,
|
|
4872
|
+
columnIndex: cell.columnIndex
|
|
4873
|
+
})).filter((fragment) => fragment.text.length > 0);
|
|
4874
|
+
if (this.layout) {
|
|
4875
|
+
const columnHeaders = this.createHeaderTextFragments("column");
|
|
4876
|
+
const rowHeaders = this.layout.rowHeaderCells.filter((cell) => cell.label).map((cell) => ({
|
|
4877
|
+
key: `header:${cell.axis}:${cell.nodeId ?? ""}:${cell.label}`,
|
|
4878
|
+
text: cell.label,
|
|
4879
|
+
rowIndex: void 0,
|
|
4880
|
+
columnIndex: void 0,
|
|
4881
|
+
originX: cell.rect.x + 10
|
|
4882
|
+
}));
|
|
4883
|
+
const rows = Array.from(
|
|
4884
|
+
{ length: this.layout.rowSlots.length },
|
|
4885
|
+
(_, rowIndex) => [
|
|
4886
|
+
rowHeaders[rowIndex],
|
|
4887
|
+
...bodyFragments.filter((fragment) => fragment.rowIndex === rowIndex)
|
|
4888
|
+
]
|
|
4889
|
+
).flat();
|
|
4890
|
+
if (axis === "column") {
|
|
4891
|
+
return [...columnHeaders, ...rows].filter(
|
|
4892
|
+
(fragment) => Boolean(fragment)
|
|
4893
|
+
);
|
|
4894
|
+
}
|
|
4895
|
+
const rowHeadersTitle = this.layout.rowFieldHeaderCells.filter((cell) => cell.label).map((cell) => ({
|
|
4896
|
+
key: `header:${cell.axis}:${cell.nodeId ?? ""}:${cell.label}`,
|
|
4897
|
+
text: cell.label,
|
|
4898
|
+
rowIndex: void 0,
|
|
4899
|
+
columnIndex: void 0,
|
|
4900
|
+
originX: cell.rect.x + 10 + (cell.expandable ? 18 : 0)
|
|
4901
|
+
}));
|
|
4902
|
+
return [...rowHeadersTitle, ...columnHeaders, ...rows].filter(
|
|
4903
|
+
(fragment) => Boolean(fragment)
|
|
4904
|
+
);
|
|
4905
|
+
}
|
|
4906
|
+
return [...this.createHeaderTextFragments(axis), ...bodyFragments];
|
|
4907
|
+
}
|
|
4908
|
+
createHeaderTextFragments(axis) {
|
|
4909
|
+
if (!this.layout) return [];
|
|
4910
|
+
return (axis === "column" ? this.layout.columnHeaderCells : [...this.layout.rowHeaderCells, ...this.layout.rowFieldHeaderCells]).filter((cell) => cell.label).map((cell) => ({
|
|
4911
|
+
key: `header:${cell.axis}:${cell.nodeId ?? ""}:${cell.label}`,
|
|
4912
|
+
text: cell.label,
|
|
4913
|
+
rowIndex: void 0,
|
|
4914
|
+
columnIndex: void 0,
|
|
4915
|
+
originX: cell.rect.x + 10 + (cell.expandable ? 18 : 0)
|
|
4916
|
+
}));
|
|
4917
|
+
}
|
|
4918
|
+
resolveBodyText(cell) {
|
|
4919
|
+
const indicator = this.options.indicators.find(
|
|
4920
|
+
(item) => item.key === cell.indicatorKey
|
|
4921
|
+
);
|
|
4922
|
+
if (!indicator || indicator.formatter || typeof cell.value !== "number")
|
|
4923
|
+
return cell.formattedValue;
|
|
4924
|
+
if (indicator.cellType === "percent")
|
|
4925
|
+
return `${(cell.value * 100).toFixed(indicator.precision ?? 2)}%`;
|
|
4926
|
+
if (indicator.cellType === "money")
|
|
4927
|
+
return cell.value.toLocaleString("zh-CN", {
|
|
4928
|
+
style: "currency",
|
|
4929
|
+
currency: "CNY",
|
|
4930
|
+
minimumFractionDigits: indicator.precision ?? 2,
|
|
4931
|
+
maximumFractionDigits: indicator.precision ?? 2
|
|
4932
|
+
});
|
|
4933
|
+
return cell.formattedValue;
|
|
4934
|
+
}
|
|
4935
|
+
createBodyTextFragments() {
|
|
4936
|
+
return (this.layout?.bodyCells ?? []).map((cell) => ({
|
|
4937
|
+
rowIndex: cell.rowIndex,
|
|
4938
|
+
columnIndex: cell.columnIndex,
|
|
4939
|
+
text: this.resolveBodyText(cell)
|
|
4940
|
+
})).filter((fragment) => fragment.text.length > 0);
|
|
4941
|
+
}
|
|
4942
|
+
resolveTextFragmentIndex(key, fragments) {
|
|
4943
|
+
return fragments.findIndex((fragment) => fragment.key === key);
|
|
4944
|
+
}
|
|
4945
|
+
resolveBodyFragmentIndex(cell) {
|
|
4946
|
+
if (!this.layout) return -1;
|
|
4947
|
+
return this.layout.bodyCells.slice(0, this.layout.bodyCells.indexOf(cell) + 1).filter((item) => this.resolveBodyText(item).length > 0).length - 1;
|
|
4948
|
+
}
|
|
4949
|
+
resolveBodyTextOriginX(cell, text) {
|
|
4950
|
+
const indicator = this.options.indicators.find(
|
|
4951
|
+
(item) => item.key === cell.indicatorKey
|
|
4952
|
+
);
|
|
4953
|
+
const width = this.measurePivotText(text);
|
|
4954
|
+
const align = indicator?.align ?? "right";
|
|
4955
|
+
return align === "right" ? cell.rect.x + cell.rect.width - 10 - width : align === "center" ? cell.rect.x + cell.rect.width / 2 - width / 2 : cell.rect.x + 10;
|
|
4956
|
+
}
|
|
4957
|
+
measurePivotText(text) {
|
|
4958
|
+
const context = this.host?.canvas.getContext("2d");
|
|
4959
|
+
if (!context) return text.length * 8;
|
|
4960
|
+
context.font = `${this.options.theme?.fontSize ?? 13}px ${this.options.theme?.fontFamily ?? "sans-serif"}`;
|
|
4961
|
+
return context.measureText(text).width;
|
|
4962
|
+
}
|
|
4630
4963
|
updateRowHeaderSelectionDrag(event) {
|
|
4631
4964
|
const drag = this.rowHeaderSelectionDrag;
|
|
4632
4965
|
if (!drag || !this.layout || !this.host) return;
|
|
@@ -4865,6 +5198,14 @@ var PivotTable = class {
|
|
|
4865
5198
|
selection: this.core.getSelection()
|
|
4866
5199
|
});
|
|
4867
5200
|
}
|
|
5201
|
+
/** 复制表格选区文本;同步复制失败时回退到异步实现。 */
|
|
5202
|
+
copyPivotText(text) {
|
|
5203
|
+
if (!text) return;
|
|
5204
|
+
const ownerDocument = this.host?.canvas.ownerDocument ?? globalThis.document;
|
|
5205
|
+
if (!copyTextSync(text, ownerDocument)) {
|
|
5206
|
+
void copyText(text, ownerDocument);
|
|
5207
|
+
}
|
|
5208
|
+
}
|
|
4868
5209
|
scheduleRender() {
|
|
4869
5210
|
if (this.frameId !== null) return;
|
|
4870
5211
|
this.frameId = requestAnimationFrame(() => {
|
|
@@ -4908,12 +5249,6 @@ var PivotTable = class {
|
|
|
4908
5249
|
});
|
|
4909
5250
|
}
|
|
4910
5251
|
};
|
|
4911
|
-
function describeElement(value) {
|
|
4912
|
-
if (!(value instanceof Element)) return String(value);
|
|
4913
|
-
const id = value.id ? `#${value.id}` : "";
|
|
4914
|
-
const className = typeof value.className === "string" && value.className ? `.${value.className.trim().replace(/\s+/g, ".")}` : "";
|
|
4915
|
-
return `${value.tagName.toLocaleLowerCase()}${id}${className}`;
|
|
4916
|
-
}
|
|
4917
5252
|
function toCellAddress(cell) {
|
|
4918
5253
|
return {
|
|
4919
5254
|
rowNodeId: cell.rowNodeId ?? "",
|