@phuong-tran-redoc/document-engine-core 0.0.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/LICENSE.md +19 -0
- package/README.md +224 -0
- package/package.json +30 -0
- package/src/constants/indent.constant.d.ts +1 -0
- package/src/constants/indent.constant.js +11 -0
- package/src/constants/index.d.ts +1 -0
- package/src/constants/index.js +18 -0
- package/src/constants/table.constant.d.ts +1 -0
- package/src/constants/table.constant.js +11 -0
- package/src/extensions/clear-content.extension.d.ts +9 -0
- package/src/extensions/clear-content.extension.js +19 -0
- package/src/extensions/indent.extension.d.ts +16 -0
- package/src/extensions/indent.extension.js +69 -0
- package/src/extensions/index.d.ts +8 -0
- package/src/extensions/index.js +25 -0
- package/src/extensions/ordered-list.extension.d.ts +13 -0
- package/src/extensions/ordered-list.extension.js +48 -0
- package/src/extensions/reset-format.extension.d.ts +9 -0
- package/src/extensions/reset-format.extension.js +19 -0
- package/src/extensions/reset-on-enter.extension.d.ts +2 -0
- package/src/extensions/reset-on-enter.extension.js +42 -0
- package/src/extensions/restricted-editing.extension.d.ts +17 -0
- package/src/extensions/restricted-editing.extension.js +384 -0
- package/src/extensions/table-resizing.extension.d.ts +6 -0
- package/src/extensions/table-resizing.extension.js +171 -0
- package/src/extensions/table-style.extension.d.ts +41 -0
- package/src/extensions/table-style.extension.js +499 -0
- package/src/extensions/text-case.extension.d.ts +13 -0
- package/src/extensions/text-case.extension.js +49 -0
- package/src/index.d.ts +7 -0
- package/src/index.js +24 -0
- package/src/models/color.model.d.ts +14 -0
- package/src/models/color.model.js +40 -0
- package/src/models/index.d.ts +1 -0
- package/src/models/index.js +18 -0
- package/src/nodes/dynamic-field.node.d.ts +49 -0
- package/src/nodes/dynamic-field.node.js +99 -0
- package/src/nodes/heading.node.d.ts +8 -0
- package/src/nodes/heading.node.js +23 -0
- package/src/nodes/index.d.ts +3 -0
- package/src/nodes/index.js +20 -0
- package/src/nodes/page-break.node.d.ts +9 -0
- package/src/nodes/page-break.node.js +50 -0
- package/src/types/index.d.ts +2 -0
- package/src/types/index.js +19 -0
- package/src/types/ordered-list.type.d.ts +1 -0
- package/src/types/ordered-list.type.js +4 -0
- package/src/types/text-case.type.d.ts +1 -0
- package/src/types/text-case.type.js +4 -0
- package/src/utils/color.util.d.ts +14 -0
- package/src/utils/color.util.js +41 -0
- package/src/utils/dom.util.d.ts +2 -0
- package/src/utils/dom.util.js +43 -0
- package/src/utils/index.d.ts +4 -0
- package/src/utils/index.js +21 -0
- package/src/utils/table.util.d.ts +36 -0
- package/src/utils/table.util.js +103 -0
- package/src/utils/text.util.d.ts +9 -0
- package/src/utils/text.util.js +59 -0
- package/src/views/block-handler.d.ts +44 -0
- package/src/views/block-handler.js +310 -0
- package/src/views/index.d.ts +1 -0
- package/src/views/index.js +18 -0
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: all[name]
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
MIN_NEW_COL_WIDTH: function() {
|
|
13
|
+
return MIN_NEW_COL_WIDTH;
|
|
14
|
+
},
|
|
15
|
+
StyledTable: function() {
|
|
16
|
+
return StyledTable;
|
|
17
|
+
},
|
|
18
|
+
StyledTableCell: function() {
|
|
19
|
+
return StyledTableCell;
|
|
20
|
+
},
|
|
21
|
+
StyledTableHeader: function() {
|
|
22
|
+
return StyledTableHeader;
|
|
23
|
+
},
|
|
24
|
+
StyledTableKit: function() {
|
|
25
|
+
return StyledTableKit;
|
|
26
|
+
},
|
|
27
|
+
TableDefaultAttributes: function() {
|
|
28
|
+
return TableDefaultAttributes;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
const _core = require("@tiptap/core");
|
|
32
|
+
const _extensiontable = require("@tiptap/extension-table");
|
|
33
|
+
const _state = require("@tiptap/pm/state");
|
|
34
|
+
const _tables = require("@tiptap/pm/tables");
|
|
35
|
+
const _utils = require("../utils");
|
|
36
|
+
const _views = require("../views");
|
|
37
|
+
const _tableresizingextension = require("./table-resizing.extension");
|
|
38
|
+
const MIN_NEW_COL_WIDTH = 5.0;
|
|
39
|
+
/**
|
|
40
|
+
* Calculate new column widths when adding a column, ensuring no column goes below MIN_NEW_COL_WIDTH
|
|
41
|
+
* @param oldColWidths - Array of current column widths
|
|
42
|
+
* @returns Array of adjusted column widths (without the new column inserted yet)
|
|
43
|
+
*/ function calculateColumnWidthsForNewColumn(oldColWidths) {
|
|
44
|
+
// Find columns that can contribute (above minimum)
|
|
45
|
+
const columnsAboveMin = oldColWidths.filter((w)=>w > MIN_NEW_COL_WIDTH);
|
|
46
|
+
// If not enough space, proportionally reduce all columns
|
|
47
|
+
if (columnsAboveMin.length === 0) {
|
|
48
|
+
const reduction = MIN_NEW_COL_WIDTH / oldColWidths.length;
|
|
49
|
+
return oldColWidths.map((w)=>w - reduction);
|
|
50
|
+
}
|
|
51
|
+
// Calculate available space from columns above minimum
|
|
52
|
+
const availableSpace = columnsAboveMin.reduce((sum, w)=>sum + (w - MIN_NEW_COL_WIDTH), 0);
|
|
53
|
+
// If we have enough space, only tax columns above minimum
|
|
54
|
+
if (availableSpace >= MIN_NEW_COL_WIDTH) {
|
|
55
|
+
return oldColWidths.map((w)=>{
|
|
56
|
+
if (w > MIN_NEW_COL_WIDTH) {
|
|
57
|
+
const contribution = (w - MIN_NEW_COL_WIDTH) / availableSpace * MIN_NEW_COL_WIDTH;
|
|
58
|
+
return Math.max(MIN_NEW_COL_WIDTH, w - contribution);
|
|
59
|
+
}
|
|
60
|
+
return w;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
// Not enough space even from columns above min, reduce proportionally
|
|
64
|
+
const reduction = MIN_NEW_COL_WIDTH / oldColWidths.length;
|
|
65
|
+
return oldColWidths.map((w)=>w - reduction);
|
|
66
|
+
}
|
|
67
|
+
const TableDefaultAttributes = {
|
|
68
|
+
border: {
|
|
69
|
+
style: 'double',
|
|
70
|
+
color: '#e5e7eb',
|
|
71
|
+
width: '1px'
|
|
72
|
+
},
|
|
73
|
+
backgroundColor: null,
|
|
74
|
+
colwidths: null,
|
|
75
|
+
cellBorder: {
|
|
76
|
+
style: 'solid',
|
|
77
|
+
color: '#e5e7eb',
|
|
78
|
+
width: '1px'
|
|
79
|
+
},
|
|
80
|
+
cellBackgroundColor: null,
|
|
81
|
+
cellVerticalAlign: 'middle',
|
|
82
|
+
cellTextAlign: null
|
|
83
|
+
};
|
|
84
|
+
// Extend TableCell and TableHeader to support styling attributes
|
|
85
|
+
const commonCellAttributes = {
|
|
86
|
+
backgroundColor: {
|
|
87
|
+
default: null,
|
|
88
|
+
renderHTML: (attrs)=>attrs.backgroundColor ? {
|
|
89
|
+
style: `background-color: ${attrs.backgroundColor};`
|
|
90
|
+
} : {},
|
|
91
|
+
parseHTML: (element)=>element.style.getPropertyValue('background-color') || null
|
|
92
|
+
},
|
|
93
|
+
border: {
|
|
94
|
+
default: TableDefaultAttributes.cellBorder,
|
|
95
|
+
renderHTML: (attrs)=>{
|
|
96
|
+
const border = attrs['border'];
|
|
97
|
+
if (!border) return {};
|
|
98
|
+
const styles = [];
|
|
99
|
+
if (border.style) styles.push(`border-style: ${border.style}`);
|
|
100
|
+
if (border.color) styles.push(`border-color: ${border.color}`);
|
|
101
|
+
if (border.width) styles.push(`border-width: ${border.width}`);
|
|
102
|
+
return styles.length ? {
|
|
103
|
+
style: styles.join('; ') + ';'
|
|
104
|
+
} : {};
|
|
105
|
+
},
|
|
106
|
+
parseHTML: (element)=>{
|
|
107
|
+
const style = element.style.getPropertyValue('border-style');
|
|
108
|
+
const color = element.style.getPropertyValue('border-color');
|
|
109
|
+
const width = element.style.getPropertyValue('border-width');
|
|
110
|
+
if (!style && !color && !width) return null;
|
|
111
|
+
return {
|
|
112
|
+
style: style || null,
|
|
113
|
+
color: color || null,
|
|
114
|
+
width: width || null
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
verticalAlign: {
|
|
119
|
+
default: TableDefaultAttributes.cellVerticalAlign,
|
|
120
|
+
renderHTML: (attrs)=>attrs.verticalAlign ? {
|
|
121
|
+
style: `vertical-align: ${attrs.verticalAlign};`
|
|
122
|
+
} : {},
|
|
123
|
+
parseHTML: (element)=>element.style.getPropertyValue('vertical-align') || null
|
|
124
|
+
},
|
|
125
|
+
textAlign: {
|
|
126
|
+
default: TableDefaultAttributes.cellTextAlign,
|
|
127
|
+
renderHTML: (attrs)=>attrs.textAlign ? {
|
|
128
|
+
style: `text-align: ${attrs.textAlign};`
|
|
129
|
+
} : {},
|
|
130
|
+
parseHTML: (element)=>element.style.getPropertyValue('text-align') || null
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
const StyledTableCell = _extensiontable.TableCell.extend({
|
|
134
|
+
addAttributes () {
|
|
135
|
+
const parent = this.parent?.() ?? {};
|
|
136
|
+
return {
|
|
137
|
+
...parent,
|
|
138
|
+
...commonCellAttributes
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
const StyledTableHeader = _extensiontable.TableHeader.extend({
|
|
143
|
+
addAttributes () {
|
|
144
|
+
const parent = this.parent?.() ?? {};
|
|
145
|
+
return {
|
|
146
|
+
...parent,
|
|
147
|
+
...commonCellAttributes
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
const StyledTable = _extensiontable.Table.extend({
|
|
152
|
+
// name: 'styledTable',
|
|
153
|
+
// draggable: true,
|
|
154
|
+
addAttributes () {
|
|
155
|
+
const parent = this.parent?.() ?? {};
|
|
156
|
+
return {
|
|
157
|
+
...parent,
|
|
158
|
+
border: {
|
|
159
|
+
default: null,
|
|
160
|
+
renderHTML: (attrs)=>{
|
|
161
|
+
const border = attrs.border;
|
|
162
|
+
if (!border) return {};
|
|
163
|
+
const styles = [];
|
|
164
|
+
if (border.style) styles.push(`border-style: ${border.style}`);
|
|
165
|
+
if (border.color) styles.push(`border-color: ${border.color}`);
|
|
166
|
+
if (border.width) styles.push(`border-width: ${border.width}`);
|
|
167
|
+
return styles.length ? {
|
|
168
|
+
style: styles.join('; ') + ';'
|
|
169
|
+
} : {};
|
|
170
|
+
},
|
|
171
|
+
parseHTML: (element)=>{
|
|
172
|
+
const style = element.style.getPropertyValue('border-style');
|
|
173
|
+
const color = element.style.getPropertyValue('border-color');
|
|
174
|
+
const width = element.style.getPropertyValue('border-width');
|
|
175
|
+
if (!style && !color && !width) return null;
|
|
176
|
+
return {
|
|
177
|
+
style: style || null,
|
|
178
|
+
color: color || null,
|
|
179
|
+
width: width || null
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
backgroundColor: {
|
|
184
|
+
default: null,
|
|
185
|
+
renderHTML: (attrs)=>attrs.backgroundColor ? {
|
|
186
|
+
style: `background-color: ${attrs.backgroundColor};`
|
|
187
|
+
} : {},
|
|
188
|
+
parseHTML: (element)=>element.style.getPropertyValue('background-color') || null
|
|
189
|
+
},
|
|
190
|
+
colwidths: {
|
|
191
|
+
default: null,
|
|
192
|
+
renderHTML: (attributes)=>{
|
|
193
|
+
if (!attributes['colwidths']) {
|
|
194
|
+
return {}; // Không có gì để render
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
'data-colwidths': JSON.stringify(attributes['colwidths'])
|
|
198
|
+
};
|
|
199
|
+
},
|
|
200
|
+
parseHTML: (element)=>{
|
|
201
|
+
// Only get cols from direct child colgroup (not from nested tables)
|
|
202
|
+
const colgroup = element.querySelector(':scope > colgroup');
|
|
203
|
+
if (!colgroup) return null;
|
|
204
|
+
const cols = colgroup.querySelectorAll('col');
|
|
205
|
+
if (cols.length === 0) return null;
|
|
206
|
+
const colwidths = [];
|
|
207
|
+
cols.forEach((col)=>{
|
|
208
|
+
const width = col.getAttribute('style');
|
|
209
|
+
if (width) {
|
|
210
|
+
const match = width.match(/width:\s*(\d+(?:\.\d+)?)%/);
|
|
211
|
+
colwidths.push(match ? parseFloat(match[1]) : null);
|
|
212
|
+
} else {
|
|
213
|
+
colwidths.push(null);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
return colwidths.length > 0 ? colwidths : null;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
},
|
|
221
|
+
renderHTML ({ node, HTMLAttributes }) {
|
|
222
|
+
const colwidths = node.attrs?.['colwidths'];
|
|
223
|
+
const domNodes = [];
|
|
224
|
+
// Render <colgroup> nếu có colwidths
|
|
225
|
+
if (colwidths) {
|
|
226
|
+
const colgroup = [
|
|
227
|
+
'colgroup',
|
|
228
|
+
{}
|
|
229
|
+
];
|
|
230
|
+
colwidths.forEach((width)=>{
|
|
231
|
+
colgroup.push([
|
|
232
|
+
'col',
|
|
233
|
+
{
|
|
234
|
+
style: width ? `width: ${width}%` : null
|
|
235
|
+
}
|
|
236
|
+
]);
|
|
237
|
+
});
|
|
238
|
+
domNodes.push(colgroup);
|
|
239
|
+
}
|
|
240
|
+
// Thêm <tbody> (0 là 'content hole')
|
|
241
|
+
domNodes.push([
|
|
242
|
+
'tbody',
|
|
243
|
+
0
|
|
244
|
+
]);
|
|
245
|
+
// Merge các HTML attributes (bao gồm cả global attributes)
|
|
246
|
+
// HTMLAttributes đã được Tiptap merge sẵn từ getRenderedAttributes
|
|
247
|
+
return [
|
|
248
|
+
'table',
|
|
249
|
+
HTMLAttributes,
|
|
250
|
+
...domNodes
|
|
251
|
+
];
|
|
252
|
+
},
|
|
253
|
+
addCommands () {
|
|
254
|
+
const parent = this.parent?.() ?? {};
|
|
255
|
+
return {
|
|
256
|
+
...parent,
|
|
257
|
+
// Table
|
|
258
|
+
setTableBorder: (border)=>({ chain, state })=>{
|
|
259
|
+
if (!border) return chain().focus().updateAttributes('table', {
|
|
260
|
+
border: null
|
|
261
|
+
}).run();
|
|
262
|
+
// Get current table border and merge with new values
|
|
263
|
+
// Find the table node
|
|
264
|
+
const cellInfo = (0, _utils.getCursorCellInfo)(state);
|
|
265
|
+
if (!cellInfo) return false;
|
|
266
|
+
const currentBorder = cellInfo?.tableNode?.attrs?.['border'] || {};
|
|
267
|
+
const mergedBorder = {
|
|
268
|
+
style: border.style !== undefined ? border.style : currentBorder.style || null,
|
|
269
|
+
color: border.color !== undefined ? border.color : currentBorder.color || null,
|
|
270
|
+
width: border.width !== undefined ? border.width : currentBorder.width || null
|
|
271
|
+
};
|
|
272
|
+
return chain().focus().updateAttributes('table', {
|
|
273
|
+
border: mergedBorder
|
|
274
|
+
}).run();
|
|
275
|
+
},
|
|
276
|
+
setTableBackgroundColor: (color)=>({ chain })=>{
|
|
277
|
+
return chain().focus().updateAttributes('table', {
|
|
278
|
+
backgroundColor: color ?? null
|
|
279
|
+
}).run();
|
|
280
|
+
},
|
|
281
|
+
insertTable: ({ rows, cols, withHeaderRow })=>({ tr, dispatch, editor })=>{
|
|
282
|
+
const { schema } = editor.state;
|
|
283
|
+
// --- BƯỚC 1: Tính toán colWidths ---
|
|
284
|
+
const calculatedColWidths = [];
|
|
285
|
+
const defaultWidth = 100 / cols;
|
|
286
|
+
for(let i = 0; i < cols; i += 1){
|
|
287
|
+
calculatedColWidths.push(defaultWidth);
|
|
288
|
+
}
|
|
289
|
+
// Ví dụ: cols = 3 -> calculatedColWidths = [33.33, 33.33, 33.33]
|
|
290
|
+
// --- BƯỚC 2: Tạo nội dung bảng (rows, cells) ---
|
|
291
|
+
// Chúng ta phải tự xây dựng các node con
|
|
292
|
+
const cellType = schema.nodes['tableCell'];
|
|
293
|
+
const headerType = schema.nodes['tableHeader'];
|
|
294
|
+
const rowType = schema.nodes['tableRow'];
|
|
295
|
+
const tableRows = [];
|
|
296
|
+
// Hàm trợ giúp tạo 1 cell rỗng
|
|
297
|
+
const createEmptyCell = (type)=>{
|
|
298
|
+
const emptyParagraph = schema.nodes['paragraph'].create();
|
|
299
|
+
return type.create(null, emptyParagraph);
|
|
300
|
+
};
|
|
301
|
+
// Tạo các hàng
|
|
302
|
+
for(let r = 0; r < rows; r += 1){
|
|
303
|
+
const tableCells = [];
|
|
304
|
+
for(let c = 0; c < cols; c += 1){
|
|
305
|
+
let cellNode;
|
|
306
|
+
// Nếu là hàng đầu tiên và có 'withHeaderRow'
|
|
307
|
+
if (r === 0 && withHeaderRow) {
|
|
308
|
+
cellNode = createEmptyCell(headerType);
|
|
309
|
+
} else {
|
|
310
|
+
cellNode = createEmptyCell(cellType);
|
|
311
|
+
}
|
|
312
|
+
tableCells.push(cellNode);
|
|
313
|
+
}
|
|
314
|
+
// Thêm hàng mới vào mảng các hàng
|
|
315
|
+
tableRows.push(rowType.create(null, tableCells));
|
|
316
|
+
}
|
|
317
|
+
// --- BƯỚC 3: Tạo node Table chính VỚI ATTRIBUTE 'colwidths' ---
|
|
318
|
+
const tableNode = schema.nodes['table'].create({
|
|
319
|
+
// Đây là mấu chốt: gán mảng % của chúng ta vào đây
|
|
320
|
+
colwidths: calculatedColWidths
|
|
321
|
+
}, tableRows // Nội dung (các node 'tableRow')
|
|
322
|
+
);
|
|
323
|
+
// --- BƯỚC 4: Dispatch transaction (Original code)---
|
|
324
|
+
if (dispatch) {
|
|
325
|
+
const offset = tr.selection.from + 1;
|
|
326
|
+
tr.replaceSelectionWith(tableNode).scrollIntoView().setSelection(_state.TextSelection.near(tr.doc.resolve(offset)));
|
|
327
|
+
}
|
|
328
|
+
return true;
|
|
329
|
+
},
|
|
330
|
+
// 2. LỆNH ADDCOLUMNAFTER
|
|
331
|
+
addColumnAfter: ()=>({ state, dispatch })=>{
|
|
332
|
+
const $cell = (0, _tables.selectionCell)(state);
|
|
333
|
+
if (!$cell) return false;
|
|
334
|
+
const table = $cell.node(-1);
|
|
335
|
+
const tablePos = $cell.start(-1) - 1;
|
|
336
|
+
const oldColWidths = table.attrs['colwidths'];
|
|
337
|
+
// Calculate column index
|
|
338
|
+
const map = _tables.TableMap.get(table);
|
|
339
|
+
const cellPosInTable = $cell.pos - $cell.start(-1);
|
|
340
|
+
const colIndex = map.colCount(cellPosInTable);
|
|
341
|
+
// Calculate new column widths - ensure no column goes below MIN_NEW_COL_WIDTH
|
|
342
|
+
const newColWidths = calculateColumnWidthsForNewColumn(oldColWidths);
|
|
343
|
+
// Insert new column width
|
|
344
|
+
newColWidths.splice(colIndex + 1, 0, MIN_NEW_COL_WIDTH);
|
|
345
|
+
if (dispatch) {
|
|
346
|
+
// Use the prosemirror-tables function directly to add column
|
|
347
|
+
// This modifies the transaction but doesn't dispatch it
|
|
348
|
+
(0, _tables.addColumnAfter)(state, (modifiedTr)=>{
|
|
349
|
+
// Add our colwidth changes to the same transaction
|
|
350
|
+
modifiedTr.setNodeMarkup(tablePos, null, {
|
|
351
|
+
...table.attrs,
|
|
352
|
+
colwidths: newColWidths
|
|
353
|
+
});
|
|
354
|
+
// Now dispatch the complete transaction
|
|
355
|
+
dispatch(modifiedTr.scrollIntoView());
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
return true;
|
|
359
|
+
},
|
|
360
|
+
// 3. LỆNH ADDCOLUMNBEFORE
|
|
361
|
+
addColumnBefore: ()=>({ state, dispatch })=>{
|
|
362
|
+
const $cell = (0, _tables.selectionCell)(state);
|
|
363
|
+
if (!$cell) return false;
|
|
364
|
+
const table = $cell.node(-1);
|
|
365
|
+
const tablePos = $cell.start(-1) - 1;
|
|
366
|
+
const oldColWidths = table.attrs['colwidths'];
|
|
367
|
+
// Calculate column index
|
|
368
|
+
const map = _tables.TableMap.get(table);
|
|
369
|
+
const cellPosInTable = $cell.pos - $cell.start(-1);
|
|
370
|
+
const colIndex = map.colCount(cellPosInTable);
|
|
371
|
+
// Calculate new column widths - ensure no column goes below MIN_NEW_COL_WIDTH
|
|
372
|
+
const newColWidths = calculateColumnWidthsForNewColumn(oldColWidths);
|
|
373
|
+
// Insert new column width at current column index (before)
|
|
374
|
+
newColWidths.splice(colIndex, 0, MIN_NEW_COL_WIDTH);
|
|
375
|
+
if (dispatch) {
|
|
376
|
+
(0, _tables.addColumnBefore)(state, (modifiedTr)=>{
|
|
377
|
+
modifiedTr.setNodeMarkup(tablePos, null, {
|
|
378
|
+
...table.attrs,
|
|
379
|
+
colwidths: newColWidths
|
|
380
|
+
});
|
|
381
|
+
dispatch(modifiedTr.scrollIntoView());
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
return true;
|
|
385
|
+
},
|
|
386
|
+
// 4. LỆNH DELETECOLUMN
|
|
387
|
+
deleteColumn: ()=>({ state, dispatch })=>{
|
|
388
|
+
const $cell = (0, _tables.selectionCell)(state);
|
|
389
|
+
if (!$cell) return false;
|
|
390
|
+
const table = $cell.node(-1);
|
|
391
|
+
const tablePos = $cell.start(-1) - 1;
|
|
392
|
+
const oldColWidths = table.attrs['colwidths'];
|
|
393
|
+
// Calculate column index
|
|
394
|
+
const map = _tables.TableMap.get(table);
|
|
395
|
+
const cellPosInTable = $cell.pos - $cell.start(-1);
|
|
396
|
+
const colIndex = map.colCount(cellPosInTable);
|
|
397
|
+
// Get width of column being removed
|
|
398
|
+
const removedWidth = oldColWidths[colIndex];
|
|
399
|
+
// Create array of remaining columns
|
|
400
|
+
const remainingWidths = oldColWidths.filter((_, i)=>i !== colIndex);
|
|
401
|
+
// Distribute removed width among remaining columns
|
|
402
|
+
const gainPerCol = removedWidth / remainingWidths.length;
|
|
403
|
+
const newColWidths = remainingWidths.map((w)=>w + gainPerCol);
|
|
404
|
+
if (dispatch) {
|
|
405
|
+
(0, _tables.deleteColumn)(state, (modifiedTr)=>{
|
|
406
|
+
modifiedTr.setNodeMarkup(tablePos, null, {
|
|
407
|
+
...table.attrs,
|
|
408
|
+
colwidths: newColWidths
|
|
409
|
+
});
|
|
410
|
+
dispatch(modifiedTr.scrollIntoView());
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
return true;
|
|
414
|
+
},
|
|
415
|
+
// Cell
|
|
416
|
+
setCellBorder: (border)=>({ chain, state })=>{
|
|
417
|
+
if (!border) return chain().focus().updateAttributes('tableCell', {
|
|
418
|
+
border: null
|
|
419
|
+
}).updateAttributes('tableHeader', {
|
|
420
|
+
border: null
|
|
421
|
+
}).run();
|
|
422
|
+
// Get current border and merge with new values
|
|
423
|
+
const { selection } = state;
|
|
424
|
+
const { $from } = selection;
|
|
425
|
+
const cellPos = $from.node(-1);
|
|
426
|
+
const currentBorder = cellPos?.attrs?.['border'] || {};
|
|
427
|
+
const mergedBorder = {
|
|
428
|
+
style: border.style ? border.style : currentBorder.style || null,
|
|
429
|
+
color: border.color ? border.color : currentBorder.color || null,
|
|
430
|
+
width: border.width ? border.width : currentBorder.width || null
|
|
431
|
+
};
|
|
432
|
+
return chain().focus().updateAttributes('tableCell', {
|
|
433
|
+
border: mergedBorder
|
|
434
|
+
}).updateAttributes('tableHeader', {
|
|
435
|
+
border: mergedBorder
|
|
436
|
+
}).run();
|
|
437
|
+
},
|
|
438
|
+
setCellVerticalAlign: (align)=>({ chain })=>{
|
|
439
|
+
return chain().focus().updateAttributes('tableCell', {
|
|
440
|
+
verticalAlign: align ?? null
|
|
441
|
+
}).updateAttributes('tableHeader', {
|
|
442
|
+
verticalAlign: align ?? null
|
|
443
|
+
}).run();
|
|
444
|
+
},
|
|
445
|
+
setCellTextAlign: (align)=>({ chain })=>{
|
|
446
|
+
return chain().focus().updateAttributes('tableCell', {
|
|
447
|
+
textAlign: align ?? null
|
|
448
|
+
}).updateAttributes('tableHeader', {
|
|
449
|
+
textAlign: align ?? null
|
|
450
|
+
}).run();
|
|
451
|
+
},
|
|
452
|
+
setCellBackgroundColor: (color)=>({ chain })=>{
|
|
453
|
+
// Set all cells to the same background color
|
|
454
|
+
return chain().focus().updateAttributes('tableCell', {
|
|
455
|
+
backgroundColor: color ?? null
|
|
456
|
+
}).updateAttributes('tableHeader', {
|
|
457
|
+
backgroundColor: color ?? null
|
|
458
|
+
}).run();
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
},
|
|
462
|
+
addNodeView () {
|
|
463
|
+
// Only use custom NodeView (with handle) when editor is editable
|
|
464
|
+
return (props)=>{
|
|
465
|
+
// Check if editor is editable
|
|
466
|
+
if (!props.editor.isEditable) {
|
|
467
|
+
// Return undefined to use default table rendering (no widget wrapper)
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
// Editor is editable → use custom NodeView with handle
|
|
471
|
+
return (0, _views.createTableNodeView)(props);
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
const StyledTableKit = _core.Extension.create({
|
|
476
|
+
name: 'styledTableKit',
|
|
477
|
+
addExtensions () {
|
|
478
|
+
const extensions = [];
|
|
479
|
+
if (this.options.table !== false) {
|
|
480
|
+
extensions.push(StyledTable.configure({
|
|
481
|
+
...this.options.table,
|
|
482
|
+
resizable: false
|
|
483
|
+
}));
|
|
484
|
+
}
|
|
485
|
+
if (this.options.tableRow !== false) {
|
|
486
|
+
extensions.push(_extensiontable.TableRow.configure(this.options.tableRow));
|
|
487
|
+
}
|
|
488
|
+
if (this.options.tableHeader !== false) {
|
|
489
|
+
extensions.push(StyledTableHeader.configure(this.options.tableHeader));
|
|
490
|
+
}
|
|
491
|
+
if (this.options.tableCell !== false) {
|
|
492
|
+
extensions.push(StyledTableCell.configure(this.options.tableCell));
|
|
493
|
+
}
|
|
494
|
+
if (this.options.table?.resizable !== false) {
|
|
495
|
+
extensions.push(_tableresizingextension.PercentageColumnResizing);
|
|
496
|
+
}
|
|
497
|
+
return extensions;
|
|
498
|
+
}
|
|
499
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
import { TextCaseType } from '../types';
|
|
3
|
+
export interface TextCaseOptions {
|
|
4
|
+
type: TextCaseType;
|
|
5
|
+
}
|
|
6
|
+
declare module '@tiptap/core' {
|
|
7
|
+
interface Commands<ReturnType> {
|
|
8
|
+
textCase: {
|
|
9
|
+
textCase: (type: TextCaseOptions['type']) => ReturnType;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export declare const TextCase: Extension<TextCaseOptions, any>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "TextCase", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return TextCase;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _core = require("@tiptap/core");
|
|
12
|
+
const _state = require("@tiptap/pm/state");
|
|
13
|
+
const TextCase = _core.Extension.create({
|
|
14
|
+
name: 'textCase',
|
|
15
|
+
addOptions () {
|
|
16
|
+
return {
|
|
17
|
+
type: 'uppercase'
|
|
18
|
+
};
|
|
19
|
+
},
|
|
20
|
+
addCommands () {
|
|
21
|
+
return {
|
|
22
|
+
textCase: (type)=>({ tr, state })=>{
|
|
23
|
+
const { $from, $to, empty } = tr.selection;
|
|
24
|
+
// If selection is empty, return false
|
|
25
|
+
if (empty) return false;
|
|
26
|
+
// If selection is not empty, get the text of the selection
|
|
27
|
+
const text = state.doc.textBetween($from.pos, $to.pos, '\n', '\n');
|
|
28
|
+
// If text is empty, return false
|
|
29
|
+
if (text.length === 0) return false;
|
|
30
|
+
let newText = text;
|
|
31
|
+
// Change the text case
|
|
32
|
+
switch(type){
|
|
33
|
+
case 'uppercase':
|
|
34
|
+
newText = text.toUpperCase();
|
|
35
|
+
break;
|
|
36
|
+
case 'lowercase':
|
|
37
|
+
newText = text.toLowerCase();
|
|
38
|
+
break;
|
|
39
|
+
case 'capitalize':
|
|
40
|
+
newText = text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
tr.replaceWith($from.pos, $to.pos, state.schema.text(newText));
|
|
44
|
+
tr.setSelection(_state.TextSelection.create(tr.doc, $from.pos, $from.pos + newText.length));
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
});
|
package/src/index.d.ts
ADDED
package/src/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
_export_star(require("./constants"), exports);
|
|
6
|
+
_export_star(require("./extensions"), exports);
|
|
7
|
+
_export_star(require("./models"), exports);
|
|
8
|
+
_export_star(require("./nodes"), exports);
|
|
9
|
+
_export_star(require("./types"), exports);
|
|
10
|
+
_export_star(require("./utils"), exports);
|
|
11
|
+
_export_star(require("./views"), exports);
|
|
12
|
+
function _export_star(from, to) {
|
|
13
|
+
Object.keys(from).forEach(function(k) {
|
|
14
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
15
|
+
Object.defineProperty(to, k, {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function() {
|
|
18
|
+
return from[k];
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
return from;
|
|
24
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare class Color {
|
|
2
|
+
readonly value: string;
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly type?: 'rgb' | 'hex';
|
|
5
|
+
private constructor();
|
|
6
|
+
static from(value: string, name?: string, type?: 'rgb' | 'hex'): Color;
|
|
7
|
+
static fromArray(colors: (string | {
|
|
8
|
+
value: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
type?: 'rgb' | 'hex';
|
|
11
|
+
})[]): Color[];
|
|
12
|
+
equals(color: Color): boolean;
|
|
13
|
+
is(color: string): boolean;
|
|
14
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "Color", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return Color;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _utils = require("../utils");
|
|
12
|
+
class Color {
|
|
13
|
+
static from(value, name, type) {
|
|
14
|
+
return new Color(value, name, type);
|
|
15
|
+
}
|
|
16
|
+
static fromArray(colors) {
|
|
17
|
+
return colors.map((color)=>{
|
|
18
|
+
if (typeof color === 'string') {
|
|
19
|
+
return new Color(color);
|
|
20
|
+
}
|
|
21
|
+
return new Color(color.value, color.name, color.type);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
equals(color) {
|
|
25
|
+
return this.value === color.value;
|
|
26
|
+
}
|
|
27
|
+
is(color) {
|
|
28
|
+
return this.value === (0, _utils.normalizeColor)(color);
|
|
29
|
+
}
|
|
30
|
+
constructor(value, name, type){
|
|
31
|
+
const normalizedColor = (0, _utils.normalizeColor)(value);
|
|
32
|
+
if (!normalizedColor) {
|
|
33
|
+
throw new Error('Invalid or unsupported color.');
|
|
34
|
+
}
|
|
35
|
+
this.value = normalizedColor;
|
|
36
|
+
this.name = name ?? normalizedColor;
|
|
37
|
+
this.type = type;
|
|
38
|
+
Object.freeze(this);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './color.model';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
_export_star(require("./color.model"), exports);
|
|
6
|
+
function _export_star(from, to) {
|
|
7
|
+
Object.keys(from).forEach(function(k) {
|
|
8
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
9
|
+
Object.defineProperty(to, k, {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
get: function() {
|
|
12
|
+
return from[k];
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
return from;
|
|
18
|
+
}
|