@productcloudos/editor 1.0.5 → 1.0.6
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/pc-editor.esm.js +115 -41
- package/dist/pc-editor.esm.js.map +1 -1
- package/dist/pc-editor.js +115 -41
- package/dist/pc-editor.js.map +1 -1
- package/dist/pc-editor.min.js +1 -1
- package/dist/pc-editor.min.js.map +1 -1
- package/dist/types/lib/core/PCEditor.d.ts +15 -0
- package/dist/types/lib/core/PCEditor.d.ts.map +1 -1
- package/dist/types/lib/objects/table/TableObject.d.ts.map +1 -1
- package/dist/types/lib/panes/FormattingPane.d.ts.map +1 -1
- package/dist/types/lib/panes/TablePane.d.ts +4 -2
- package/dist/types/lib/panes/TablePane.d.ts.map +1 -1
- package/dist/types/lib/rendering/CanvasManager.d.ts +1 -0
- package/dist/types/lib/rendering/CanvasManager.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/pc-editor.esm.js
CHANGED
|
@@ -7737,6 +7737,9 @@ class TableObject extends BaseEmbeddedObject {
|
|
|
7737
7737
|
result.mergedCell.markReflowDirty();
|
|
7738
7738
|
}
|
|
7739
7739
|
this.clearSelection();
|
|
7740
|
+
// Focus the anchor (top-left) cell of the merged range
|
|
7741
|
+
const normalized = TableCellMerger.normalizeRange(mergeRange);
|
|
7742
|
+
this.focusCell(normalized.start.row, normalized.start.col);
|
|
7740
7743
|
this.emit('cells-merged', { range: mergeRange });
|
|
7741
7744
|
this.emit('content-changed', {});
|
|
7742
7745
|
}
|
|
@@ -14293,7 +14296,8 @@ class CanvasManager extends EventEmitter {
|
|
|
14293
14296
|
const pageIndex = this.document.pages.findIndex(p => p.id === pageId);
|
|
14294
14297
|
// Get the slice for this page (for multi-page tables)
|
|
14295
14298
|
const slice = table.getRenderedSlice(pageIndex);
|
|
14296
|
-
const tablePosition = slice?.position ||
|
|
14299
|
+
const tablePosition = slice?.position ||
|
|
14300
|
+
(table.renderedPageIndex === pageIndex ? table.renderedPosition : null);
|
|
14297
14301
|
const sliceHeight = slice?.height || table.height;
|
|
14298
14302
|
// Check if point is within the table slice on this page
|
|
14299
14303
|
const isInsideTable = tablePosition &&
|
|
@@ -14326,6 +14330,7 @@ class CanvasManager extends EventEmitter {
|
|
|
14326
14330
|
end: cellAddr
|
|
14327
14331
|
});
|
|
14328
14332
|
this.render();
|
|
14333
|
+
this.emit('table-cell-selection-changed', { table });
|
|
14329
14334
|
e.preventDefault();
|
|
14330
14335
|
return;
|
|
14331
14336
|
}
|
|
@@ -14605,7 +14610,8 @@ class CanvasManager extends EventEmitter {
|
|
|
14605
14610
|
const currentPageIndex = this.document.pages.findIndex(p => p.id === pageId);
|
|
14606
14611
|
// Get the slice for the current page (for multi-page tables)
|
|
14607
14612
|
const slice = table.getRenderedSlice(currentPageIndex);
|
|
14608
|
-
const tablePosition = slice?.position ||
|
|
14613
|
+
const tablePosition = slice?.position ||
|
|
14614
|
+
(table.renderedPageIndex === currentPageIndex ? table.renderedPosition : null);
|
|
14609
14615
|
const sliceHeight = slice?.height || table.height;
|
|
14610
14616
|
if (tablePosition) {
|
|
14611
14617
|
// Check if point is within the table slice on this page
|
|
@@ -14635,6 +14641,7 @@ class CanvasManager extends EventEmitter {
|
|
|
14635
14641
|
end: cellAddr
|
|
14636
14642
|
});
|
|
14637
14643
|
this.render();
|
|
14644
|
+
this.emit('table-cell-selection-changed', { table });
|
|
14638
14645
|
}
|
|
14639
14646
|
}
|
|
14640
14647
|
}
|
|
@@ -15178,40 +15185,46 @@ class CanvasManager extends EventEmitter {
|
|
|
15178
15185
|
canvas.style.cursor = 'move';
|
|
15179
15186
|
return;
|
|
15180
15187
|
}
|
|
15181
|
-
// Show text cursor for
|
|
15182
|
-
if (object instanceof TextBoxObject) {
|
|
15183
|
-
canvas.style.cursor =
|
|
15184
|
-
|
|
15188
|
+
// Show text cursor for objects in edit mode, arrow otherwise
|
|
15189
|
+
if (object instanceof TextBoxObject && this.editingTextBox === object) {
|
|
15190
|
+
canvas.style.cursor = CanvasManager.TEXT_CURSOR;
|
|
15191
|
+
}
|
|
15192
|
+
else if (object instanceof TableObject && this._focusedControl === object) {
|
|
15193
|
+
canvas.style.cursor = CanvasManager.TEXT_CURSOR;
|
|
15185
15194
|
}
|
|
15195
|
+
else {
|
|
15196
|
+
canvas.style.cursor = 'default';
|
|
15197
|
+
}
|
|
15198
|
+
return;
|
|
15186
15199
|
}
|
|
15187
15200
|
}
|
|
15188
15201
|
// Check for table cells (show text cursor)
|
|
15189
15202
|
const tableCellHit = hitTestManager.queryByType(pageIndex, point, 'table-cell');
|
|
15190
15203
|
if (tableCellHit && tableCellHit.data.type === 'table-cell') {
|
|
15191
|
-
canvas.style.cursor =
|
|
15204
|
+
canvas.style.cursor = CanvasManager.TEXT_CURSOR;
|
|
15192
15205
|
return;
|
|
15193
15206
|
}
|
|
15194
15207
|
// Check for text regions (body, header, footer - show text cursor)
|
|
15195
15208
|
const textRegionHit = hitTestManager.queryByType(pageIndex, point, 'text-region');
|
|
15196
15209
|
if (textRegionHit && textRegionHit.data.type === 'text-region') {
|
|
15197
|
-
canvas.style.cursor =
|
|
15210
|
+
canvas.style.cursor = CanvasManager.TEXT_CURSOR;
|
|
15198
15211
|
return;
|
|
15199
15212
|
}
|
|
15200
15213
|
// Also check if point is within any editable region (body, header, footer)
|
|
15201
15214
|
// This catches cases where text region hit targets may not cover empty space
|
|
15202
15215
|
const bodyRegion = this.regionManager.getBodyRegion();
|
|
15203
15216
|
if (bodyRegion && bodyRegion.containsPointInRegion(point, pageIndex)) {
|
|
15204
|
-
canvas.style.cursor =
|
|
15217
|
+
canvas.style.cursor = CanvasManager.TEXT_CURSOR;
|
|
15205
15218
|
return;
|
|
15206
15219
|
}
|
|
15207
15220
|
const headerRegion = this.regionManager.getHeaderRegion();
|
|
15208
15221
|
if (headerRegion && headerRegion.containsPointInRegion(point, pageIndex)) {
|
|
15209
|
-
canvas.style.cursor =
|
|
15222
|
+
canvas.style.cursor = CanvasManager.TEXT_CURSOR;
|
|
15210
15223
|
return;
|
|
15211
15224
|
}
|
|
15212
15225
|
const footerRegion = this.regionManager.getFooterRegion();
|
|
15213
15226
|
if (footerRegion && footerRegion.containsPointInRegion(point, pageIndex)) {
|
|
15214
|
-
canvas.style.cursor =
|
|
15227
|
+
canvas.style.cursor = CanvasManager.TEXT_CURSOR;
|
|
15215
15228
|
return;
|
|
15216
15229
|
}
|
|
15217
15230
|
canvas.style.cursor = 'default';
|
|
@@ -15229,7 +15242,8 @@ class CanvasManager extends EventEmitter {
|
|
|
15229
15242
|
const { table, dividerType, index } = target.data;
|
|
15230
15243
|
// Get the table position from slice info
|
|
15231
15244
|
const slice = table.getRenderedSlice(pageIndex);
|
|
15232
|
-
const tablePosition = slice?.position ||
|
|
15245
|
+
const tablePosition = slice?.position ||
|
|
15246
|
+
(table.renderedPageIndex === pageIndex ? table.renderedPosition : null);
|
|
15233
15247
|
if (tablePosition) {
|
|
15234
15248
|
// Calculate the divider position based on type and index
|
|
15235
15249
|
let position;
|
|
@@ -15957,7 +15971,9 @@ class CanvasManager extends EventEmitter {
|
|
|
15957
15971
|
if (obj instanceof TableObject) {
|
|
15958
15972
|
// For multi-page tables, check if this page has a rendered slice
|
|
15959
15973
|
const slice = obj.getRenderedSlice(pageIndex);
|
|
15960
|
-
|
|
15974
|
+
// Only use renderedPosition if the table was actually rendered on this page
|
|
15975
|
+
const tablePosition = slice?.position ||
|
|
15976
|
+
(obj.renderedPageIndex === pageIndex ? obj.renderedPosition : null);
|
|
15961
15977
|
if (tablePosition) {
|
|
15962
15978
|
// Check if point is inside the table slice on this page
|
|
15963
15979
|
const sliceHeight = slice?.height || obj.height;
|
|
@@ -16201,6 +16217,10 @@ class CanvasManager extends EventEmitter {
|
|
|
16201
16217
|
}
|
|
16202
16218
|
CanvasManager.CELL_SELECTION_THRESHOLD = 5; // Minimum pixels to drag before cell selection starts
|
|
16203
16219
|
CanvasManager.RELATIVE_DRAG_THRESHOLD = 3; // Minimum pixels to drag before moving starts
|
|
16220
|
+
// Custom text cursor as a black I-beam SVG data URI.
|
|
16221
|
+
// The native 'text' cursor can render as white on Windows browsers,
|
|
16222
|
+
// making it invisible over the white canvas background.
|
|
16223
|
+
CanvasManager.TEXT_CURSOR = "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='20' viewBox='0 0 16 20'%3E%3Cpath d='M5 1h2v1h2V1h2v2h-2v6h2v2h-2v6h2v2h-2v-1H7v1H5v-2h2v-6H5V9h2V3H5z' fill='%23000'/%3E%3C/svg%3E\") 8 10, text";
|
|
16204
16224
|
|
|
16205
16225
|
/**
|
|
16206
16226
|
* DataBinder handles binding data to documents.
|
|
@@ -21489,6 +21509,10 @@ class PCEditor extends EventEmitter {
|
|
|
21489
21509
|
this.canvasManager.on('tablecell-cursor-changed', (data) => {
|
|
21490
21510
|
this.emit('tablecell-cursor-changed', data);
|
|
21491
21511
|
});
|
|
21512
|
+
// Forward table cell selection changes (multi-cell drag/shift-click)
|
|
21513
|
+
this.canvasManager.on('table-cell-selection-changed', (data) => {
|
|
21514
|
+
this.emit('table-cell-selection-changed', data);
|
|
21515
|
+
});
|
|
21492
21516
|
this.canvasManager.on('repeating-section-clicked', (data) => {
|
|
21493
21517
|
// Repeating section clicked - update selection state
|
|
21494
21518
|
if (data.section && data.section.id) {
|
|
@@ -23458,6 +23482,39 @@ class PCEditor extends EventEmitter {
|
|
|
23458
23482
|
table.removeColumn(colIndex);
|
|
23459
23483
|
this.canvasManager.render();
|
|
23460
23484
|
}
|
|
23485
|
+
/**
|
|
23486
|
+
* Merge selected cells in a table.
|
|
23487
|
+
* Uses the table's current cell selection range.
|
|
23488
|
+
* @param table The table containing the cells to merge
|
|
23489
|
+
* @returns true if cells were merged successfully
|
|
23490
|
+
*/
|
|
23491
|
+
tableMergeCells(table) {
|
|
23492
|
+
Logger.log('[pc-editor] tableMergeCells');
|
|
23493
|
+
if (!this._isReady)
|
|
23494
|
+
return false;
|
|
23495
|
+
const result = table.mergeCells();
|
|
23496
|
+
if (result.success) {
|
|
23497
|
+
this.canvasManager.render();
|
|
23498
|
+
}
|
|
23499
|
+
return result.success;
|
|
23500
|
+
}
|
|
23501
|
+
/**
|
|
23502
|
+
* Split a merged cell back into individual cells.
|
|
23503
|
+
* @param table The table containing the merged cell
|
|
23504
|
+
* @param row Row index of the merged cell
|
|
23505
|
+
* @param col Column index of the merged cell
|
|
23506
|
+
* @returns true if the cell was split successfully
|
|
23507
|
+
*/
|
|
23508
|
+
tableSplitCell(table, row, col) {
|
|
23509
|
+
Logger.log('[pc-editor] tableSplitCell', row, col);
|
|
23510
|
+
if (!this._isReady)
|
|
23511
|
+
return false;
|
|
23512
|
+
const result = table.splitCell(row, col);
|
|
23513
|
+
if (result.success) {
|
|
23514
|
+
this.canvasManager.render();
|
|
23515
|
+
}
|
|
23516
|
+
return result.success;
|
|
23517
|
+
}
|
|
23461
23518
|
/**
|
|
23462
23519
|
* Begin a compound operation. Groups multiple mutations into a single undo entry.
|
|
23463
23520
|
* Call endCompoundOperation after making changes.
|
|
@@ -26500,9 +26557,15 @@ class FormattingPane extends BasePane {
|
|
|
26500
26557
|
this.bulletListBtn?.classList.toggle('pc-pane-button--active', listFormatting.listType === 'bullet');
|
|
26501
26558
|
this.numberedListBtn?.classList.toggle('pc-pane-button--active', listFormatting.listType === 'number');
|
|
26502
26559
|
}
|
|
26560
|
+
else {
|
|
26561
|
+
this.bulletListBtn?.classList.remove('pc-pane-button--active');
|
|
26562
|
+
this.numberedListBtn?.classList.remove('pc-pane-button--active');
|
|
26563
|
+
}
|
|
26503
26564
|
}
|
|
26504
26565
|
catch {
|
|
26505
26566
|
// No text editing active
|
|
26567
|
+
this.bulletListBtn?.classList.remove('pc-pane-button--active');
|
|
26568
|
+
this.numberedListBtn?.classList.remove('pc-pane-button--active');
|
|
26506
26569
|
}
|
|
26507
26570
|
}
|
|
26508
26571
|
getSelection() {
|
|
@@ -27817,8 +27880,9 @@ class TablePane extends BasePane {
|
|
|
27817
27880
|
// Default controls
|
|
27818
27881
|
this.defaultPaddingInput = null;
|
|
27819
27882
|
this.defaultBorderColorInput = null;
|
|
27820
|
-
//
|
|
27821
|
-
this.
|
|
27883
|
+
// Merge/split buttons
|
|
27884
|
+
this.mergeCellsBtn = null;
|
|
27885
|
+
this.splitCellBtn = null;
|
|
27822
27886
|
// Cell formatting controls
|
|
27823
27887
|
this.cellBgColorInput = null;
|
|
27824
27888
|
this.borderTopCheck = null;
|
|
@@ -27838,12 +27902,12 @@ class TablePane extends BasePane {
|
|
|
27838
27902
|
// Listen for selection/focus changes
|
|
27839
27903
|
const updateHandler = () => this.updateFromFocusedTable();
|
|
27840
27904
|
this.editor.on('selection-change', updateHandler);
|
|
27841
|
-
this.editor.on('
|
|
27842
|
-
this.editor.on('table-cell-selection', updateHandler);
|
|
27905
|
+
this.editor.on('tablecell-cursor-changed', updateHandler);
|
|
27906
|
+
this.editor.on('table-cell-selection-changed', updateHandler);
|
|
27843
27907
|
this.eventCleanup.push(() => {
|
|
27844
27908
|
this.editor?.off('selection-change', updateHandler);
|
|
27845
|
-
this.editor?.off('
|
|
27846
|
-
this.editor?.off('table-cell-selection', updateHandler);
|
|
27909
|
+
this.editor?.off('tablecell-cursor-changed', updateHandler);
|
|
27910
|
+
this.editor?.off('table-cell-selection-changed', updateHandler);
|
|
27847
27911
|
});
|
|
27848
27912
|
// Initial update
|
|
27849
27913
|
this.updateFromFocusedTable();
|
|
@@ -27896,16 +27960,6 @@ class TablePane extends BasePane {
|
|
|
27896
27960
|
this.addButtonListener(applyHeadersBtn, () => this.applyHeaders());
|
|
27897
27961
|
headersSection.appendChild(applyHeadersBtn);
|
|
27898
27962
|
container.appendChild(headersSection);
|
|
27899
|
-
// Row Loop section
|
|
27900
|
-
const loopSection = this.createSection('Row Loop');
|
|
27901
|
-
this.loopFieldInput = this.createTextInput({ placeholder: 'items' });
|
|
27902
|
-
loopSection.appendChild(this.createFormGroup('Array Field', this.loopFieldInput, {
|
|
27903
|
-
hint: 'Creates a loop on the currently focused row'
|
|
27904
|
-
}));
|
|
27905
|
-
const createLoopBtn = this.createButton('Create Row Loop');
|
|
27906
|
-
this.addButtonListener(createLoopBtn, () => this.createRowLoop());
|
|
27907
|
-
loopSection.appendChild(createLoopBtn);
|
|
27908
|
-
container.appendChild(loopSection);
|
|
27909
27963
|
// Defaults section
|
|
27910
27964
|
const defaultsSection = this.createSection('Defaults');
|
|
27911
27965
|
const defaultsRow = this.createRow();
|
|
@@ -27922,6 +27976,17 @@ class TablePane extends BasePane {
|
|
|
27922
27976
|
const cellSection = this.createSection('Cell Formatting');
|
|
27923
27977
|
this.cellSelectionDisplay = this.createHint('No cell selected');
|
|
27924
27978
|
cellSection.appendChild(this.cellSelectionDisplay);
|
|
27979
|
+
// Merge/Split buttons
|
|
27980
|
+
const mergeBtnGroup = this.createButtonGroup();
|
|
27981
|
+
this.mergeCellsBtn = this.createButton('Merge Cells');
|
|
27982
|
+
this.mergeCellsBtn.disabled = true;
|
|
27983
|
+
this.splitCellBtn = this.createButton('Split Cell');
|
|
27984
|
+
this.splitCellBtn.disabled = true;
|
|
27985
|
+
this.addButtonListener(this.mergeCellsBtn, () => this.doMergeCells());
|
|
27986
|
+
this.addButtonListener(this.splitCellBtn, () => this.doSplitCell());
|
|
27987
|
+
mergeBtnGroup.appendChild(this.mergeCellsBtn);
|
|
27988
|
+
mergeBtnGroup.appendChild(this.splitCellBtn);
|
|
27989
|
+
cellSection.appendChild(mergeBtnGroup);
|
|
27925
27990
|
// Background
|
|
27926
27991
|
this.cellBgColorInput = this.createColorInput('#ffffff');
|
|
27927
27992
|
cellSection.appendChild(this.createFormGroup('Background', this.cellBgColorInput));
|
|
@@ -28038,6 +28103,15 @@ class TablePane extends BasePane {
|
|
|
28038
28103
|
return;
|
|
28039
28104
|
const focusedCell = table.focusedCell;
|
|
28040
28105
|
const selectedRange = table.selectedRange;
|
|
28106
|
+
// Update merge/split button states
|
|
28107
|
+
if (this.mergeCellsBtn) {
|
|
28108
|
+
const canMerge = selectedRange ? table.canMergeRange(selectedRange).canMerge : false;
|
|
28109
|
+
this.mergeCellsBtn.disabled = !canMerge;
|
|
28110
|
+
}
|
|
28111
|
+
if (this.splitCellBtn) {
|
|
28112
|
+
const canSplit = focusedCell ? table.canSplitCell(focusedCell.row, focusedCell.col).canSplit : false;
|
|
28113
|
+
this.splitCellBtn.disabled = !canSplit;
|
|
28114
|
+
}
|
|
28041
28115
|
if (selectedRange) {
|
|
28042
28116
|
const count = (selectedRange.end.row - selectedRange.start.row + 1) *
|
|
28043
28117
|
(selectedRange.end.col - selectedRange.start.col + 1);
|
|
@@ -28195,20 +28269,20 @@ class TablePane extends BasePane {
|
|
|
28195
28269
|
hasTable() {
|
|
28196
28270
|
return this.currentTable !== null;
|
|
28197
28271
|
}
|
|
28198
|
-
|
|
28199
|
-
if (!this.editor || !this.currentTable)
|
|
28200
|
-
this.onApplyCallback?.(false, new Error('No table focused'));
|
|
28272
|
+
doMergeCells() {
|
|
28273
|
+
if (!this.editor || !this.currentTable)
|
|
28201
28274
|
return;
|
|
28202
|
-
|
|
28203
|
-
|
|
28204
|
-
|
|
28205
|
-
|
|
28275
|
+
this.editor.tableMergeCells(this.currentTable);
|
|
28276
|
+
this.updateFromFocusedTable();
|
|
28277
|
+
}
|
|
28278
|
+
doSplitCell() {
|
|
28279
|
+
if (!this.editor || !this.currentTable)
|
|
28206
28280
|
return;
|
|
28207
|
-
|
|
28208
|
-
|
|
28209
|
-
|
|
28210
|
-
this.editor.
|
|
28211
|
-
this.
|
|
28281
|
+
const focused = this.currentTable.focusedCell;
|
|
28282
|
+
if (!focused)
|
|
28283
|
+
return;
|
|
28284
|
+
this.editor.tableSplitCell(this.currentTable, focused.row, focused.col);
|
|
28285
|
+
this.updateFromFocusedTable();
|
|
28212
28286
|
}
|
|
28213
28287
|
/**
|
|
28214
28288
|
* Update the pane from current editor state.
|