@jackuait/blok 0.10.11 → 0.10.12
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/blok.mjs +2 -2
- package/dist/chunks/{blok-CX_pZ_qq.mjs → blok-Cb7w54t6.mjs} +81 -38
- package/dist/chunks/{constants-lxerM-Xa.mjs → constants-C0aZXxoO.mjs} +1 -1
- package/dist/chunks/{tools-CMNxZqJC.mjs → tools-vS7102lG.mjs} +83 -32
- package/dist/full.mjs +3 -3
- package/dist/react.mjs +2 -2
- package/dist/tools.mjs +2 -2
- package/package.json +1 -1
- package/src/components/modules/api/blocks.ts +9 -4
- package/src/components/modules/blockEvents/composers/keyboardNavigation.ts +29 -6
- package/src/components/modules/blockManager/blockManager.ts +12 -2
- package/src/components/modules/blockManager/operations.ts +189 -9
- package/src/components/modules/caret.ts +57 -0
- package/src/components/modules/drag/operations/DragOperations.ts +10 -3
- package/src/styles/main.css +5 -0
- package/src/tools/callout/index.ts +39 -4
- package/src/tools/table/index.ts +59 -7
- package/src/tools/table/table-cell-blocks.ts +90 -3
- package/types/api/blocks.d.ts +2 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { API } from '../../../types';
|
|
2
2
|
import { DATA_ATTR } from '../../components/constants/data-attributes';
|
|
3
3
|
|
|
4
|
-
import { CELL_ATTR, ROW_ATTR, CELL_COL_ATTR } from './table-core';
|
|
4
|
+
import { CELL_ATTR, ROW_ATTR, CELL_ROW_ATTR, CELL_COL_ATTR } from './table-core';
|
|
5
5
|
import type { TableModel } from './table-model';
|
|
6
6
|
import type { LegacyCellContent, CellContent } from './types';
|
|
7
7
|
import { isCellWithBlocks } from './types';
|
|
@@ -353,7 +353,9 @@ export class TableCellBlocks {
|
|
|
353
353
|
* - Cells that already have block references get those blocks mounted.
|
|
354
354
|
* - If referenced blocks are missing from BlockManager, a fallback paragraph is created.
|
|
355
355
|
*/
|
|
356
|
-
public initializeCells(
|
|
356
|
+
public initializeCells(
|
|
357
|
+
content: LegacyCellContent[][]
|
|
358
|
+
): CellContent[][] {
|
|
357
359
|
const rowElements = this.gridElement.querySelectorAll(`[${ROW_ATTR}]`);
|
|
358
360
|
const normalizedContent: CellContent[][] = [];
|
|
359
361
|
|
|
@@ -437,6 +439,63 @@ export class TableCellBlocks {
|
|
|
437
439
|
return normalizedContent;
|
|
438
440
|
}
|
|
439
441
|
|
|
442
|
+
/**
|
|
443
|
+
* After a setData/render rebuild, reclaim any blocks the model references
|
|
444
|
+
* whose holders are not yet mounted in their model cell. This catches blocks
|
|
445
|
+
* that were restored via separate Yjs ops in a different transaction order
|
|
446
|
+
* — without it the restored block would float at the top level as an orphan
|
|
447
|
+
* (regression: table-undo-redo-orphans, multi-cell undo restoration).
|
|
448
|
+
*/
|
|
449
|
+
public reclaimReferencedBlocks(): void {
|
|
450
|
+
const snapshot = this.model.snapshot();
|
|
451
|
+
|
|
452
|
+
snapshot.content.forEach((row, rowIndex) => {
|
|
453
|
+
row.forEach((cellContent, colIndex) => {
|
|
454
|
+
if (!isCellWithBlocks(cellContent) || cellContent.blocks.length === 0) {
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const cell = this.gridElement.querySelector<HTMLElement>(
|
|
459
|
+
`[${CELL_ROW_ATTR}="${rowIndex}"][${CELL_COL_ATTR}="${colIndex}"]`
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
if (!cell) {
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const container = cell.querySelector<HTMLElement>(`[${CELL_BLOCKS_ATTR}]`);
|
|
467
|
+
|
|
468
|
+
if (!container) {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
for (const blockId of cellContent.blocks) {
|
|
473
|
+
const getIndex = this.api.blocks.getBlockIndex;
|
|
474
|
+
const getByIndex = this.api.blocks.getBlockByIndex;
|
|
475
|
+
|
|
476
|
+
if (typeof getIndex !== 'function' || typeof getByIndex !== 'function') {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
const index = getIndex(blockId);
|
|
481
|
+
|
|
482
|
+
if (index === undefined) {
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
const block = getByIndex(index);
|
|
486
|
+
|
|
487
|
+
if (!block) {
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
if (container.contains(block.holder)) {
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
this.claimBlockForCell(cell, blockId);
|
|
494
|
+
}
|
|
495
|
+
});
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
|
|
440
499
|
/**
|
|
441
500
|
* Remove placeholder attributes from contenteditable elements inside a cell container.
|
|
442
501
|
* Blocks in table cells should feel like plain table fields, not standalone paragraphs.
|
|
@@ -635,7 +694,14 @@ export class TableCellBlocks {
|
|
|
635
694
|
* When a block is removed, ensure no cell is left empty.
|
|
636
695
|
*/
|
|
637
696
|
private handleBlockMutation = (data: unknown): void => {
|
|
638
|
-
|
|
697
|
+
// While a structural op (setData / paste / row-col change) is rebuilding
|
|
698
|
+
// the table, defer events so they don't operate on stale DOM. EXCEPT for
|
|
699
|
+
// Yjs replay: an undo/redo that restores a previously-owned cell block
|
|
700
|
+
// fires block-added DURING the table's own setData, and discarding it
|
|
701
|
+
// would leave the restored block as a top-level orphan
|
|
702
|
+
// (regression: table-undo-redo-orphans). Process those immediately —
|
|
703
|
+
// recordedCellPos lookup below will route the block back to its cell.
|
|
704
|
+
if (this.isStructuralOpActive() && !this.api.blocks.isSyncingFromYjs) {
|
|
639
705
|
this.deferredEvents.push(data);
|
|
640
706
|
|
|
641
707
|
return;
|
|
@@ -674,6 +740,27 @@ export class TableCellBlocks {
|
|
|
674
740
|
return;
|
|
675
741
|
}
|
|
676
742
|
|
|
743
|
+
// Yjs undo replay: a block this table previously owned is being restored.
|
|
744
|
+
// The model's contentGrid still references its id from a prior render but
|
|
745
|
+
// the DOM is empty (we deliberately did not fabricate a replacement, see
|
|
746
|
+
// table-undo-redo-orphans regression). Reattach it to the recorded cell
|
|
747
|
+
// before falling through to adjacency-based heuristics, otherwise the
|
|
748
|
+
// restored block lands as a top-level orphan.
|
|
749
|
+
const recordedCellPos = this.model.findCellForBlock(detail.target.id);
|
|
750
|
+
|
|
751
|
+
if (recordedCellPos) {
|
|
752
|
+
const cellEl = this.gridElement.querySelector<HTMLElement>(
|
|
753
|
+
`[${CELL_ROW_ATTR}="${recordedCellPos.row}"][${CELL_COL_ATTR}="${recordedCellPos.col}"]`
|
|
754
|
+
);
|
|
755
|
+
|
|
756
|
+
if (cellEl) {
|
|
757
|
+
this.claimBlockForCell(cellEl, detail.target.id);
|
|
758
|
+
this.cellsPendingCheck.delete(cellEl);
|
|
759
|
+
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
677
764
|
const blockIndex = detail.index;
|
|
678
765
|
|
|
679
766
|
if (blockIndex === undefined) {
|
package/types/api/blocks.d.ts
CHANGED
|
@@ -189,9 +189,10 @@ export interface Blocks {
|
|
|
189
189
|
*
|
|
190
190
|
* @param parentId - id of the parent block
|
|
191
191
|
* @param insertIndex - flat block index where the new block should appear
|
|
192
|
+
* @param childData - optional data override for the child block (default: empty paragraph)
|
|
192
193
|
* @returns BlockAPI for the newly created child block
|
|
193
194
|
*/
|
|
194
|
-
insertInsideParent(parentId: string, insertIndex: number): BlockAPI;
|
|
195
|
+
insertInsideParent(parentId: string, insertIndex: number, childData?: BlockToolData): BlockAPI;
|
|
195
196
|
|
|
196
197
|
/**
|
|
197
198
|
* Execute a function within a transaction.
|