@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.js
CHANGED
|
@@ -7758,6 +7758,9 @@ class TableObject extends BaseEmbeddedObject {
|
|
|
7758
7758
|
result.mergedCell.markReflowDirty();
|
|
7759
7759
|
}
|
|
7760
7760
|
this.clearSelection();
|
|
7761
|
+
// Focus the anchor (top-left) cell of the merged range
|
|
7762
|
+
const normalized = TableCellMerger.normalizeRange(mergeRange);
|
|
7763
|
+
this.focusCell(normalized.start.row, normalized.start.col);
|
|
7761
7764
|
this.emit('cells-merged', { range: mergeRange });
|
|
7762
7765
|
this.emit('content-changed', {});
|
|
7763
7766
|
}
|
|
@@ -14314,7 +14317,8 @@ class CanvasManager extends EventEmitter {
|
|
|
14314
14317
|
const pageIndex = this.document.pages.findIndex(p => p.id === pageId);
|
|
14315
14318
|
// Get the slice for this page (for multi-page tables)
|
|
14316
14319
|
const slice = table.getRenderedSlice(pageIndex);
|
|
14317
|
-
const tablePosition = slice?.position ||
|
|
14320
|
+
const tablePosition = slice?.position ||
|
|
14321
|
+
(table.renderedPageIndex === pageIndex ? table.renderedPosition : null);
|
|
14318
14322
|
const sliceHeight = slice?.height || table.height;
|
|
14319
14323
|
// Check if point is within the table slice on this page
|
|
14320
14324
|
const isInsideTable = tablePosition &&
|
|
@@ -14347,6 +14351,7 @@ class CanvasManager extends EventEmitter {
|
|
|
14347
14351
|
end: cellAddr
|
|
14348
14352
|
});
|
|
14349
14353
|
this.render();
|
|
14354
|
+
this.emit('table-cell-selection-changed', { table });
|
|
14350
14355
|
e.preventDefault();
|
|
14351
14356
|
return;
|
|
14352
14357
|
}
|
|
@@ -14626,7 +14631,8 @@ class CanvasManager extends EventEmitter {
|
|
|
14626
14631
|
const currentPageIndex = this.document.pages.findIndex(p => p.id === pageId);
|
|
14627
14632
|
// Get the slice for the current page (for multi-page tables)
|
|
14628
14633
|
const slice = table.getRenderedSlice(currentPageIndex);
|
|
14629
|
-
const tablePosition = slice?.position ||
|
|
14634
|
+
const tablePosition = slice?.position ||
|
|
14635
|
+
(table.renderedPageIndex === currentPageIndex ? table.renderedPosition : null);
|
|
14630
14636
|
const sliceHeight = slice?.height || table.height;
|
|
14631
14637
|
if (tablePosition) {
|
|
14632
14638
|
// Check if point is within the table slice on this page
|
|
@@ -14656,6 +14662,7 @@ class CanvasManager extends EventEmitter {
|
|
|
14656
14662
|
end: cellAddr
|
|
14657
14663
|
});
|
|
14658
14664
|
this.render();
|
|
14665
|
+
this.emit('table-cell-selection-changed', { table });
|
|
14659
14666
|
}
|
|
14660
14667
|
}
|
|
14661
14668
|
}
|
|
@@ -15199,40 +15206,46 @@ class CanvasManager extends EventEmitter {
|
|
|
15199
15206
|
canvas.style.cursor = 'move';
|
|
15200
15207
|
return;
|
|
15201
15208
|
}
|
|
15202
|
-
// Show text cursor for
|
|
15203
|
-
if (object instanceof TextBoxObject) {
|
|
15204
|
-
canvas.style.cursor =
|
|
15205
|
-
|
|
15209
|
+
// Show text cursor for objects in edit mode, arrow otherwise
|
|
15210
|
+
if (object instanceof TextBoxObject && this.editingTextBox === object) {
|
|
15211
|
+
canvas.style.cursor = CanvasManager.TEXT_CURSOR;
|
|
15212
|
+
}
|
|
15213
|
+
else if (object instanceof TableObject && this._focusedControl === object) {
|
|
15214
|
+
canvas.style.cursor = CanvasManager.TEXT_CURSOR;
|
|
15206
15215
|
}
|
|
15216
|
+
else {
|
|
15217
|
+
canvas.style.cursor = 'default';
|
|
15218
|
+
}
|
|
15219
|
+
return;
|
|
15207
15220
|
}
|
|
15208
15221
|
}
|
|
15209
15222
|
// Check for table cells (show text cursor)
|
|
15210
15223
|
const tableCellHit = hitTestManager.queryByType(pageIndex, point, 'table-cell');
|
|
15211
15224
|
if (tableCellHit && tableCellHit.data.type === 'table-cell') {
|
|
15212
|
-
canvas.style.cursor =
|
|
15225
|
+
canvas.style.cursor = CanvasManager.TEXT_CURSOR;
|
|
15213
15226
|
return;
|
|
15214
15227
|
}
|
|
15215
15228
|
// Check for text regions (body, header, footer - show text cursor)
|
|
15216
15229
|
const textRegionHit = hitTestManager.queryByType(pageIndex, point, 'text-region');
|
|
15217
15230
|
if (textRegionHit && textRegionHit.data.type === 'text-region') {
|
|
15218
|
-
canvas.style.cursor =
|
|
15231
|
+
canvas.style.cursor = CanvasManager.TEXT_CURSOR;
|
|
15219
15232
|
return;
|
|
15220
15233
|
}
|
|
15221
15234
|
// Also check if point is within any editable region (body, header, footer)
|
|
15222
15235
|
// This catches cases where text region hit targets may not cover empty space
|
|
15223
15236
|
const bodyRegion = this.regionManager.getBodyRegion();
|
|
15224
15237
|
if (bodyRegion && bodyRegion.containsPointInRegion(point, pageIndex)) {
|
|
15225
|
-
canvas.style.cursor =
|
|
15238
|
+
canvas.style.cursor = CanvasManager.TEXT_CURSOR;
|
|
15226
15239
|
return;
|
|
15227
15240
|
}
|
|
15228
15241
|
const headerRegion = this.regionManager.getHeaderRegion();
|
|
15229
15242
|
if (headerRegion && headerRegion.containsPointInRegion(point, pageIndex)) {
|
|
15230
|
-
canvas.style.cursor =
|
|
15243
|
+
canvas.style.cursor = CanvasManager.TEXT_CURSOR;
|
|
15231
15244
|
return;
|
|
15232
15245
|
}
|
|
15233
15246
|
const footerRegion = this.regionManager.getFooterRegion();
|
|
15234
15247
|
if (footerRegion && footerRegion.containsPointInRegion(point, pageIndex)) {
|
|
15235
|
-
canvas.style.cursor =
|
|
15248
|
+
canvas.style.cursor = CanvasManager.TEXT_CURSOR;
|
|
15236
15249
|
return;
|
|
15237
15250
|
}
|
|
15238
15251
|
canvas.style.cursor = 'default';
|
|
@@ -15250,7 +15263,8 @@ class CanvasManager extends EventEmitter {
|
|
|
15250
15263
|
const { table, dividerType, index } = target.data;
|
|
15251
15264
|
// Get the table position from slice info
|
|
15252
15265
|
const slice = table.getRenderedSlice(pageIndex);
|
|
15253
|
-
const tablePosition = slice?.position ||
|
|
15266
|
+
const tablePosition = slice?.position ||
|
|
15267
|
+
(table.renderedPageIndex === pageIndex ? table.renderedPosition : null);
|
|
15254
15268
|
if (tablePosition) {
|
|
15255
15269
|
// Calculate the divider position based on type and index
|
|
15256
15270
|
let position;
|
|
@@ -15978,7 +15992,9 @@ class CanvasManager extends EventEmitter {
|
|
|
15978
15992
|
if (obj instanceof TableObject) {
|
|
15979
15993
|
// For multi-page tables, check if this page has a rendered slice
|
|
15980
15994
|
const slice = obj.getRenderedSlice(pageIndex);
|
|
15981
|
-
|
|
15995
|
+
// Only use renderedPosition if the table was actually rendered on this page
|
|
15996
|
+
const tablePosition = slice?.position ||
|
|
15997
|
+
(obj.renderedPageIndex === pageIndex ? obj.renderedPosition : null);
|
|
15982
15998
|
if (tablePosition) {
|
|
15983
15999
|
// Check if point is inside the table slice on this page
|
|
15984
16000
|
const sliceHeight = slice?.height || obj.height;
|
|
@@ -16222,6 +16238,10 @@ class CanvasManager extends EventEmitter {
|
|
|
16222
16238
|
}
|
|
16223
16239
|
CanvasManager.CELL_SELECTION_THRESHOLD = 5; // Minimum pixels to drag before cell selection starts
|
|
16224
16240
|
CanvasManager.RELATIVE_DRAG_THRESHOLD = 3; // Minimum pixels to drag before moving starts
|
|
16241
|
+
// Custom text cursor as a black I-beam SVG data URI.
|
|
16242
|
+
// The native 'text' cursor can render as white on Windows browsers,
|
|
16243
|
+
// making it invisible over the white canvas background.
|
|
16244
|
+
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";
|
|
16225
16245
|
|
|
16226
16246
|
/**
|
|
16227
16247
|
* DataBinder handles binding data to documents.
|
|
@@ -21510,6 +21530,10 @@ class PCEditor extends EventEmitter {
|
|
|
21510
21530
|
this.canvasManager.on('tablecell-cursor-changed', (data) => {
|
|
21511
21531
|
this.emit('tablecell-cursor-changed', data);
|
|
21512
21532
|
});
|
|
21533
|
+
// Forward table cell selection changes (multi-cell drag/shift-click)
|
|
21534
|
+
this.canvasManager.on('table-cell-selection-changed', (data) => {
|
|
21535
|
+
this.emit('table-cell-selection-changed', data);
|
|
21536
|
+
});
|
|
21513
21537
|
this.canvasManager.on('repeating-section-clicked', (data) => {
|
|
21514
21538
|
// Repeating section clicked - update selection state
|
|
21515
21539
|
if (data.section && data.section.id) {
|
|
@@ -23479,6 +23503,39 @@ class PCEditor extends EventEmitter {
|
|
|
23479
23503
|
table.removeColumn(colIndex);
|
|
23480
23504
|
this.canvasManager.render();
|
|
23481
23505
|
}
|
|
23506
|
+
/**
|
|
23507
|
+
* Merge selected cells in a table.
|
|
23508
|
+
* Uses the table's current cell selection range.
|
|
23509
|
+
* @param table The table containing the cells to merge
|
|
23510
|
+
* @returns true if cells were merged successfully
|
|
23511
|
+
*/
|
|
23512
|
+
tableMergeCells(table) {
|
|
23513
|
+
Logger.log('[pc-editor] tableMergeCells');
|
|
23514
|
+
if (!this._isReady)
|
|
23515
|
+
return false;
|
|
23516
|
+
const result = table.mergeCells();
|
|
23517
|
+
if (result.success) {
|
|
23518
|
+
this.canvasManager.render();
|
|
23519
|
+
}
|
|
23520
|
+
return result.success;
|
|
23521
|
+
}
|
|
23522
|
+
/**
|
|
23523
|
+
* Split a merged cell back into individual cells.
|
|
23524
|
+
* @param table The table containing the merged cell
|
|
23525
|
+
* @param row Row index of the merged cell
|
|
23526
|
+
* @param col Column index of the merged cell
|
|
23527
|
+
* @returns true if the cell was split successfully
|
|
23528
|
+
*/
|
|
23529
|
+
tableSplitCell(table, row, col) {
|
|
23530
|
+
Logger.log('[pc-editor] tableSplitCell', row, col);
|
|
23531
|
+
if (!this._isReady)
|
|
23532
|
+
return false;
|
|
23533
|
+
const result = table.splitCell(row, col);
|
|
23534
|
+
if (result.success) {
|
|
23535
|
+
this.canvasManager.render();
|
|
23536
|
+
}
|
|
23537
|
+
return result.success;
|
|
23538
|
+
}
|
|
23482
23539
|
/**
|
|
23483
23540
|
* Begin a compound operation. Groups multiple mutations into a single undo entry.
|
|
23484
23541
|
* Call endCompoundOperation after making changes.
|
|
@@ -26521,9 +26578,15 @@ class FormattingPane extends BasePane {
|
|
|
26521
26578
|
this.bulletListBtn?.classList.toggle('pc-pane-button--active', listFormatting.listType === 'bullet');
|
|
26522
26579
|
this.numberedListBtn?.classList.toggle('pc-pane-button--active', listFormatting.listType === 'number');
|
|
26523
26580
|
}
|
|
26581
|
+
else {
|
|
26582
|
+
this.bulletListBtn?.classList.remove('pc-pane-button--active');
|
|
26583
|
+
this.numberedListBtn?.classList.remove('pc-pane-button--active');
|
|
26584
|
+
}
|
|
26524
26585
|
}
|
|
26525
26586
|
catch {
|
|
26526
26587
|
// No text editing active
|
|
26588
|
+
this.bulletListBtn?.classList.remove('pc-pane-button--active');
|
|
26589
|
+
this.numberedListBtn?.classList.remove('pc-pane-button--active');
|
|
26527
26590
|
}
|
|
26528
26591
|
}
|
|
26529
26592
|
getSelection() {
|
|
@@ -27838,8 +27901,9 @@ class TablePane extends BasePane {
|
|
|
27838
27901
|
// Default controls
|
|
27839
27902
|
this.defaultPaddingInput = null;
|
|
27840
27903
|
this.defaultBorderColorInput = null;
|
|
27841
|
-
//
|
|
27842
|
-
this.
|
|
27904
|
+
// Merge/split buttons
|
|
27905
|
+
this.mergeCellsBtn = null;
|
|
27906
|
+
this.splitCellBtn = null;
|
|
27843
27907
|
// Cell formatting controls
|
|
27844
27908
|
this.cellBgColorInput = null;
|
|
27845
27909
|
this.borderTopCheck = null;
|
|
@@ -27859,12 +27923,12 @@ class TablePane extends BasePane {
|
|
|
27859
27923
|
// Listen for selection/focus changes
|
|
27860
27924
|
const updateHandler = () => this.updateFromFocusedTable();
|
|
27861
27925
|
this.editor.on('selection-change', updateHandler);
|
|
27862
|
-
this.editor.on('
|
|
27863
|
-
this.editor.on('table-cell-selection', updateHandler);
|
|
27926
|
+
this.editor.on('tablecell-cursor-changed', updateHandler);
|
|
27927
|
+
this.editor.on('table-cell-selection-changed', updateHandler);
|
|
27864
27928
|
this.eventCleanup.push(() => {
|
|
27865
27929
|
this.editor?.off('selection-change', updateHandler);
|
|
27866
|
-
this.editor?.off('
|
|
27867
|
-
this.editor?.off('table-cell-selection', updateHandler);
|
|
27930
|
+
this.editor?.off('tablecell-cursor-changed', updateHandler);
|
|
27931
|
+
this.editor?.off('table-cell-selection-changed', updateHandler);
|
|
27868
27932
|
});
|
|
27869
27933
|
// Initial update
|
|
27870
27934
|
this.updateFromFocusedTable();
|
|
@@ -27917,16 +27981,6 @@ class TablePane extends BasePane {
|
|
|
27917
27981
|
this.addButtonListener(applyHeadersBtn, () => this.applyHeaders());
|
|
27918
27982
|
headersSection.appendChild(applyHeadersBtn);
|
|
27919
27983
|
container.appendChild(headersSection);
|
|
27920
|
-
// Row Loop section
|
|
27921
|
-
const loopSection = this.createSection('Row Loop');
|
|
27922
|
-
this.loopFieldInput = this.createTextInput({ placeholder: 'items' });
|
|
27923
|
-
loopSection.appendChild(this.createFormGroup('Array Field', this.loopFieldInput, {
|
|
27924
|
-
hint: 'Creates a loop on the currently focused row'
|
|
27925
|
-
}));
|
|
27926
|
-
const createLoopBtn = this.createButton('Create Row Loop');
|
|
27927
|
-
this.addButtonListener(createLoopBtn, () => this.createRowLoop());
|
|
27928
|
-
loopSection.appendChild(createLoopBtn);
|
|
27929
|
-
container.appendChild(loopSection);
|
|
27930
27984
|
// Defaults section
|
|
27931
27985
|
const defaultsSection = this.createSection('Defaults');
|
|
27932
27986
|
const defaultsRow = this.createRow();
|
|
@@ -27943,6 +27997,17 @@ class TablePane extends BasePane {
|
|
|
27943
27997
|
const cellSection = this.createSection('Cell Formatting');
|
|
27944
27998
|
this.cellSelectionDisplay = this.createHint('No cell selected');
|
|
27945
27999
|
cellSection.appendChild(this.cellSelectionDisplay);
|
|
28000
|
+
// Merge/Split buttons
|
|
28001
|
+
const mergeBtnGroup = this.createButtonGroup();
|
|
28002
|
+
this.mergeCellsBtn = this.createButton('Merge Cells');
|
|
28003
|
+
this.mergeCellsBtn.disabled = true;
|
|
28004
|
+
this.splitCellBtn = this.createButton('Split Cell');
|
|
28005
|
+
this.splitCellBtn.disabled = true;
|
|
28006
|
+
this.addButtonListener(this.mergeCellsBtn, () => this.doMergeCells());
|
|
28007
|
+
this.addButtonListener(this.splitCellBtn, () => this.doSplitCell());
|
|
28008
|
+
mergeBtnGroup.appendChild(this.mergeCellsBtn);
|
|
28009
|
+
mergeBtnGroup.appendChild(this.splitCellBtn);
|
|
28010
|
+
cellSection.appendChild(mergeBtnGroup);
|
|
27946
28011
|
// Background
|
|
27947
28012
|
this.cellBgColorInput = this.createColorInput('#ffffff');
|
|
27948
28013
|
cellSection.appendChild(this.createFormGroup('Background', this.cellBgColorInput));
|
|
@@ -28059,6 +28124,15 @@ class TablePane extends BasePane {
|
|
|
28059
28124
|
return;
|
|
28060
28125
|
const focusedCell = table.focusedCell;
|
|
28061
28126
|
const selectedRange = table.selectedRange;
|
|
28127
|
+
// Update merge/split button states
|
|
28128
|
+
if (this.mergeCellsBtn) {
|
|
28129
|
+
const canMerge = selectedRange ? table.canMergeRange(selectedRange).canMerge : false;
|
|
28130
|
+
this.mergeCellsBtn.disabled = !canMerge;
|
|
28131
|
+
}
|
|
28132
|
+
if (this.splitCellBtn) {
|
|
28133
|
+
const canSplit = focusedCell ? table.canSplitCell(focusedCell.row, focusedCell.col).canSplit : false;
|
|
28134
|
+
this.splitCellBtn.disabled = !canSplit;
|
|
28135
|
+
}
|
|
28062
28136
|
if (selectedRange) {
|
|
28063
28137
|
const count = (selectedRange.end.row - selectedRange.start.row + 1) *
|
|
28064
28138
|
(selectedRange.end.col - selectedRange.start.col + 1);
|
|
@@ -28216,20 +28290,20 @@ class TablePane extends BasePane {
|
|
|
28216
28290
|
hasTable() {
|
|
28217
28291
|
return this.currentTable !== null;
|
|
28218
28292
|
}
|
|
28219
|
-
|
|
28220
|
-
if (!this.editor || !this.currentTable)
|
|
28221
|
-
this.onApplyCallback?.(false, new Error('No table focused'));
|
|
28293
|
+
doMergeCells() {
|
|
28294
|
+
if (!this.editor || !this.currentTable)
|
|
28222
28295
|
return;
|
|
28223
|
-
|
|
28224
|
-
|
|
28225
|
-
|
|
28226
|
-
|
|
28296
|
+
this.editor.tableMergeCells(this.currentTable);
|
|
28297
|
+
this.updateFromFocusedTable();
|
|
28298
|
+
}
|
|
28299
|
+
doSplitCell() {
|
|
28300
|
+
if (!this.editor || !this.currentTable)
|
|
28227
28301
|
return;
|
|
28228
|
-
|
|
28229
|
-
|
|
28230
|
-
|
|
28231
|
-
this.editor.
|
|
28232
|
-
this.
|
|
28302
|
+
const focused = this.currentTable.focusedCell;
|
|
28303
|
+
if (!focused)
|
|
28304
|
+
return;
|
|
28305
|
+
this.editor.tableSplitCell(this.currentTable, focused.row, focused.col);
|
|
28306
|
+
this.updateFromFocusedTable();
|
|
28233
28307
|
}
|
|
28234
28308
|
/**
|
|
28235
28309
|
* Update the pane from current editor state.
|