quill-table-up 2.3.1 → 2.4.0
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/README.md +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +35 -12
- package/dist/index.js +26 -25
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +35 -31
- package/dist/index.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/e2e/table-keyboard-handler.test.ts +218 -0
- package/src/__tests__/e2e/table-selection.test.ts +137 -131
- package/src/__tests__/unit/table-cell-merge.test.ts +261 -1
- package/src/__tests__/unit/table-clipboard.test.ts +62 -44
- package/src/__tests__/unit/table-insert.test.ts +39 -2
- package/src/__tests__/unit/table-redo-undo.test.ts +69 -0
- package/src/__tests__/unit/table-remove.test.ts +4 -2
- package/src/__tests__/unit/utils.ts +22 -4
- package/src/__tests__/unit/vitest.d.ts +4 -1
- package/src/formats/index.ts +6 -0
- package/src/formats/overrides/block-embed.ts +54 -0
- package/src/formats/overrides/block.ts +10 -4
- package/src/formats/overrides/index.ts +1 -0
- package/src/formats/table-cell-format.ts +39 -6
- package/src/formats/table-cell-inner-format.ts +70 -21
- package/src/formats/table-main-format.ts +92 -1
- package/src/formats/table-row-format.ts +13 -2
- package/src/modules/table-clipboard.ts +30 -35
- package/src/modules/table-resize/table-resize-box.ts +2 -2
- package/src/modules/table-resize/table-resize-common.ts +1 -1
- package/src/modules/table-resize/table-resize-line.ts +1 -1
- package/src/modules/table-resize/table-resize-scale.ts +1 -1
- package/src/modules/table-scrollbar.ts +5 -5
- package/src/modules/table-selection.ts +52 -31
- package/src/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/src/style/table-selection.less +1 -0
- package/src/table-up.ts +57 -23
- package/src/utils/blot-helper.ts +7 -4
- package/src/utils/index.ts +1 -1
- package/src/utils/{scroll-event-handle.ts → scroll-event-helper.ts} +7 -0
- package/src/utils/types.ts +2 -0
package/src/table-up.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import type { EmitterSource, Op, Parchment as TypeParchment, Range as TypeRange } from 'quill';
|
|
2
|
+
import type { BlockEmbed as TypeBlockEmbed } from 'quill/blots/block';
|
|
3
|
+
import type TypeBlock from 'quill/blots/block';
|
|
2
4
|
import type { Context } from 'quill/modules/keyboard';
|
|
3
5
|
import type TypeKeyboard from 'quill/modules/keyboard';
|
|
4
6
|
import type TypeToolbar from 'quill/modules/toolbar';
|
|
5
|
-
import type { InternalModule, InternalTableSelectionModule, QuillTheme, QuillThemePicker, TableCellValue, TableConstantsData, TableTextOptions, TableUpOptions } from './utils';
|
|
7
|
+
import type { Constructor, InternalModule, InternalTableSelectionModule, QuillTheme, QuillThemePicker, TableCellValue, TableConstantsData, TableTextOptions, TableUpOptions } from './utils';
|
|
6
8
|
import Quill from 'quill';
|
|
7
|
-
import { BlockOverride, ContainerFormat, ScrollOverride, TableBodyFormat, TableCaptionFormat, TableCellFormat, TableCellInnerFormat, TableColFormat, TableColgroupFormat, TableMainFormat, TableRowFormat, TableWrapperFormat } from './formats';
|
|
9
|
+
import { BlockEmbedOverride, BlockOverride, ContainerFormat, ScrollOverride, TableBodyFormat, TableCaptionFormat, TableCellFormat, TableCellInnerFormat, TableColFormat, TableColgroupFormat, TableMainFormat, TableRowFormat, TableWrapperFormat } from './formats';
|
|
8
10
|
import { TableClipboard } from './modules';
|
|
9
|
-
import { blotName, createBEM, createSelectBox, cssTextToObject, debounce, findParentBlot, findParentBlots, isForbidInTable, isFunction, isNumber, isString, limitDomInViewPort, mixinClass, objectToCssText, randomId, tableCantInsert, tableUpEvent, tableUpInternal, tableUpSize, toCamelCase } from './utils';
|
|
11
|
+
import { blotName, createBEM, createSelectBox, cssTextToObject, debounce, findParentBlot, findParentBlots, isForbidInTable, isFunction, isNumber, isString, isSubclassOf, limitDomInViewPort, mixinClass, objectToCssText, randomId, tableCantInsert, tableUpEvent, tableUpInternal, tableUpSize, toCamelCase } from './utils';
|
|
10
12
|
|
|
11
13
|
const Parchment = Quill.import('parchment');
|
|
12
14
|
const Delta = Quill.import('delta');
|
|
13
|
-
const Break = Quill.import('blots/break') as TypeParchment.BlotConstructor;
|
|
14
15
|
const icons = Quill.import('ui/icons') as Record<string, any>;
|
|
16
|
+
const Break = Quill.import('blots/break') as TypeParchment.BlotConstructor;
|
|
17
|
+
const Block = Quill.import('blots/block') as typeof TypeBlock;
|
|
18
|
+
const BlockEmbed = Quill.import('blots/block/embed') as typeof TypeBlockEmbed;
|
|
15
19
|
|
|
16
20
|
function createCell(scroll: TypeParchment.ScrollBlot, { tableId, rowId, colId }: { tableId: string; rowId: string; colId: string }) {
|
|
17
21
|
const value = {
|
|
@@ -72,6 +76,26 @@ function generateTableArrowHandler(up: boolean) {
|
|
|
72
76
|
collapsed: true,
|
|
73
77
|
format: [blotName.tableCellInner],
|
|
74
78
|
handler(this: { quill: Quill }, range: TypeRange, context: Context) {
|
|
79
|
+
const direction = up ? 'prev' : 'next';
|
|
80
|
+
const childDirection = up ? 'tail' : 'head';
|
|
81
|
+
if (context.line[direction]) return true;
|
|
82
|
+
|
|
83
|
+
// TODO: if there have a very long text in cell, the line will auto wrap
|
|
84
|
+
// there is no good way to find the correct index of the last `line`
|
|
85
|
+
const cursorRect = this.quill.selection.getBounds(range.index);
|
|
86
|
+
const lineRect = context.line.domNode.getBoundingClientRect();
|
|
87
|
+
if (!cursorRect || !lineRect) return true;
|
|
88
|
+
if (up) {
|
|
89
|
+
if (cursorRect.top - lineRect.top > 3) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
if (lineRect.bottom - cursorRect.bottom > 3) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
75
99
|
let tableBlot: TableWrapperFormat;
|
|
76
100
|
let tableMain: TableMainFormat;
|
|
77
101
|
let tableRow: TableRowFormat;
|
|
@@ -84,8 +108,6 @@ function generateTableArrowHandler(up: boolean) {
|
|
|
84
108
|
}
|
|
85
109
|
|
|
86
110
|
const colIds = tableMain.getColIds();
|
|
87
|
-
const direction = up ? 'prev' : 'next';
|
|
88
|
-
const childDirection = up ? 'tail' : 'head';
|
|
89
111
|
const tableCaption = tableBlot.descendants(TableCaptionFormat, 0)[0];
|
|
90
112
|
|
|
91
113
|
let aroundLine;
|
|
@@ -104,10 +126,8 @@ function generateTableArrowHandler(up: boolean) {
|
|
|
104
126
|
else {
|
|
105
127
|
aroundLine = tableBlot[direction];
|
|
106
128
|
}
|
|
129
|
+
if (context.line[direction] || !aroundLine) return true;
|
|
107
130
|
|
|
108
|
-
if (context.line[direction] || !aroundLine) {
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
111
131
|
const targetRow = tableRow[direction] as TableRowFormat;
|
|
112
132
|
if (targetRow) {
|
|
113
133
|
const cellIndex = colIds.indexOf(tableCell.colId);
|
|
@@ -211,18 +231,28 @@ export class TableUp {
|
|
|
211
231
|
|
|
212
232
|
TableCellInnerFormat.requiredContainer = TableCellFormat;
|
|
213
233
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
234
|
+
// override Block and BlockEmbed
|
|
235
|
+
const excludeFormat = new Set(['table']);
|
|
236
|
+
const overrideFormats = Object.entries(Quill.imports as Record<string, Constructor>).filter(([name, blot]) => {
|
|
237
|
+
const blotName = name.split('formats/')[1];
|
|
238
|
+
return name.startsWith('formats/')
|
|
239
|
+
&& !excludeFormat.has(blotName)
|
|
240
|
+
&& !isSubclassOf(blot, Parchment.Attributor)
|
|
241
|
+
&& (isSubclassOf(blot, Block) || isSubclassOf(blot, BlockEmbed));
|
|
242
|
+
},
|
|
243
|
+
);
|
|
244
|
+
const overrides = overrideFormats.reduce((pre, [name, blot]) => {
|
|
245
|
+
const extendsClass = isSubclassOf(blot, BlockEmbed) ? BlockEmbedOverride : BlockOverride;
|
|
246
|
+
pre[name] = class extends mixinClass(blot, [extendsClass]) {
|
|
247
|
+
static register() {}
|
|
219
248
|
};
|
|
220
|
-
return
|
|
221
|
-
}, {} as Record<string,
|
|
249
|
+
return pre;
|
|
250
|
+
}, {} as Record<string, Constructor>);
|
|
222
251
|
|
|
223
252
|
Quill.register({
|
|
224
253
|
'blots/scroll': ScrollOverride,
|
|
225
254
|
'blots/block': BlockOverride,
|
|
255
|
+
'blots/block/embed': BlockEmbedOverride,
|
|
226
256
|
...overrides,
|
|
227
257
|
[`blots/${blotName.container}`]: ContainerFormat,
|
|
228
258
|
[`formats/${blotName.tableCell}`]: TableCellFormat,
|
|
@@ -383,6 +413,7 @@ export class TableUp {
|
|
|
383
413
|
scrollbarOptions: {},
|
|
384
414
|
resizeOptions: {},
|
|
385
415
|
resizeScaleOptions: {},
|
|
416
|
+
autoMergeCell: true,
|
|
386
417
|
} as TableUpOptions, options);
|
|
387
418
|
}
|
|
388
419
|
|
|
@@ -953,6 +984,9 @@ export class TableUp {
|
|
|
953
984
|
|
|
954
985
|
balanceTables() {
|
|
955
986
|
for (const tableBlot of this.quill.scroll.descendants(TableMainFormat)) {
|
|
987
|
+
// 同时, 当关闭 autoMerge 时, 如何对 cell 数据的 emptyRow 处理
|
|
988
|
+
tableBlot.checkEmptyCol(this.options.autoMergeCell);
|
|
989
|
+
tableBlot.checkEmptyRow(this.options.autoMergeCell);
|
|
956
990
|
this.fixUnusuaDeletelTable(tableBlot);
|
|
957
991
|
}
|
|
958
992
|
}
|
|
@@ -1064,6 +1098,7 @@ export class TableUp {
|
|
|
1064
1098
|
* after insert or remove cell. handle cell colspan and rowspan merge
|
|
1065
1099
|
*/
|
|
1066
1100
|
fixTableByRemove(tableBlot: TableMainFormat) {
|
|
1101
|
+
if (!this.options.autoMergeCell) return;
|
|
1067
1102
|
// calculate all cells
|
|
1068
1103
|
// maybe will get empty tr
|
|
1069
1104
|
const trBlots = tableBlot.getRows();
|
|
@@ -1150,13 +1185,11 @@ export class TableUp {
|
|
|
1150
1185
|
}
|
|
1151
1186
|
}
|
|
1152
1187
|
|
|
1153
|
-
const patchTds: {
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
};
|
|
1159
|
-
} = {};
|
|
1188
|
+
const patchTds: Record<string, {
|
|
1189
|
+
rowspan: number;
|
|
1190
|
+
colspan: number;
|
|
1191
|
+
colIndex: number;
|
|
1192
|
+
}> = {};
|
|
1160
1193
|
for (let i = endTrIndex; i < Math.min(trs.length, nextTrIndex); i++) {
|
|
1161
1194
|
const tr = trs[i];
|
|
1162
1195
|
tr.foreachCellInner((td) => {
|
|
@@ -1171,6 +1204,7 @@ export class TableUp {
|
|
|
1171
1204
|
// only remove td. empty tr to calculate colspan and rowspan
|
|
1172
1205
|
td.parent.remove();
|
|
1173
1206
|
});
|
|
1207
|
+
if (tr.length() === 0) tr.remove();
|
|
1174
1208
|
}
|
|
1175
1209
|
|
|
1176
1210
|
if (trs[nextTrIndex]) {
|
package/src/utils/blot-helper.ts
CHANGED
|
@@ -75,12 +75,12 @@ export function findChildBlot<T extends TypeParchment.BlotConstructor>(parent: T
|
|
|
75
75
|
return descendants;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
function mixinProps<T = any, U = any>(target: T, source: U) {
|
|
78
|
+
function mixinProps<T = any, U = any>(target: T, source: U, excludeReg?: RegExp) {
|
|
79
79
|
for (const prop of Object.getOwnPropertyNames(source)) {
|
|
80
|
-
if (
|
|
80
|
+
if (excludeReg && excludeReg.test(prop)) continue;
|
|
81
81
|
Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop)!);
|
|
82
82
|
}
|
|
83
|
-
return target
|
|
83
|
+
return target;
|
|
84
84
|
}
|
|
85
85
|
export function mixinClass<
|
|
86
86
|
T extends Constructor,
|
|
@@ -95,8 +95,11 @@ export function mixinClass<
|
|
|
95
95
|
}
|
|
96
96
|
};
|
|
97
97
|
for (const source of mixins) {
|
|
98
|
-
mixinProps
|
|
98
|
+
mixinProps(targetClass.prototype, source.prototype, /^constructor$/);
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
return targetClass;
|
|
102
102
|
}
|
|
103
|
+
export function isSubclassOf(childClass: any, parentClass: any): boolean {
|
|
104
|
+
return childClass.prototype instanceof parentClass;
|
|
105
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -6,7 +6,7 @@ export * from './constants';
|
|
|
6
6
|
export * from './is';
|
|
7
7
|
export * from './position';
|
|
8
8
|
export * from './resize-observer-helper';
|
|
9
|
-
export * from './scroll-event-
|
|
9
|
+
export * from './scroll-event-helper';
|
|
10
10
|
export * from './transformer';
|
|
11
11
|
export * from './transition-event-helper';
|
|
12
12
|
export * from './types';
|
package/src/utils/types.ts
CHANGED
|
@@ -71,6 +71,7 @@ export interface TableUpOptions {
|
|
|
71
71
|
alignOptions: any;
|
|
72
72
|
resizeScale?: Constructor<InternalModule, [TableUp, HTMLElement, Quill, Partial<TableResizeScaleOptions>]>;
|
|
73
73
|
resizeScaleOptions: Partial<TableResizeScaleOptions>;
|
|
74
|
+
autoMergeCell: boolean;
|
|
74
75
|
}
|
|
75
76
|
export interface TableColValue {
|
|
76
77
|
tableId: string;
|
|
@@ -86,6 +87,7 @@ export interface TableCellValue {
|
|
|
86
87
|
rowspan: number;
|
|
87
88
|
colspan: number;
|
|
88
89
|
style?: string;
|
|
90
|
+
emptyRow?: string[];
|
|
89
91
|
}
|
|
90
92
|
export interface TableRowValue {
|
|
91
93
|
tableId: string;
|