@youcan/celeste 0.6.30 → 0.6.32
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/celeste.css +483 -264
- package/dist/cjs/alert.js +2 -2
- package/dist/cjs/chunks/index.js +229 -2
- package/dist/cjs/chunks/index2.js +1457 -0
- package/dist/cjs/chunks/index3.js +16457 -0
- package/dist/cjs/chunks/sonner.js +1154 -0
- package/dist/cjs/config.js +136 -0
- package/dist/cjs/extra-settings.js +155 -0
- package/dist/cjs/index.js +75 -0
- package/dist/cjs/label.js +2 -2
- package/dist/cjs/link-bubble.js +228 -0
- package/dist/cjs/link-button.js +2 -2
- package/dist/cjs/rich-editor.js +4996 -0
- package/dist/cjs/select-icon.js +2 -2
- package/dist/cjs/sonner-alert.js +41 -0
- package/dist/cjs/sonner.js +3 -0
- package/dist/cjs/text-input-affix.js +2 -2
- package/dist/cjs/types.js +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/rich-editor/config.d.ts +33 -0
- package/dist/components/rich-editor/extra-settings.d.ts +6 -0
- package/dist/components/rich-editor/index.d.ts +2 -0
- package/dist/components/rich-editor/link-bubble.d.ts +11 -0
- package/dist/components/rich-editor/rich-editor.d.ts +55 -0
- package/dist/components/rich-editor/types.d.ts +19 -0
- package/dist/components/sonner/index.d.ts +4 -0
- package/dist/components/sonner/sonner-alert.d.ts +13 -0
- package/dist/components/sonner/sonner.d.ts +5 -0
- package/dist/es/alert.js +2 -2
- package/dist/es/checkbox-label.js +1 -1
- package/dist/es/chunks/index.js +277 -50
- package/dist/es/chunks/index2.js +1457 -0
- package/dist/es/chunks/index3.js +16458 -0
- package/dist/es/chunks/sonner.js +1155 -0
- package/dist/es/combobox-group.js +1 -1
- package/dist/es/combobox-input.js +1 -1
- package/dist/es/combobox-item.js +1 -1
- package/dist/es/combobox-list.js +1 -1
- package/dist/es/combobox-root.js +1 -1
- package/dist/es/combobox-separator.js +1 -1
- package/dist/es/combobox-trigger.js +1 -1
- package/dist/es/command-group.js +1 -1
- package/dist/es/command-input.js +1 -1
- package/dist/es/command-item.js +1 -1
- package/dist/es/command-list.js +1 -1
- package/dist/es/command-root.js +1 -1
- package/dist/es/command-separator.js +1 -1
- package/dist/es/config.js +136 -0
- package/dist/es/dropdown-menu-group.js +1 -1
- package/dist/es/dropdown-menu-item.js +1 -1
- package/dist/es/dropdown-menu-label.js +1 -1
- package/dist/es/dropdown-menu-separator.js +1 -1
- package/dist/es/dropdown-menu-trigger.js +1 -1
- package/dist/es/dropdown-menu.js +1 -1
- package/dist/es/dropdown.js +1 -1
- package/dist/es/extra-settings.js +156 -0
- package/dist/es/index.js +94 -19
- package/dist/es/label.js +3 -3
- package/dist/es/link-bubble.js +229 -0
- package/dist/es/link-button.js +2 -2
- package/dist/es/modal-content.js +1 -1
- package/dist/es/modal-header.js +1 -1
- package/dist/es/popover-content.js +1 -1
- package/dist/es/popover-trigger.js +1 -1
- package/dist/es/rich-editor.js +4997 -0
- package/dist/es/scroll-bar.js +1 -1
- package/dist/es/segmented-control-item.js +1 -1
- package/dist/es/segmented-control.js +1 -1
- package/dist/es/select-content.js +1 -1
- package/dist/es/select-icon.js +2 -2
- package/dist/es/select-item.js +1 -1
- package/dist/es/select-trigger.js +1 -1
- package/dist/es/select-value.js +1 -1
- package/dist/es/sonner-alert.js +42 -0
- package/dist/es/sonner.js +4 -0
- package/dist/es/tab-menu-content.js +1 -1
- package/dist/es/tab-menu-item.js +1 -1
- package/dist/es/tab-menu-list.js +1 -1
- package/dist/es/tab-menu.js +1 -1
- package/dist/es/text-input-affix.js +2 -2
- package/dist/es/tooltip.js +1 -1
- package/dist/es/types.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/sonner.d.ts +19 -0
- package/package.json +15 -4
- package/src/components/index.ts +2 -0
- package/src/components/rich-editor/config.ts +150 -0
- package/src/components/rich-editor/extra-settings.vue +151 -0
- package/src/components/rich-editor/index.ts +2 -0
- package/src/components/rich-editor/link-bubble.vue +288 -0
- package/src/components/rich-editor/rich-editor.vue +428 -0
- package/src/components/rich-editor/stories/rich-editor.stories.ts +87 -0
- package/src/components/rich-editor/types.ts +21 -0
- package/src/components/sonner/index.ts +5 -0
- package/src/components/sonner/sonner-alert.vue +54 -0
- package/src/components/sonner/sonner.vue +13 -0
- package/src/components/sonner/stories/sonner.stories.ts +194 -0
- package/src/index.ts +1 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/sonner.ts +72 -0
|
@@ -0,0 +1,1457 @@
|
|
|
1
|
+
import { P as PluginKey, S as Selection, k as keydownHandler, a as SelectionRange, T as TextSelection, F as Fragment, b as Slice, E as Extension, c as Plugin, i as isTextSelection, p as posToDOMRect, g as getText, d as getTextSerializersFromSchema } from "./index3.js";
|
|
2
|
+
import { g as flip, s as shift, l as offset, p as arrow$1, r as size, v as autoPlacement, B as hide, D as inline, E as computePosition } from "./index.js";
|
|
3
|
+
import { defineComponent, ref, onMounted, onBeforeUnmount, h, Teleport } from "vue";
|
|
4
|
+
var readFromCache;
|
|
5
|
+
var addToCache;
|
|
6
|
+
if (typeof WeakMap != "undefined") {
|
|
7
|
+
let cache = /* @__PURE__ */ new WeakMap();
|
|
8
|
+
readFromCache = (key) => cache.get(key);
|
|
9
|
+
addToCache = (key, value) => {
|
|
10
|
+
cache.set(key, value);
|
|
11
|
+
return value;
|
|
12
|
+
};
|
|
13
|
+
} else {
|
|
14
|
+
const cache = [];
|
|
15
|
+
const cacheSize = 10;
|
|
16
|
+
let cachePos = 0;
|
|
17
|
+
readFromCache = (key) => {
|
|
18
|
+
for (let i = 0; i < cache.length; i += 2)
|
|
19
|
+
if (cache[i] == key) return cache[i + 1];
|
|
20
|
+
};
|
|
21
|
+
addToCache = (key, value) => {
|
|
22
|
+
if (cachePos == cacheSize) cachePos = 0;
|
|
23
|
+
cache[cachePos++] = key;
|
|
24
|
+
return cache[cachePos++] = value;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
var TableMap = class {
|
|
28
|
+
constructor(width, height, map, problems) {
|
|
29
|
+
this.width = width;
|
|
30
|
+
this.height = height;
|
|
31
|
+
this.map = map;
|
|
32
|
+
this.problems = problems;
|
|
33
|
+
}
|
|
34
|
+
// Find the dimensions of the cell at the given position.
|
|
35
|
+
findCell(pos) {
|
|
36
|
+
for (let i = 0; i < this.map.length; i++) {
|
|
37
|
+
const curPos = this.map[i];
|
|
38
|
+
if (curPos != pos) continue;
|
|
39
|
+
const left = i % this.width;
|
|
40
|
+
const top = i / this.width | 0;
|
|
41
|
+
let right = left + 1;
|
|
42
|
+
let bottom = top + 1;
|
|
43
|
+
for (let j = 1; right < this.width && this.map[i + j] == curPos; j++) {
|
|
44
|
+
right++;
|
|
45
|
+
}
|
|
46
|
+
for (let j = 1; bottom < this.height && this.map[i + this.width * j] == curPos; j++) {
|
|
47
|
+
bottom++;
|
|
48
|
+
}
|
|
49
|
+
return { left, top, right, bottom };
|
|
50
|
+
}
|
|
51
|
+
throw new RangeError(`No cell with offset ${pos} found`);
|
|
52
|
+
}
|
|
53
|
+
// Find the left side of the cell at the given position.
|
|
54
|
+
colCount(pos) {
|
|
55
|
+
for (let i = 0; i < this.map.length; i++) {
|
|
56
|
+
if (this.map[i] == pos) {
|
|
57
|
+
return i % this.width;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
throw new RangeError(`No cell with offset ${pos} found`);
|
|
61
|
+
}
|
|
62
|
+
// Find the next cell in the given direction, starting from the cell
|
|
63
|
+
// at `pos`, if any.
|
|
64
|
+
nextCell(pos, axis, dir) {
|
|
65
|
+
const { left, right, top, bottom } = this.findCell(pos);
|
|
66
|
+
if (axis == "horiz") {
|
|
67
|
+
if (dir < 0 ? left == 0 : right == this.width) return null;
|
|
68
|
+
return this.map[top * this.width + (dir < 0 ? left - 1 : right)];
|
|
69
|
+
} else {
|
|
70
|
+
if (dir < 0 ? top == 0 : bottom == this.height) return null;
|
|
71
|
+
return this.map[left + this.width * (dir < 0 ? top - 1 : bottom)];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Get the rectangle spanning the two given cells.
|
|
75
|
+
rectBetween(a, b) {
|
|
76
|
+
const {
|
|
77
|
+
left: leftA,
|
|
78
|
+
right: rightA,
|
|
79
|
+
top: topA,
|
|
80
|
+
bottom: bottomA
|
|
81
|
+
} = this.findCell(a);
|
|
82
|
+
const {
|
|
83
|
+
left: leftB,
|
|
84
|
+
right: rightB,
|
|
85
|
+
top: topB,
|
|
86
|
+
bottom: bottomB
|
|
87
|
+
} = this.findCell(b);
|
|
88
|
+
return {
|
|
89
|
+
left: Math.min(leftA, leftB),
|
|
90
|
+
top: Math.min(topA, topB),
|
|
91
|
+
right: Math.max(rightA, rightB),
|
|
92
|
+
bottom: Math.max(bottomA, bottomB)
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
// Return the position of all cells that have the top left corner in
|
|
96
|
+
// the given rectangle.
|
|
97
|
+
cellsInRect(rect) {
|
|
98
|
+
const result = [];
|
|
99
|
+
const seen = {};
|
|
100
|
+
for (let row = rect.top; row < rect.bottom; row++) {
|
|
101
|
+
for (let col = rect.left; col < rect.right; col++) {
|
|
102
|
+
const index = row * this.width + col;
|
|
103
|
+
const pos = this.map[index];
|
|
104
|
+
if (seen[pos]) continue;
|
|
105
|
+
seen[pos] = true;
|
|
106
|
+
if (col == rect.left && col && this.map[index - 1] == pos || row == rect.top && row && this.map[index - this.width] == pos) {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
result.push(pos);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
// Return the position at which the cell at the given row and column
|
|
115
|
+
// starts, or would start, if a cell started there.
|
|
116
|
+
positionAt(row, col, table) {
|
|
117
|
+
for (let i = 0, rowStart = 0; ; i++) {
|
|
118
|
+
const rowEnd = rowStart + table.child(i).nodeSize;
|
|
119
|
+
if (i == row) {
|
|
120
|
+
let index = col + row * this.width;
|
|
121
|
+
const rowEndIndex = (row + 1) * this.width;
|
|
122
|
+
while (index < rowEndIndex && this.map[index] < rowStart) index++;
|
|
123
|
+
return index == rowEndIndex ? rowEnd - 1 : this.map[index];
|
|
124
|
+
}
|
|
125
|
+
rowStart = rowEnd;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Find the table map for the given table node.
|
|
129
|
+
static get(table) {
|
|
130
|
+
return readFromCache(table) || addToCache(table, computeMap(table));
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
function computeMap(table) {
|
|
134
|
+
if (table.type.spec.tableRole != "table")
|
|
135
|
+
throw new RangeError("Not a table node: " + table.type.name);
|
|
136
|
+
const width = findWidth(table), height = table.childCount;
|
|
137
|
+
const map = [];
|
|
138
|
+
let mapPos = 0;
|
|
139
|
+
let problems = null;
|
|
140
|
+
const colWidths = [];
|
|
141
|
+
for (let i = 0, e = width * height; i < e; i++) map[i] = 0;
|
|
142
|
+
for (let row = 0, pos = 0; row < height; row++) {
|
|
143
|
+
const rowNode = table.child(row);
|
|
144
|
+
pos++;
|
|
145
|
+
for (let i = 0; ; i++) {
|
|
146
|
+
while (mapPos < map.length && map[mapPos] != 0) mapPos++;
|
|
147
|
+
if (i == rowNode.childCount) break;
|
|
148
|
+
const cellNode = rowNode.child(i);
|
|
149
|
+
const { colspan, rowspan, colwidth } = cellNode.attrs;
|
|
150
|
+
for (let h2 = 0; h2 < rowspan; h2++) {
|
|
151
|
+
if (h2 + row >= height) {
|
|
152
|
+
(problems || (problems = [])).push({
|
|
153
|
+
type: "overlong_rowspan",
|
|
154
|
+
pos,
|
|
155
|
+
n: rowspan - h2
|
|
156
|
+
});
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
const start = mapPos + h2 * width;
|
|
160
|
+
for (let w = 0; w < colspan; w++) {
|
|
161
|
+
if (map[start + w] == 0) map[start + w] = pos;
|
|
162
|
+
else
|
|
163
|
+
(problems || (problems = [])).push({
|
|
164
|
+
type: "collision",
|
|
165
|
+
row,
|
|
166
|
+
pos,
|
|
167
|
+
n: colspan - w
|
|
168
|
+
});
|
|
169
|
+
const colW = colwidth && colwidth[w];
|
|
170
|
+
if (colW) {
|
|
171
|
+
const widthIndex = (start + w) % width * 2, prev = colWidths[widthIndex];
|
|
172
|
+
if (prev == null || prev != colW && colWidths[widthIndex + 1] == 1) {
|
|
173
|
+
colWidths[widthIndex] = colW;
|
|
174
|
+
colWidths[widthIndex + 1] = 1;
|
|
175
|
+
} else if (prev == colW) {
|
|
176
|
+
colWidths[widthIndex + 1]++;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
mapPos += colspan;
|
|
182
|
+
pos += cellNode.nodeSize;
|
|
183
|
+
}
|
|
184
|
+
const expectedPos = (row + 1) * width;
|
|
185
|
+
let missing = 0;
|
|
186
|
+
while (mapPos < expectedPos) if (map[mapPos++] == 0) missing++;
|
|
187
|
+
if (missing)
|
|
188
|
+
(problems || (problems = [])).push({ type: "missing", row, n: missing });
|
|
189
|
+
pos++;
|
|
190
|
+
}
|
|
191
|
+
if (width === 0 || height === 0)
|
|
192
|
+
(problems || (problems = [])).push({ type: "zero_sized" });
|
|
193
|
+
const tableMap = new TableMap(width, height, map, problems);
|
|
194
|
+
let badWidths = false;
|
|
195
|
+
for (let i = 0; !badWidths && i < colWidths.length; i += 2)
|
|
196
|
+
if (colWidths[i] != null && colWidths[i + 1] < height) badWidths = true;
|
|
197
|
+
if (badWidths) findBadColWidths(tableMap, colWidths, table);
|
|
198
|
+
return tableMap;
|
|
199
|
+
}
|
|
200
|
+
function findWidth(table) {
|
|
201
|
+
let width = -1;
|
|
202
|
+
let hasRowSpan = false;
|
|
203
|
+
for (let row = 0; row < table.childCount; row++) {
|
|
204
|
+
const rowNode = table.child(row);
|
|
205
|
+
let rowWidth = 0;
|
|
206
|
+
if (hasRowSpan)
|
|
207
|
+
for (let j = 0; j < row; j++) {
|
|
208
|
+
const prevRow = table.child(j);
|
|
209
|
+
for (let i = 0; i < prevRow.childCount; i++) {
|
|
210
|
+
const cell = prevRow.child(i);
|
|
211
|
+
if (j + cell.attrs.rowspan > row) rowWidth += cell.attrs.colspan;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
for (let i = 0; i < rowNode.childCount; i++) {
|
|
215
|
+
const cell = rowNode.child(i);
|
|
216
|
+
rowWidth += cell.attrs.colspan;
|
|
217
|
+
if (cell.attrs.rowspan > 1) hasRowSpan = true;
|
|
218
|
+
}
|
|
219
|
+
if (width == -1) width = rowWidth;
|
|
220
|
+
else if (width != rowWidth) width = Math.max(width, rowWidth);
|
|
221
|
+
}
|
|
222
|
+
return width;
|
|
223
|
+
}
|
|
224
|
+
function findBadColWidths(map, colWidths, table) {
|
|
225
|
+
if (!map.problems) map.problems = [];
|
|
226
|
+
const seen = {};
|
|
227
|
+
for (let i = 0; i < map.map.length; i++) {
|
|
228
|
+
const pos = map.map[i];
|
|
229
|
+
if (seen[pos]) continue;
|
|
230
|
+
seen[pos] = true;
|
|
231
|
+
const node = table.nodeAt(pos);
|
|
232
|
+
if (!node) {
|
|
233
|
+
throw new RangeError(`No cell with offset ${pos} found`);
|
|
234
|
+
}
|
|
235
|
+
let updated = null;
|
|
236
|
+
const attrs = node.attrs;
|
|
237
|
+
for (let j = 0; j < attrs.colspan; j++) {
|
|
238
|
+
const col = (i + j) % map.width;
|
|
239
|
+
const colWidth = colWidths[col * 2];
|
|
240
|
+
if (colWidth != null && (!attrs.colwidth || attrs.colwidth[j] != colWidth))
|
|
241
|
+
(updated || (updated = freshColWidth(attrs)))[j] = colWidth;
|
|
242
|
+
}
|
|
243
|
+
if (updated)
|
|
244
|
+
map.problems.unshift({
|
|
245
|
+
type: "colwidth mismatch",
|
|
246
|
+
pos,
|
|
247
|
+
colwidth: updated
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function freshColWidth(attrs) {
|
|
252
|
+
if (attrs.colwidth) return attrs.colwidth.slice();
|
|
253
|
+
const result = [];
|
|
254
|
+
for (let i = 0; i < attrs.colspan; i++) result.push(0);
|
|
255
|
+
return result;
|
|
256
|
+
}
|
|
257
|
+
function tableNodeTypes(schema) {
|
|
258
|
+
let result = schema.cached.tableNodeTypes;
|
|
259
|
+
if (!result) {
|
|
260
|
+
result = schema.cached.tableNodeTypes = {};
|
|
261
|
+
for (const name in schema.nodes) {
|
|
262
|
+
const type = schema.nodes[name], role = type.spec.tableRole;
|
|
263
|
+
if (role) result[role] = type;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return result;
|
|
267
|
+
}
|
|
268
|
+
new PluginKey("selectingCells");
|
|
269
|
+
function cellAround($pos) {
|
|
270
|
+
for (let d = $pos.depth - 1; d > 0; d--)
|
|
271
|
+
if ($pos.node(d).type.spec.tableRole == "row")
|
|
272
|
+
return $pos.node(0).resolve($pos.before(d + 1));
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
function isInTable(state) {
|
|
276
|
+
const $head = state.selection.$head;
|
|
277
|
+
for (let d = $head.depth; d > 0; d--)
|
|
278
|
+
if ($head.node(d).type.spec.tableRole == "row") return true;
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
function selectionCell(state) {
|
|
282
|
+
const sel = state.selection;
|
|
283
|
+
if ("$anchorCell" in sel && sel.$anchorCell) {
|
|
284
|
+
return sel.$anchorCell.pos > sel.$headCell.pos ? sel.$anchorCell : sel.$headCell;
|
|
285
|
+
} else if ("node" in sel && sel.node && sel.node.type.spec.tableRole == "cell") {
|
|
286
|
+
return sel.$anchor;
|
|
287
|
+
}
|
|
288
|
+
const $cell = cellAround(sel.$head) || cellNear(sel.$head);
|
|
289
|
+
if ($cell) {
|
|
290
|
+
return $cell;
|
|
291
|
+
}
|
|
292
|
+
throw new RangeError(`No cell found around position ${sel.head}`);
|
|
293
|
+
}
|
|
294
|
+
function cellNear($pos) {
|
|
295
|
+
for (let after = $pos.nodeAfter, pos = $pos.pos; after; after = after.firstChild, pos++) {
|
|
296
|
+
const role = after.type.spec.tableRole;
|
|
297
|
+
if (role == "cell" || role == "header_cell") return $pos.doc.resolve(pos);
|
|
298
|
+
}
|
|
299
|
+
for (let before = $pos.nodeBefore, pos = $pos.pos; before; before = before.lastChild, pos--) {
|
|
300
|
+
const role = before.type.spec.tableRole;
|
|
301
|
+
if (role == "cell" || role == "header_cell")
|
|
302
|
+
return $pos.doc.resolve(pos - before.nodeSize);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
function pointsAtCell($pos) {
|
|
306
|
+
return $pos.parent.type.spec.tableRole == "row" && !!$pos.nodeAfter;
|
|
307
|
+
}
|
|
308
|
+
function inSameTable($cellA, $cellB) {
|
|
309
|
+
return $cellA.depth == $cellB.depth && $cellA.pos >= $cellB.start(-1) && $cellA.pos <= $cellB.end(-1);
|
|
310
|
+
}
|
|
311
|
+
function nextCell($pos, axis, dir) {
|
|
312
|
+
const table = $pos.node(-1);
|
|
313
|
+
const map = TableMap.get(table);
|
|
314
|
+
const tableStart = $pos.start(-1);
|
|
315
|
+
const moved = map.nextCell($pos.pos - tableStart, axis, dir);
|
|
316
|
+
return moved == null ? null : $pos.node(0).resolve(tableStart + moved);
|
|
317
|
+
}
|
|
318
|
+
function removeColSpan(attrs, pos, n = 1) {
|
|
319
|
+
const result = { ...attrs, colspan: attrs.colspan - n };
|
|
320
|
+
if (result.colwidth) {
|
|
321
|
+
result.colwidth = result.colwidth.slice();
|
|
322
|
+
result.colwidth.splice(pos, n);
|
|
323
|
+
if (!result.colwidth.some((w) => w > 0)) result.colwidth = null;
|
|
324
|
+
}
|
|
325
|
+
return result;
|
|
326
|
+
}
|
|
327
|
+
var CellSelection = class _CellSelection extends Selection {
|
|
328
|
+
// A table selection is identified by its anchor and head cells. The
|
|
329
|
+
// positions given to this constructor should point _before_ two
|
|
330
|
+
// cells in the same table. They may be the same, to select a single
|
|
331
|
+
// cell.
|
|
332
|
+
constructor($anchorCell, $headCell = $anchorCell) {
|
|
333
|
+
const table = $anchorCell.node(-1);
|
|
334
|
+
const map = TableMap.get(table);
|
|
335
|
+
const tableStart = $anchorCell.start(-1);
|
|
336
|
+
const rect = map.rectBetween(
|
|
337
|
+
$anchorCell.pos - tableStart,
|
|
338
|
+
$headCell.pos - tableStart
|
|
339
|
+
);
|
|
340
|
+
const doc = $anchorCell.node(0);
|
|
341
|
+
const cells = map.cellsInRect(rect).filter((p) => p != $headCell.pos - tableStart);
|
|
342
|
+
cells.unshift($headCell.pos - tableStart);
|
|
343
|
+
const ranges = cells.map((pos) => {
|
|
344
|
+
const cell = table.nodeAt(pos);
|
|
345
|
+
if (!cell) {
|
|
346
|
+
throw RangeError(`No cell with offset ${pos} found`);
|
|
347
|
+
}
|
|
348
|
+
const from = tableStart + pos + 1;
|
|
349
|
+
return new SelectionRange(
|
|
350
|
+
doc.resolve(from),
|
|
351
|
+
doc.resolve(from + cell.content.size)
|
|
352
|
+
);
|
|
353
|
+
});
|
|
354
|
+
super(ranges[0].$from, ranges[0].$to, ranges);
|
|
355
|
+
this.$anchorCell = $anchorCell;
|
|
356
|
+
this.$headCell = $headCell;
|
|
357
|
+
}
|
|
358
|
+
map(doc, mapping) {
|
|
359
|
+
const $anchorCell = doc.resolve(mapping.map(this.$anchorCell.pos));
|
|
360
|
+
const $headCell = doc.resolve(mapping.map(this.$headCell.pos));
|
|
361
|
+
if (pointsAtCell($anchorCell) && pointsAtCell($headCell) && inSameTable($anchorCell, $headCell)) {
|
|
362
|
+
const tableChanged = this.$anchorCell.node(-1) != $anchorCell.node(-1);
|
|
363
|
+
if (tableChanged && this.isRowSelection())
|
|
364
|
+
return _CellSelection.rowSelection($anchorCell, $headCell);
|
|
365
|
+
else if (tableChanged && this.isColSelection())
|
|
366
|
+
return _CellSelection.colSelection($anchorCell, $headCell);
|
|
367
|
+
else return new _CellSelection($anchorCell, $headCell);
|
|
368
|
+
}
|
|
369
|
+
return TextSelection.between($anchorCell, $headCell);
|
|
370
|
+
}
|
|
371
|
+
// Returns a rectangular slice of table rows containing the selected
|
|
372
|
+
// cells.
|
|
373
|
+
content() {
|
|
374
|
+
const table = this.$anchorCell.node(-1);
|
|
375
|
+
const map = TableMap.get(table);
|
|
376
|
+
const tableStart = this.$anchorCell.start(-1);
|
|
377
|
+
const rect = map.rectBetween(
|
|
378
|
+
this.$anchorCell.pos - tableStart,
|
|
379
|
+
this.$headCell.pos - tableStart
|
|
380
|
+
);
|
|
381
|
+
const seen = {};
|
|
382
|
+
const rows = [];
|
|
383
|
+
for (let row = rect.top; row < rect.bottom; row++) {
|
|
384
|
+
const rowContent = [];
|
|
385
|
+
for (let index = row * map.width + rect.left, col = rect.left; col < rect.right; col++, index++) {
|
|
386
|
+
const pos = map.map[index];
|
|
387
|
+
if (seen[pos]) continue;
|
|
388
|
+
seen[pos] = true;
|
|
389
|
+
const cellRect = map.findCell(pos);
|
|
390
|
+
let cell = table.nodeAt(pos);
|
|
391
|
+
if (!cell) {
|
|
392
|
+
throw RangeError(`No cell with offset ${pos} found`);
|
|
393
|
+
}
|
|
394
|
+
const extraLeft = rect.left - cellRect.left;
|
|
395
|
+
const extraRight = cellRect.right - rect.right;
|
|
396
|
+
if (extraLeft > 0 || extraRight > 0) {
|
|
397
|
+
let attrs = cell.attrs;
|
|
398
|
+
if (extraLeft > 0) {
|
|
399
|
+
attrs = removeColSpan(attrs, 0, extraLeft);
|
|
400
|
+
}
|
|
401
|
+
if (extraRight > 0) {
|
|
402
|
+
attrs = removeColSpan(
|
|
403
|
+
attrs,
|
|
404
|
+
attrs.colspan - extraRight,
|
|
405
|
+
extraRight
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
if (cellRect.left < rect.left) {
|
|
409
|
+
cell = cell.type.createAndFill(attrs);
|
|
410
|
+
if (!cell) {
|
|
411
|
+
throw RangeError(
|
|
412
|
+
`Could not create cell with attrs ${JSON.stringify(attrs)}`
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
} else {
|
|
416
|
+
cell = cell.type.create(attrs, cell.content);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (cellRect.top < rect.top || cellRect.bottom > rect.bottom) {
|
|
420
|
+
const attrs = {
|
|
421
|
+
...cell.attrs,
|
|
422
|
+
rowspan: Math.min(cellRect.bottom, rect.bottom) - Math.max(cellRect.top, rect.top)
|
|
423
|
+
};
|
|
424
|
+
if (cellRect.top < rect.top) {
|
|
425
|
+
cell = cell.type.createAndFill(attrs);
|
|
426
|
+
} else {
|
|
427
|
+
cell = cell.type.create(attrs, cell.content);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
rowContent.push(cell);
|
|
431
|
+
}
|
|
432
|
+
rows.push(table.child(row).copy(Fragment.from(rowContent)));
|
|
433
|
+
}
|
|
434
|
+
const fragment = this.isColSelection() && this.isRowSelection() ? table : rows;
|
|
435
|
+
return new Slice(Fragment.from(fragment), 1, 1);
|
|
436
|
+
}
|
|
437
|
+
replace(tr, content = Slice.empty) {
|
|
438
|
+
const mapFrom = tr.steps.length, ranges = this.ranges;
|
|
439
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
440
|
+
const { $from, $to } = ranges[i], mapping = tr.mapping.slice(mapFrom);
|
|
441
|
+
tr.replace(
|
|
442
|
+
mapping.map($from.pos),
|
|
443
|
+
mapping.map($to.pos),
|
|
444
|
+
i ? Slice.empty : content
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
const sel = Selection.findFrom(
|
|
448
|
+
tr.doc.resolve(tr.mapping.slice(mapFrom).map(this.to)),
|
|
449
|
+
-1
|
|
450
|
+
);
|
|
451
|
+
if (sel) tr.setSelection(sel);
|
|
452
|
+
}
|
|
453
|
+
replaceWith(tr, node) {
|
|
454
|
+
this.replace(tr, new Slice(Fragment.from(node), 0, 0));
|
|
455
|
+
}
|
|
456
|
+
forEachCell(f) {
|
|
457
|
+
const table = this.$anchorCell.node(-1);
|
|
458
|
+
const map = TableMap.get(table);
|
|
459
|
+
const tableStart = this.$anchorCell.start(-1);
|
|
460
|
+
const cells = map.cellsInRect(
|
|
461
|
+
map.rectBetween(
|
|
462
|
+
this.$anchorCell.pos - tableStart,
|
|
463
|
+
this.$headCell.pos - tableStart
|
|
464
|
+
)
|
|
465
|
+
);
|
|
466
|
+
for (let i = 0; i < cells.length; i++) {
|
|
467
|
+
f(table.nodeAt(cells[i]), tableStart + cells[i]);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
// True if this selection goes all the way from the top to the
|
|
471
|
+
// bottom of the table.
|
|
472
|
+
isColSelection() {
|
|
473
|
+
const anchorTop = this.$anchorCell.index(-1);
|
|
474
|
+
const headTop = this.$headCell.index(-1);
|
|
475
|
+
if (Math.min(anchorTop, headTop) > 0) return false;
|
|
476
|
+
const anchorBottom = anchorTop + this.$anchorCell.nodeAfter.attrs.rowspan;
|
|
477
|
+
const headBottom = headTop + this.$headCell.nodeAfter.attrs.rowspan;
|
|
478
|
+
return Math.max(anchorBottom, headBottom) == this.$headCell.node(-1).childCount;
|
|
479
|
+
}
|
|
480
|
+
// Returns the smallest column selection that covers the given anchor
|
|
481
|
+
// and head cell.
|
|
482
|
+
static colSelection($anchorCell, $headCell = $anchorCell) {
|
|
483
|
+
const table = $anchorCell.node(-1);
|
|
484
|
+
const map = TableMap.get(table);
|
|
485
|
+
const tableStart = $anchorCell.start(-1);
|
|
486
|
+
const anchorRect = map.findCell($anchorCell.pos - tableStart);
|
|
487
|
+
const headRect = map.findCell($headCell.pos - tableStart);
|
|
488
|
+
const doc = $anchorCell.node(0);
|
|
489
|
+
if (anchorRect.top <= headRect.top) {
|
|
490
|
+
if (anchorRect.top > 0)
|
|
491
|
+
$anchorCell = doc.resolve(tableStart + map.map[anchorRect.left]);
|
|
492
|
+
if (headRect.bottom < map.height)
|
|
493
|
+
$headCell = doc.resolve(
|
|
494
|
+
tableStart + map.map[map.width * (map.height - 1) + headRect.right - 1]
|
|
495
|
+
);
|
|
496
|
+
} else {
|
|
497
|
+
if (headRect.top > 0)
|
|
498
|
+
$headCell = doc.resolve(tableStart + map.map[headRect.left]);
|
|
499
|
+
if (anchorRect.bottom < map.height)
|
|
500
|
+
$anchorCell = doc.resolve(
|
|
501
|
+
tableStart + map.map[map.width * (map.height - 1) + anchorRect.right - 1]
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
return new _CellSelection($anchorCell, $headCell);
|
|
505
|
+
}
|
|
506
|
+
// True if this selection goes all the way from the left to the
|
|
507
|
+
// right of the table.
|
|
508
|
+
isRowSelection() {
|
|
509
|
+
const table = this.$anchorCell.node(-1);
|
|
510
|
+
const map = TableMap.get(table);
|
|
511
|
+
const tableStart = this.$anchorCell.start(-1);
|
|
512
|
+
const anchorLeft = map.colCount(this.$anchorCell.pos - tableStart);
|
|
513
|
+
const headLeft = map.colCount(this.$headCell.pos - tableStart);
|
|
514
|
+
if (Math.min(anchorLeft, headLeft) > 0) return false;
|
|
515
|
+
const anchorRight = anchorLeft + this.$anchorCell.nodeAfter.attrs.colspan;
|
|
516
|
+
const headRight = headLeft + this.$headCell.nodeAfter.attrs.colspan;
|
|
517
|
+
return Math.max(anchorRight, headRight) == map.width;
|
|
518
|
+
}
|
|
519
|
+
eq(other) {
|
|
520
|
+
return other instanceof _CellSelection && other.$anchorCell.pos == this.$anchorCell.pos && other.$headCell.pos == this.$headCell.pos;
|
|
521
|
+
}
|
|
522
|
+
// Returns the smallest row selection that covers the given anchor
|
|
523
|
+
// and head cell.
|
|
524
|
+
static rowSelection($anchorCell, $headCell = $anchorCell) {
|
|
525
|
+
const table = $anchorCell.node(-1);
|
|
526
|
+
const map = TableMap.get(table);
|
|
527
|
+
const tableStart = $anchorCell.start(-1);
|
|
528
|
+
const anchorRect = map.findCell($anchorCell.pos - tableStart);
|
|
529
|
+
const headRect = map.findCell($headCell.pos - tableStart);
|
|
530
|
+
const doc = $anchorCell.node(0);
|
|
531
|
+
if (anchorRect.left <= headRect.left) {
|
|
532
|
+
if (anchorRect.left > 0)
|
|
533
|
+
$anchorCell = doc.resolve(
|
|
534
|
+
tableStart + map.map[anchorRect.top * map.width]
|
|
535
|
+
);
|
|
536
|
+
if (headRect.right < map.width)
|
|
537
|
+
$headCell = doc.resolve(
|
|
538
|
+
tableStart + map.map[map.width * (headRect.top + 1) - 1]
|
|
539
|
+
);
|
|
540
|
+
} else {
|
|
541
|
+
if (headRect.left > 0)
|
|
542
|
+
$headCell = doc.resolve(tableStart + map.map[headRect.top * map.width]);
|
|
543
|
+
if (anchorRect.right < map.width)
|
|
544
|
+
$anchorCell = doc.resolve(
|
|
545
|
+
tableStart + map.map[map.width * (anchorRect.top + 1) - 1]
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
return new _CellSelection($anchorCell, $headCell);
|
|
549
|
+
}
|
|
550
|
+
toJSON() {
|
|
551
|
+
return {
|
|
552
|
+
type: "cell",
|
|
553
|
+
anchor: this.$anchorCell.pos,
|
|
554
|
+
head: this.$headCell.pos
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
static fromJSON(doc, json) {
|
|
558
|
+
return new _CellSelection(doc.resolve(json.anchor), doc.resolve(json.head));
|
|
559
|
+
}
|
|
560
|
+
static create(doc, anchorCell, headCell = anchorCell) {
|
|
561
|
+
return new _CellSelection(doc.resolve(anchorCell), doc.resolve(headCell));
|
|
562
|
+
}
|
|
563
|
+
getBookmark() {
|
|
564
|
+
return new CellBookmark(this.$anchorCell.pos, this.$headCell.pos);
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
CellSelection.prototype.visible = false;
|
|
568
|
+
Selection.jsonID("cell", CellSelection);
|
|
569
|
+
var CellBookmark = class _CellBookmark {
|
|
570
|
+
constructor(anchor, head) {
|
|
571
|
+
this.anchor = anchor;
|
|
572
|
+
this.head = head;
|
|
573
|
+
}
|
|
574
|
+
map(mapping) {
|
|
575
|
+
return new _CellBookmark(mapping.map(this.anchor), mapping.map(this.head));
|
|
576
|
+
}
|
|
577
|
+
resolve(doc) {
|
|
578
|
+
const $anchorCell = doc.resolve(this.anchor), $headCell = doc.resolve(this.head);
|
|
579
|
+
if ($anchorCell.parent.type.spec.tableRole == "row" && $headCell.parent.type.spec.tableRole == "row" && $anchorCell.index() < $anchorCell.parent.childCount && $headCell.index() < $headCell.parent.childCount && inSameTable($anchorCell, $headCell))
|
|
580
|
+
return new CellSelection($anchorCell, $headCell);
|
|
581
|
+
else return Selection.near($headCell, 1);
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
new PluginKey("fix-tables");
|
|
585
|
+
function selectedRect(state) {
|
|
586
|
+
const sel = state.selection;
|
|
587
|
+
const $pos = selectionCell(state);
|
|
588
|
+
const table = $pos.node(-1);
|
|
589
|
+
const tableStart = $pos.start(-1);
|
|
590
|
+
const map = TableMap.get(table);
|
|
591
|
+
const rect = sel instanceof CellSelection ? map.rectBetween(
|
|
592
|
+
sel.$anchorCell.pos - tableStart,
|
|
593
|
+
sel.$headCell.pos - tableStart
|
|
594
|
+
) : map.findCell($pos.pos - tableStart);
|
|
595
|
+
return { ...rect, tableStart, map, table };
|
|
596
|
+
}
|
|
597
|
+
function deprecated_toggleHeader(type) {
|
|
598
|
+
return function(state, dispatch) {
|
|
599
|
+
if (!isInTable(state)) return false;
|
|
600
|
+
if (dispatch) {
|
|
601
|
+
const types = tableNodeTypes(state.schema);
|
|
602
|
+
const rect = selectedRect(state), tr = state.tr;
|
|
603
|
+
const cells = rect.map.cellsInRect(
|
|
604
|
+
type == "column" ? {
|
|
605
|
+
left: rect.left,
|
|
606
|
+
top: 0,
|
|
607
|
+
right: rect.right,
|
|
608
|
+
bottom: rect.map.height
|
|
609
|
+
} : type == "row" ? {
|
|
610
|
+
left: 0,
|
|
611
|
+
top: rect.top,
|
|
612
|
+
right: rect.map.width,
|
|
613
|
+
bottom: rect.bottom
|
|
614
|
+
} : rect
|
|
615
|
+
);
|
|
616
|
+
const nodes = cells.map((pos) => rect.table.nodeAt(pos));
|
|
617
|
+
for (let i = 0; i < cells.length; i++)
|
|
618
|
+
if (nodes[i].type == types.header_cell)
|
|
619
|
+
tr.setNodeMarkup(
|
|
620
|
+
rect.tableStart + cells[i],
|
|
621
|
+
types.cell,
|
|
622
|
+
nodes[i].attrs
|
|
623
|
+
);
|
|
624
|
+
if (tr.steps.length == 0)
|
|
625
|
+
for (let i = 0; i < cells.length; i++)
|
|
626
|
+
tr.setNodeMarkup(
|
|
627
|
+
rect.tableStart + cells[i],
|
|
628
|
+
types.header_cell,
|
|
629
|
+
nodes[i].attrs
|
|
630
|
+
);
|
|
631
|
+
dispatch(tr);
|
|
632
|
+
}
|
|
633
|
+
return true;
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
function isHeaderEnabledByType(type, rect, types) {
|
|
637
|
+
const cellPositions = rect.map.cellsInRect({
|
|
638
|
+
left: 0,
|
|
639
|
+
top: 0,
|
|
640
|
+
right: type == "row" ? rect.map.width : 1,
|
|
641
|
+
bottom: type == "column" ? rect.map.height : 1
|
|
642
|
+
});
|
|
643
|
+
for (let i = 0; i < cellPositions.length; i++) {
|
|
644
|
+
const cell = rect.table.nodeAt(cellPositions[i]);
|
|
645
|
+
if (cell && cell.type !== types.header_cell) {
|
|
646
|
+
return false;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
return true;
|
|
650
|
+
}
|
|
651
|
+
function toggleHeader(type, options) {
|
|
652
|
+
options = options || { useDeprecatedLogic: false };
|
|
653
|
+
if (options.useDeprecatedLogic) return deprecated_toggleHeader(type);
|
|
654
|
+
return function(state, dispatch) {
|
|
655
|
+
if (!isInTable(state)) return false;
|
|
656
|
+
if (dispatch) {
|
|
657
|
+
const types = tableNodeTypes(state.schema);
|
|
658
|
+
const rect = selectedRect(state), tr = state.tr;
|
|
659
|
+
const isHeaderRowEnabled = isHeaderEnabledByType("row", rect, types);
|
|
660
|
+
const isHeaderColumnEnabled = isHeaderEnabledByType(
|
|
661
|
+
"column",
|
|
662
|
+
rect,
|
|
663
|
+
types
|
|
664
|
+
);
|
|
665
|
+
const isHeaderEnabled = type === "column" ? isHeaderRowEnabled : type === "row" ? isHeaderColumnEnabled : false;
|
|
666
|
+
const selectionStartsAt = isHeaderEnabled ? 1 : 0;
|
|
667
|
+
const cellsRect = type == "column" ? {
|
|
668
|
+
left: 0,
|
|
669
|
+
top: selectionStartsAt,
|
|
670
|
+
right: 1,
|
|
671
|
+
bottom: rect.map.height
|
|
672
|
+
} : type == "row" ? {
|
|
673
|
+
left: selectionStartsAt,
|
|
674
|
+
top: 0,
|
|
675
|
+
right: rect.map.width,
|
|
676
|
+
bottom: 1
|
|
677
|
+
} : rect;
|
|
678
|
+
const newType = type == "column" ? isHeaderColumnEnabled ? types.cell : types.header_cell : type == "row" ? isHeaderRowEnabled ? types.cell : types.header_cell : types.cell;
|
|
679
|
+
rect.map.cellsInRect(cellsRect).forEach((relativeCellPos) => {
|
|
680
|
+
const cellPos = relativeCellPos + rect.tableStart;
|
|
681
|
+
const cell = tr.doc.nodeAt(cellPos);
|
|
682
|
+
if (cell) {
|
|
683
|
+
tr.setNodeMarkup(cellPos, newType, cell.attrs);
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
dispatch(tr);
|
|
687
|
+
}
|
|
688
|
+
return true;
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
toggleHeader("row", {
|
|
692
|
+
useDeprecatedLogic: true
|
|
693
|
+
});
|
|
694
|
+
toggleHeader("column", {
|
|
695
|
+
useDeprecatedLogic: true
|
|
696
|
+
});
|
|
697
|
+
toggleHeader("cell", {
|
|
698
|
+
useDeprecatedLogic: true
|
|
699
|
+
});
|
|
700
|
+
function deleteCellSelection(state, dispatch) {
|
|
701
|
+
const sel = state.selection;
|
|
702
|
+
if (!(sel instanceof CellSelection)) return false;
|
|
703
|
+
if (dispatch) {
|
|
704
|
+
const tr = state.tr;
|
|
705
|
+
const baseContent = tableNodeTypes(state.schema).cell.createAndFill().content;
|
|
706
|
+
sel.forEachCell((cell, pos) => {
|
|
707
|
+
if (!cell.content.eq(baseContent))
|
|
708
|
+
tr.replace(
|
|
709
|
+
tr.mapping.map(pos + 1),
|
|
710
|
+
tr.mapping.map(pos + cell.nodeSize - 1),
|
|
711
|
+
new Slice(baseContent, 0, 0)
|
|
712
|
+
);
|
|
713
|
+
});
|
|
714
|
+
if (tr.docChanged) dispatch(tr);
|
|
715
|
+
}
|
|
716
|
+
return true;
|
|
717
|
+
}
|
|
718
|
+
keydownHandler({
|
|
719
|
+
ArrowLeft: arrow("horiz", -1),
|
|
720
|
+
ArrowRight: arrow("horiz", 1),
|
|
721
|
+
ArrowUp: arrow("vert", -1),
|
|
722
|
+
ArrowDown: arrow("vert", 1),
|
|
723
|
+
"Shift-ArrowLeft": shiftArrow("horiz", -1),
|
|
724
|
+
"Shift-ArrowRight": shiftArrow("horiz", 1),
|
|
725
|
+
"Shift-ArrowUp": shiftArrow("vert", -1),
|
|
726
|
+
"Shift-ArrowDown": shiftArrow("vert", 1),
|
|
727
|
+
Backspace: deleteCellSelection,
|
|
728
|
+
"Mod-Backspace": deleteCellSelection,
|
|
729
|
+
Delete: deleteCellSelection,
|
|
730
|
+
"Mod-Delete": deleteCellSelection
|
|
731
|
+
});
|
|
732
|
+
function maybeSetSelection(state, dispatch, selection) {
|
|
733
|
+
if (selection.eq(state.selection)) return false;
|
|
734
|
+
if (dispatch) dispatch(state.tr.setSelection(selection).scrollIntoView());
|
|
735
|
+
return true;
|
|
736
|
+
}
|
|
737
|
+
function arrow(axis, dir) {
|
|
738
|
+
return (state, dispatch, view) => {
|
|
739
|
+
if (!view) return false;
|
|
740
|
+
const sel = state.selection;
|
|
741
|
+
if (sel instanceof CellSelection) {
|
|
742
|
+
return maybeSetSelection(
|
|
743
|
+
state,
|
|
744
|
+
dispatch,
|
|
745
|
+
Selection.near(sel.$headCell, dir)
|
|
746
|
+
);
|
|
747
|
+
}
|
|
748
|
+
if (axis != "horiz" && !sel.empty) return false;
|
|
749
|
+
const end = atEndOfCell(view, axis, dir);
|
|
750
|
+
if (end == null) return false;
|
|
751
|
+
if (axis == "horiz") {
|
|
752
|
+
return maybeSetSelection(
|
|
753
|
+
state,
|
|
754
|
+
dispatch,
|
|
755
|
+
Selection.near(state.doc.resolve(sel.head + dir), dir)
|
|
756
|
+
);
|
|
757
|
+
} else {
|
|
758
|
+
const $cell = state.doc.resolve(end);
|
|
759
|
+
const $next = nextCell($cell, axis, dir);
|
|
760
|
+
let newSel;
|
|
761
|
+
if ($next) newSel = Selection.near($next, 1);
|
|
762
|
+
else if (dir < 0)
|
|
763
|
+
newSel = Selection.near(state.doc.resolve($cell.before(-1)), -1);
|
|
764
|
+
else newSel = Selection.near(state.doc.resolve($cell.after(-1)), 1);
|
|
765
|
+
return maybeSetSelection(state, dispatch, newSel);
|
|
766
|
+
}
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
function shiftArrow(axis, dir) {
|
|
770
|
+
return (state, dispatch, view) => {
|
|
771
|
+
if (!view) return false;
|
|
772
|
+
const sel = state.selection;
|
|
773
|
+
let cellSel;
|
|
774
|
+
if (sel instanceof CellSelection) {
|
|
775
|
+
cellSel = sel;
|
|
776
|
+
} else {
|
|
777
|
+
const end = atEndOfCell(view, axis, dir);
|
|
778
|
+
if (end == null) return false;
|
|
779
|
+
cellSel = new CellSelection(state.doc.resolve(end));
|
|
780
|
+
}
|
|
781
|
+
const $head = nextCell(cellSel.$headCell, axis, dir);
|
|
782
|
+
if (!$head) return false;
|
|
783
|
+
return maybeSetSelection(
|
|
784
|
+
state,
|
|
785
|
+
dispatch,
|
|
786
|
+
new CellSelection(cellSel.$anchorCell, $head)
|
|
787
|
+
);
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
function atEndOfCell(view, axis, dir) {
|
|
791
|
+
if (!(view.state.selection instanceof TextSelection)) return null;
|
|
792
|
+
const { $head } = view.state.selection;
|
|
793
|
+
for (let d = $head.depth - 1; d >= 0; d--) {
|
|
794
|
+
const parent = $head.node(d), index = dir < 0 ? $head.index(d) : $head.indexAfter(d);
|
|
795
|
+
if (index != (dir < 0 ? 0 : parent.childCount)) return null;
|
|
796
|
+
if (parent.type.spec.tableRole == "cell" || parent.type.spec.tableRole == "header_cell") {
|
|
797
|
+
const cellPos = $head.before(d);
|
|
798
|
+
const dirStr = axis == "vert" ? dir > 0 ? "down" : "up" : dir > 0 ? "right" : "left";
|
|
799
|
+
return view.endOfTextblock(dirStr) ? cellPos : null;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
return null;
|
|
803
|
+
}
|
|
804
|
+
new PluginKey(
|
|
805
|
+
"tableColumnResizing"
|
|
806
|
+
);
|
|
807
|
+
function combineDOMRects(rect1, rect2) {
|
|
808
|
+
const top = Math.min(rect1.top, rect2.top);
|
|
809
|
+
const bottom = Math.max(rect1.bottom, rect2.bottom);
|
|
810
|
+
const left = Math.min(rect1.left, rect2.left);
|
|
811
|
+
const right = Math.max(rect1.right, rect2.right);
|
|
812
|
+
const width = right - left;
|
|
813
|
+
const height = bottom - top;
|
|
814
|
+
const x = left;
|
|
815
|
+
const y = top;
|
|
816
|
+
return new DOMRect(x, y, width, height);
|
|
817
|
+
}
|
|
818
|
+
var BubbleMenuView = class {
|
|
819
|
+
constructor({
|
|
820
|
+
editor,
|
|
821
|
+
element,
|
|
822
|
+
view,
|
|
823
|
+
updateDelay = 250,
|
|
824
|
+
resizeDelay = 60,
|
|
825
|
+
shouldShow,
|
|
826
|
+
options
|
|
827
|
+
}) {
|
|
828
|
+
this.preventHide = false;
|
|
829
|
+
this.isVisible = false;
|
|
830
|
+
this.floatingUIOptions = {
|
|
831
|
+
strategy: "absolute",
|
|
832
|
+
placement: "top",
|
|
833
|
+
offset: 8,
|
|
834
|
+
flip: {},
|
|
835
|
+
shift: {},
|
|
836
|
+
arrow: false,
|
|
837
|
+
size: false,
|
|
838
|
+
autoPlacement: false,
|
|
839
|
+
hide: false,
|
|
840
|
+
inline: false,
|
|
841
|
+
onShow: void 0,
|
|
842
|
+
onHide: void 0,
|
|
843
|
+
onUpdate: void 0,
|
|
844
|
+
onDestroy: void 0
|
|
845
|
+
};
|
|
846
|
+
this.shouldShow = ({ view: view2, state, from, to }) => {
|
|
847
|
+
const { doc, selection } = state;
|
|
848
|
+
const { empty } = selection;
|
|
849
|
+
const isEmptyTextBlock = !doc.textBetween(from, to).length && isTextSelection(state.selection);
|
|
850
|
+
const isChildOfMenu = this.element.contains(document.activeElement);
|
|
851
|
+
const hasEditorFocus = view2.hasFocus() || isChildOfMenu;
|
|
852
|
+
if (!hasEditorFocus || empty || isEmptyTextBlock || !this.editor.isEditable) {
|
|
853
|
+
return false;
|
|
854
|
+
}
|
|
855
|
+
return true;
|
|
856
|
+
};
|
|
857
|
+
this.mousedownHandler = () => {
|
|
858
|
+
this.preventHide = true;
|
|
859
|
+
};
|
|
860
|
+
this.dragstartHandler = () => {
|
|
861
|
+
this.hide();
|
|
862
|
+
};
|
|
863
|
+
this.resizeHandler = () => {
|
|
864
|
+
if (this.resizeDebounceTimer) {
|
|
865
|
+
clearTimeout(this.resizeDebounceTimer);
|
|
866
|
+
}
|
|
867
|
+
this.resizeDebounceTimer = window.setTimeout(() => {
|
|
868
|
+
this.updatePosition();
|
|
869
|
+
}, this.resizeDelay);
|
|
870
|
+
};
|
|
871
|
+
this.focusHandler = () => {
|
|
872
|
+
setTimeout(() => this.update(this.editor.view));
|
|
873
|
+
};
|
|
874
|
+
this.blurHandler = ({ event }) => {
|
|
875
|
+
var _a;
|
|
876
|
+
if (this.preventHide) {
|
|
877
|
+
this.preventHide = false;
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
if ((event == null ? void 0 : event.relatedTarget) && ((_a = this.element.parentNode) == null ? void 0 : _a.contains(event.relatedTarget))) {
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
if ((event == null ? void 0 : event.relatedTarget) === this.editor.view.dom) {
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
this.hide();
|
|
887
|
+
};
|
|
888
|
+
this.handleDebouncedUpdate = (view2, oldState) => {
|
|
889
|
+
const selectionChanged = !(oldState == null ? void 0 : oldState.selection.eq(view2.state.selection));
|
|
890
|
+
const docChanged = !(oldState == null ? void 0 : oldState.doc.eq(view2.state.doc));
|
|
891
|
+
if (!selectionChanged && !docChanged) {
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
if (this.updateDebounceTimer) {
|
|
895
|
+
clearTimeout(this.updateDebounceTimer);
|
|
896
|
+
}
|
|
897
|
+
this.updateDebounceTimer = window.setTimeout(() => {
|
|
898
|
+
this.updateHandler(view2, selectionChanged, docChanged, oldState);
|
|
899
|
+
}, this.updateDelay);
|
|
900
|
+
};
|
|
901
|
+
this.updateHandler = (view2, selectionChanged, docChanged, oldState) => {
|
|
902
|
+
const { composing } = view2;
|
|
903
|
+
const isSame = !selectionChanged && !docChanged;
|
|
904
|
+
if (composing || isSame) {
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
const shouldShow2 = this.getShouldShow(oldState);
|
|
908
|
+
if (!shouldShow2) {
|
|
909
|
+
this.hide();
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
912
|
+
this.updatePosition();
|
|
913
|
+
this.show();
|
|
914
|
+
};
|
|
915
|
+
this.editor = editor;
|
|
916
|
+
this.element = element;
|
|
917
|
+
this.view = view;
|
|
918
|
+
this.updateDelay = updateDelay;
|
|
919
|
+
this.resizeDelay = resizeDelay;
|
|
920
|
+
this.floatingUIOptions = {
|
|
921
|
+
...this.floatingUIOptions,
|
|
922
|
+
...options
|
|
923
|
+
};
|
|
924
|
+
this.element.tabIndex = 0;
|
|
925
|
+
if (shouldShow) {
|
|
926
|
+
this.shouldShow = shouldShow;
|
|
927
|
+
}
|
|
928
|
+
this.element.addEventListener("mousedown", this.mousedownHandler, { capture: true });
|
|
929
|
+
this.view.dom.addEventListener("dragstart", this.dragstartHandler);
|
|
930
|
+
this.editor.on("focus", this.focusHandler);
|
|
931
|
+
this.editor.on("blur", this.blurHandler);
|
|
932
|
+
window.addEventListener("resize", this.resizeHandler);
|
|
933
|
+
this.update(view, view.state);
|
|
934
|
+
if (this.getShouldShow()) {
|
|
935
|
+
this.show();
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
get middlewares() {
|
|
939
|
+
const middlewares = [];
|
|
940
|
+
if (this.floatingUIOptions.flip) {
|
|
941
|
+
middlewares.push(flip(typeof this.floatingUIOptions.flip !== "boolean" ? this.floatingUIOptions.flip : void 0));
|
|
942
|
+
}
|
|
943
|
+
if (this.floatingUIOptions.shift) {
|
|
944
|
+
middlewares.push(
|
|
945
|
+
shift(typeof this.floatingUIOptions.shift !== "boolean" ? this.floatingUIOptions.shift : void 0)
|
|
946
|
+
);
|
|
947
|
+
}
|
|
948
|
+
if (this.floatingUIOptions.offset) {
|
|
949
|
+
middlewares.push(
|
|
950
|
+
offset(typeof this.floatingUIOptions.offset !== "boolean" ? this.floatingUIOptions.offset : void 0)
|
|
951
|
+
);
|
|
952
|
+
}
|
|
953
|
+
if (this.floatingUIOptions.arrow) {
|
|
954
|
+
middlewares.push(arrow$1(this.floatingUIOptions.arrow));
|
|
955
|
+
}
|
|
956
|
+
if (this.floatingUIOptions.size) {
|
|
957
|
+
middlewares.push(size(typeof this.floatingUIOptions.size !== "boolean" ? this.floatingUIOptions.size : void 0));
|
|
958
|
+
}
|
|
959
|
+
if (this.floatingUIOptions.autoPlacement) {
|
|
960
|
+
middlewares.push(
|
|
961
|
+
autoPlacement(
|
|
962
|
+
typeof this.floatingUIOptions.autoPlacement !== "boolean" ? this.floatingUIOptions.autoPlacement : void 0
|
|
963
|
+
)
|
|
964
|
+
);
|
|
965
|
+
}
|
|
966
|
+
if (this.floatingUIOptions.hide) {
|
|
967
|
+
middlewares.push(hide(typeof this.floatingUIOptions.hide !== "boolean" ? this.floatingUIOptions.hide : void 0));
|
|
968
|
+
}
|
|
969
|
+
if (this.floatingUIOptions.inline) {
|
|
970
|
+
middlewares.push(
|
|
971
|
+
inline(typeof this.floatingUIOptions.inline !== "boolean" ? this.floatingUIOptions.inline : void 0)
|
|
972
|
+
);
|
|
973
|
+
}
|
|
974
|
+
return middlewares;
|
|
975
|
+
}
|
|
976
|
+
updatePosition() {
|
|
977
|
+
const { selection } = this.editor.state;
|
|
978
|
+
const domRect = posToDOMRect(this.view, selection.from, selection.to);
|
|
979
|
+
let virtualElement = {
|
|
980
|
+
getBoundingClientRect: () => domRect,
|
|
981
|
+
getClientRects: () => [domRect]
|
|
982
|
+
};
|
|
983
|
+
if (selection instanceof CellSelection) {
|
|
984
|
+
const { $anchorCell, $headCell } = selection;
|
|
985
|
+
const from = $anchorCell ? $anchorCell.pos : $headCell.pos;
|
|
986
|
+
const to = $headCell ? $headCell.pos : $anchorCell.pos;
|
|
987
|
+
const fromDOM = this.view.nodeDOM(from);
|
|
988
|
+
const toDOM = this.view.nodeDOM(to);
|
|
989
|
+
if (!fromDOM || !toDOM) {
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
992
|
+
const clientRect = fromDOM === toDOM ? fromDOM.getBoundingClientRect() : combineDOMRects(
|
|
993
|
+
fromDOM.getBoundingClientRect(),
|
|
994
|
+
toDOM.getBoundingClientRect()
|
|
995
|
+
);
|
|
996
|
+
virtualElement = {
|
|
997
|
+
getBoundingClientRect: () => clientRect,
|
|
998
|
+
getClientRects: () => [clientRect]
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
computePosition(virtualElement, this.element, {
|
|
1002
|
+
placement: this.floatingUIOptions.placement,
|
|
1003
|
+
strategy: this.floatingUIOptions.strategy,
|
|
1004
|
+
middleware: this.middlewares
|
|
1005
|
+
}).then(({ x, y, strategy }) => {
|
|
1006
|
+
this.element.style.width = "max-content";
|
|
1007
|
+
this.element.style.position = strategy;
|
|
1008
|
+
this.element.style.left = `${x}px`;
|
|
1009
|
+
this.element.style.top = `${y}px`;
|
|
1010
|
+
if (this.isVisible && this.floatingUIOptions.onUpdate) {
|
|
1011
|
+
this.floatingUIOptions.onUpdate();
|
|
1012
|
+
}
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
1015
|
+
update(view, oldState) {
|
|
1016
|
+
const { state } = view;
|
|
1017
|
+
const hasValidSelection = state.selection.from !== state.selection.to;
|
|
1018
|
+
if (this.updateDelay > 0 && hasValidSelection) {
|
|
1019
|
+
this.handleDebouncedUpdate(view, oldState);
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
const selectionChanged = !(oldState == null ? void 0 : oldState.selection.eq(view.state.selection));
|
|
1023
|
+
const docChanged = !(oldState == null ? void 0 : oldState.doc.eq(view.state.doc));
|
|
1024
|
+
this.updateHandler(view, selectionChanged, docChanged, oldState);
|
|
1025
|
+
}
|
|
1026
|
+
getShouldShow(oldState) {
|
|
1027
|
+
var _a;
|
|
1028
|
+
const { state } = this.view;
|
|
1029
|
+
const { selection } = state;
|
|
1030
|
+
const { ranges } = selection;
|
|
1031
|
+
const from = Math.min(...ranges.map((range) => range.$from.pos));
|
|
1032
|
+
const to = Math.max(...ranges.map((range) => range.$to.pos));
|
|
1033
|
+
const shouldShow = (_a = this.shouldShow) == null ? void 0 : _a.call(this, {
|
|
1034
|
+
editor: this.editor,
|
|
1035
|
+
element: this.element,
|
|
1036
|
+
view: this.view,
|
|
1037
|
+
state,
|
|
1038
|
+
oldState,
|
|
1039
|
+
from,
|
|
1040
|
+
to
|
|
1041
|
+
});
|
|
1042
|
+
return shouldShow;
|
|
1043
|
+
}
|
|
1044
|
+
show() {
|
|
1045
|
+
var _a;
|
|
1046
|
+
if (this.isVisible) {
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
this.element.style.visibility = "visible";
|
|
1050
|
+
this.element.style.opacity = "1";
|
|
1051
|
+
(_a = this.view.dom.parentElement) == null ? void 0 : _a.appendChild(this.element);
|
|
1052
|
+
if (this.floatingUIOptions.onShow) {
|
|
1053
|
+
this.floatingUIOptions.onShow();
|
|
1054
|
+
}
|
|
1055
|
+
this.isVisible = true;
|
|
1056
|
+
}
|
|
1057
|
+
hide() {
|
|
1058
|
+
if (!this.isVisible) {
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
this.element.style.visibility = "hidden";
|
|
1062
|
+
this.element.style.opacity = "0";
|
|
1063
|
+
this.element.remove();
|
|
1064
|
+
if (this.floatingUIOptions.onHide) {
|
|
1065
|
+
this.floatingUIOptions.onHide();
|
|
1066
|
+
}
|
|
1067
|
+
this.isVisible = false;
|
|
1068
|
+
}
|
|
1069
|
+
destroy() {
|
|
1070
|
+
this.hide();
|
|
1071
|
+
this.element.removeEventListener("mousedown", this.mousedownHandler, { capture: true });
|
|
1072
|
+
this.view.dom.removeEventListener("dragstart", this.dragstartHandler);
|
|
1073
|
+
window.removeEventListener("resize", this.resizeHandler);
|
|
1074
|
+
this.editor.off("focus", this.focusHandler);
|
|
1075
|
+
this.editor.off("blur", this.blurHandler);
|
|
1076
|
+
if (this.floatingUIOptions.onDestroy) {
|
|
1077
|
+
this.floatingUIOptions.onDestroy();
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
};
|
|
1081
|
+
var BubbleMenuPlugin = (options) => {
|
|
1082
|
+
return new Plugin({
|
|
1083
|
+
key: typeof options.pluginKey === "string" ? new PluginKey(options.pluginKey) : options.pluginKey,
|
|
1084
|
+
view: (view) => new BubbleMenuView({ view, ...options })
|
|
1085
|
+
});
|
|
1086
|
+
};
|
|
1087
|
+
Extension.create({
|
|
1088
|
+
name: "bubbleMenu",
|
|
1089
|
+
addOptions() {
|
|
1090
|
+
return {
|
|
1091
|
+
element: null,
|
|
1092
|
+
pluginKey: "bubbleMenu",
|
|
1093
|
+
updateDelay: void 0,
|
|
1094
|
+
shouldShow: null
|
|
1095
|
+
};
|
|
1096
|
+
},
|
|
1097
|
+
addProseMirrorPlugins() {
|
|
1098
|
+
if (!this.options.element) {
|
|
1099
|
+
return [];
|
|
1100
|
+
}
|
|
1101
|
+
return [
|
|
1102
|
+
BubbleMenuPlugin({
|
|
1103
|
+
pluginKey: this.options.pluginKey,
|
|
1104
|
+
editor: this.editor,
|
|
1105
|
+
element: this.options.element,
|
|
1106
|
+
updateDelay: this.options.updateDelay,
|
|
1107
|
+
options: this.options.options,
|
|
1108
|
+
shouldShow: this.options.shouldShow
|
|
1109
|
+
})
|
|
1110
|
+
];
|
|
1111
|
+
}
|
|
1112
|
+
});
|
|
1113
|
+
var BubbleMenu2 = defineComponent({
|
|
1114
|
+
name: "BubbleMenu",
|
|
1115
|
+
props: {
|
|
1116
|
+
pluginKey: {
|
|
1117
|
+
type: [String, Object],
|
|
1118
|
+
default: "bubbleMenu"
|
|
1119
|
+
},
|
|
1120
|
+
editor: {
|
|
1121
|
+
type: Object,
|
|
1122
|
+
required: true
|
|
1123
|
+
},
|
|
1124
|
+
updateDelay: {
|
|
1125
|
+
type: Number,
|
|
1126
|
+
default: void 0
|
|
1127
|
+
},
|
|
1128
|
+
resizeDelay: {
|
|
1129
|
+
type: Number,
|
|
1130
|
+
default: void 0
|
|
1131
|
+
},
|
|
1132
|
+
options: {
|
|
1133
|
+
type: Object,
|
|
1134
|
+
default: () => ({})
|
|
1135
|
+
},
|
|
1136
|
+
shouldShow: {
|
|
1137
|
+
type: Function,
|
|
1138
|
+
default: null
|
|
1139
|
+
}
|
|
1140
|
+
},
|
|
1141
|
+
setup(props, { slots }) {
|
|
1142
|
+
const root = ref(null);
|
|
1143
|
+
onMounted(() => {
|
|
1144
|
+
const { editor, options, pluginKey, resizeDelay, shouldShow, updateDelay } = props;
|
|
1145
|
+
if (!root.value) {
|
|
1146
|
+
return;
|
|
1147
|
+
}
|
|
1148
|
+
root.value.style.visibility = "hidden";
|
|
1149
|
+
root.value.style.position = "absolute";
|
|
1150
|
+
root.value.remove();
|
|
1151
|
+
editor.registerPlugin(
|
|
1152
|
+
BubbleMenuPlugin({
|
|
1153
|
+
editor,
|
|
1154
|
+
element: root.value,
|
|
1155
|
+
options,
|
|
1156
|
+
pluginKey,
|
|
1157
|
+
resizeDelay,
|
|
1158
|
+
shouldShow,
|
|
1159
|
+
updateDelay
|
|
1160
|
+
})
|
|
1161
|
+
);
|
|
1162
|
+
});
|
|
1163
|
+
onBeforeUnmount(() => {
|
|
1164
|
+
const { pluginKey, editor } = props;
|
|
1165
|
+
editor.unregisterPlugin(pluginKey);
|
|
1166
|
+
});
|
|
1167
|
+
return () => {
|
|
1168
|
+
var _a;
|
|
1169
|
+
return h(Teleport, { to: "body" }, h("div", { ref: root }, (_a = slots.default) == null ? void 0 : _a.call(slots)));
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
});
|
|
1173
|
+
var FloatingMenuView = class {
|
|
1174
|
+
constructor({ editor, element, view, options, shouldShow }) {
|
|
1175
|
+
this.preventHide = false;
|
|
1176
|
+
this.isVisible = false;
|
|
1177
|
+
this.shouldShow = ({ view: view2, state }) => {
|
|
1178
|
+
const { selection } = state;
|
|
1179
|
+
const { $anchor, empty } = selection;
|
|
1180
|
+
const isRootDepth = $anchor.depth === 1;
|
|
1181
|
+
const isEmptyTextBlock = $anchor.parent.isTextblock && !$anchor.parent.type.spec.code && !$anchor.parent.textContent && $anchor.parent.childCount === 0 && !this.getTextContent($anchor.parent);
|
|
1182
|
+
if (!view2.hasFocus() || !empty || !isRootDepth || !isEmptyTextBlock || !this.editor.isEditable) {
|
|
1183
|
+
return false;
|
|
1184
|
+
}
|
|
1185
|
+
return true;
|
|
1186
|
+
};
|
|
1187
|
+
this.floatingUIOptions = {
|
|
1188
|
+
strategy: "absolute",
|
|
1189
|
+
placement: "right",
|
|
1190
|
+
offset: 8,
|
|
1191
|
+
flip: {},
|
|
1192
|
+
shift: {},
|
|
1193
|
+
arrow: false,
|
|
1194
|
+
size: false,
|
|
1195
|
+
autoPlacement: false,
|
|
1196
|
+
hide: false,
|
|
1197
|
+
inline: false
|
|
1198
|
+
};
|
|
1199
|
+
this.updateHandler = (view2, selectionChanged, docChanged, oldState) => {
|
|
1200
|
+
const { composing } = view2;
|
|
1201
|
+
const isSame = !selectionChanged && !docChanged;
|
|
1202
|
+
if (composing || isSame) {
|
|
1203
|
+
return;
|
|
1204
|
+
}
|
|
1205
|
+
const shouldShow2 = this.getShouldShow(oldState);
|
|
1206
|
+
if (!shouldShow2) {
|
|
1207
|
+
this.hide();
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1210
|
+
this.updatePosition();
|
|
1211
|
+
this.show();
|
|
1212
|
+
};
|
|
1213
|
+
this.mousedownHandler = () => {
|
|
1214
|
+
this.preventHide = true;
|
|
1215
|
+
};
|
|
1216
|
+
this.focusHandler = () => {
|
|
1217
|
+
setTimeout(() => this.update(this.editor.view));
|
|
1218
|
+
};
|
|
1219
|
+
this.blurHandler = ({ event }) => {
|
|
1220
|
+
var _a;
|
|
1221
|
+
if (this.preventHide) {
|
|
1222
|
+
this.preventHide = false;
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
if ((event == null ? void 0 : event.relatedTarget) && ((_a = this.element.parentNode) == null ? void 0 : _a.contains(event.relatedTarget))) {
|
|
1226
|
+
return;
|
|
1227
|
+
}
|
|
1228
|
+
if ((event == null ? void 0 : event.relatedTarget) === this.editor.view.dom) {
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1231
|
+
this.hide();
|
|
1232
|
+
};
|
|
1233
|
+
this.editor = editor;
|
|
1234
|
+
this.element = element;
|
|
1235
|
+
this.view = view;
|
|
1236
|
+
this.floatingUIOptions = {
|
|
1237
|
+
...this.floatingUIOptions,
|
|
1238
|
+
...options
|
|
1239
|
+
};
|
|
1240
|
+
this.element.tabIndex = 0;
|
|
1241
|
+
if (shouldShow) {
|
|
1242
|
+
this.shouldShow = shouldShow;
|
|
1243
|
+
}
|
|
1244
|
+
this.element.addEventListener("mousedown", this.mousedownHandler, { capture: true });
|
|
1245
|
+
this.editor.on("focus", this.focusHandler);
|
|
1246
|
+
this.editor.on("blur", this.blurHandler);
|
|
1247
|
+
this.update(view, view.state);
|
|
1248
|
+
if (this.getShouldShow()) {
|
|
1249
|
+
this.show();
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
getTextContent(node) {
|
|
1253
|
+
return getText(node, { textSerializers: getTextSerializersFromSchema(this.editor.schema) });
|
|
1254
|
+
}
|
|
1255
|
+
get middlewares() {
|
|
1256
|
+
const middlewares = [];
|
|
1257
|
+
if (this.floatingUIOptions.flip) {
|
|
1258
|
+
middlewares.push(flip(typeof this.floatingUIOptions.flip !== "boolean" ? this.floatingUIOptions.flip : void 0));
|
|
1259
|
+
}
|
|
1260
|
+
if (this.floatingUIOptions.shift) {
|
|
1261
|
+
middlewares.push(
|
|
1262
|
+
shift(typeof this.floatingUIOptions.shift !== "boolean" ? this.floatingUIOptions.shift : void 0)
|
|
1263
|
+
);
|
|
1264
|
+
}
|
|
1265
|
+
if (this.floatingUIOptions.offset) {
|
|
1266
|
+
middlewares.push(
|
|
1267
|
+
offset(typeof this.floatingUIOptions.offset !== "boolean" ? this.floatingUIOptions.offset : void 0)
|
|
1268
|
+
);
|
|
1269
|
+
}
|
|
1270
|
+
if (this.floatingUIOptions.arrow) {
|
|
1271
|
+
middlewares.push(arrow$1(this.floatingUIOptions.arrow));
|
|
1272
|
+
}
|
|
1273
|
+
if (this.floatingUIOptions.size) {
|
|
1274
|
+
middlewares.push(size(typeof this.floatingUIOptions.size !== "boolean" ? this.floatingUIOptions.size : void 0));
|
|
1275
|
+
}
|
|
1276
|
+
if (this.floatingUIOptions.autoPlacement) {
|
|
1277
|
+
middlewares.push(
|
|
1278
|
+
autoPlacement(
|
|
1279
|
+
typeof this.floatingUIOptions.autoPlacement !== "boolean" ? this.floatingUIOptions.autoPlacement : void 0
|
|
1280
|
+
)
|
|
1281
|
+
);
|
|
1282
|
+
}
|
|
1283
|
+
if (this.floatingUIOptions.hide) {
|
|
1284
|
+
middlewares.push(hide(typeof this.floatingUIOptions.hide !== "boolean" ? this.floatingUIOptions.hide : void 0));
|
|
1285
|
+
}
|
|
1286
|
+
if (this.floatingUIOptions.inline) {
|
|
1287
|
+
middlewares.push(
|
|
1288
|
+
inline(typeof this.floatingUIOptions.inline !== "boolean" ? this.floatingUIOptions.inline : void 0)
|
|
1289
|
+
);
|
|
1290
|
+
}
|
|
1291
|
+
return middlewares;
|
|
1292
|
+
}
|
|
1293
|
+
getShouldShow(oldState) {
|
|
1294
|
+
var _a;
|
|
1295
|
+
const { state } = this.view;
|
|
1296
|
+
const { selection } = state;
|
|
1297
|
+
const { ranges } = selection;
|
|
1298
|
+
const from = Math.min(...ranges.map((range) => range.$from.pos));
|
|
1299
|
+
const to = Math.max(...ranges.map((range) => range.$to.pos));
|
|
1300
|
+
const shouldShow = (_a = this.shouldShow) == null ? void 0 : _a.call(this, {
|
|
1301
|
+
editor: this.editor,
|
|
1302
|
+
view: this.view,
|
|
1303
|
+
state,
|
|
1304
|
+
oldState,
|
|
1305
|
+
from,
|
|
1306
|
+
to
|
|
1307
|
+
});
|
|
1308
|
+
return shouldShow;
|
|
1309
|
+
}
|
|
1310
|
+
updatePosition() {
|
|
1311
|
+
const { selection } = this.editor.state;
|
|
1312
|
+
const domRect = posToDOMRect(this.view, selection.from, selection.to);
|
|
1313
|
+
const virtualElement = {
|
|
1314
|
+
getBoundingClientRect: () => domRect,
|
|
1315
|
+
getClientRects: () => [domRect]
|
|
1316
|
+
};
|
|
1317
|
+
computePosition(virtualElement, this.element, {
|
|
1318
|
+
placement: this.floatingUIOptions.placement,
|
|
1319
|
+
strategy: this.floatingUIOptions.strategy,
|
|
1320
|
+
middleware: this.middlewares
|
|
1321
|
+
}).then(({ x, y, strategy }) => {
|
|
1322
|
+
this.element.style.width = "max-content";
|
|
1323
|
+
this.element.style.position = strategy;
|
|
1324
|
+
this.element.style.left = `${x}px`;
|
|
1325
|
+
this.element.style.top = `${y}px`;
|
|
1326
|
+
if (this.isVisible && this.floatingUIOptions.onUpdate) {
|
|
1327
|
+
this.floatingUIOptions.onUpdate();
|
|
1328
|
+
}
|
|
1329
|
+
});
|
|
1330
|
+
}
|
|
1331
|
+
update(view, oldState) {
|
|
1332
|
+
const selectionChanged = !(oldState == null ? void 0 : oldState.selection.eq(view.state.selection));
|
|
1333
|
+
const docChanged = !(oldState == null ? void 0 : oldState.doc.eq(view.state.doc));
|
|
1334
|
+
this.updateHandler(view, selectionChanged, docChanged, oldState);
|
|
1335
|
+
}
|
|
1336
|
+
show() {
|
|
1337
|
+
var _a;
|
|
1338
|
+
if (this.isVisible) {
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1341
|
+
this.element.style.visibility = "visible";
|
|
1342
|
+
this.element.style.opacity = "1";
|
|
1343
|
+
(_a = this.view.dom.parentElement) == null ? void 0 : _a.appendChild(this.element);
|
|
1344
|
+
if (this.floatingUIOptions.onShow) {
|
|
1345
|
+
this.floatingUIOptions.onShow();
|
|
1346
|
+
}
|
|
1347
|
+
this.isVisible = true;
|
|
1348
|
+
}
|
|
1349
|
+
hide() {
|
|
1350
|
+
if (!this.isVisible) {
|
|
1351
|
+
return;
|
|
1352
|
+
}
|
|
1353
|
+
this.element.style.visibility = "hidden";
|
|
1354
|
+
this.element.style.opacity = "0";
|
|
1355
|
+
this.element.remove();
|
|
1356
|
+
if (this.floatingUIOptions.onHide) {
|
|
1357
|
+
this.floatingUIOptions.onHide();
|
|
1358
|
+
}
|
|
1359
|
+
this.isVisible = false;
|
|
1360
|
+
}
|
|
1361
|
+
destroy() {
|
|
1362
|
+
this.hide();
|
|
1363
|
+
this.element.removeEventListener("mousedown", this.mousedownHandler, { capture: true });
|
|
1364
|
+
this.editor.off("focus", this.focusHandler);
|
|
1365
|
+
this.editor.off("blur", this.blurHandler);
|
|
1366
|
+
if (this.floatingUIOptions.onDestroy) {
|
|
1367
|
+
this.floatingUIOptions.onDestroy();
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
};
|
|
1371
|
+
var FloatingMenuPlugin = (options) => {
|
|
1372
|
+
return new Plugin({
|
|
1373
|
+
key: typeof options.pluginKey === "string" ? new PluginKey(options.pluginKey) : options.pluginKey,
|
|
1374
|
+
view: (view) => new FloatingMenuView({ view, ...options })
|
|
1375
|
+
});
|
|
1376
|
+
};
|
|
1377
|
+
Extension.create({
|
|
1378
|
+
name: "floatingMenu",
|
|
1379
|
+
addOptions() {
|
|
1380
|
+
return {
|
|
1381
|
+
element: null,
|
|
1382
|
+
options: {},
|
|
1383
|
+
pluginKey: "floatingMenu",
|
|
1384
|
+
shouldShow: null
|
|
1385
|
+
};
|
|
1386
|
+
},
|
|
1387
|
+
addProseMirrorPlugins() {
|
|
1388
|
+
if (!this.options.element) {
|
|
1389
|
+
return [];
|
|
1390
|
+
}
|
|
1391
|
+
return [
|
|
1392
|
+
FloatingMenuPlugin({
|
|
1393
|
+
pluginKey: this.options.pluginKey,
|
|
1394
|
+
editor: this.editor,
|
|
1395
|
+
element: this.options.element,
|
|
1396
|
+
options: this.options.options,
|
|
1397
|
+
shouldShow: this.options.shouldShow
|
|
1398
|
+
})
|
|
1399
|
+
];
|
|
1400
|
+
}
|
|
1401
|
+
});
|
|
1402
|
+
var FloatingMenu2 = defineComponent({
|
|
1403
|
+
name: "FloatingMenu",
|
|
1404
|
+
props: {
|
|
1405
|
+
pluginKey: {
|
|
1406
|
+
// TODO: TypeScript breaks :(
|
|
1407
|
+
// type: [String, Object as PropType<Exclude<FloatingMenuPluginProps['pluginKey'], string>>],
|
|
1408
|
+
type: null,
|
|
1409
|
+
default: "floatingMenu"
|
|
1410
|
+
},
|
|
1411
|
+
editor: {
|
|
1412
|
+
type: Object,
|
|
1413
|
+
required: true
|
|
1414
|
+
},
|
|
1415
|
+
options: {
|
|
1416
|
+
type: Object,
|
|
1417
|
+
default: () => ({})
|
|
1418
|
+
},
|
|
1419
|
+
shouldShow: {
|
|
1420
|
+
type: Function,
|
|
1421
|
+
default: null
|
|
1422
|
+
}
|
|
1423
|
+
},
|
|
1424
|
+
setup(props, { slots }) {
|
|
1425
|
+
const root = ref(null);
|
|
1426
|
+
onMounted(() => {
|
|
1427
|
+
const { pluginKey, editor, options, shouldShow } = props;
|
|
1428
|
+
if (!root.value) {
|
|
1429
|
+
return;
|
|
1430
|
+
}
|
|
1431
|
+
root.value.style.visibility = "hidden";
|
|
1432
|
+
root.value.style.position = "absolute";
|
|
1433
|
+
root.value.remove();
|
|
1434
|
+
editor.registerPlugin(
|
|
1435
|
+
FloatingMenuPlugin({
|
|
1436
|
+
pluginKey,
|
|
1437
|
+
editor,
|
|
1438
|
+
element: root.value,
|
|
1439
|
+
options,
|
|
1440
|
+
shouldShow
|
|
1441
|
+
})
|
|
1442
|
+
);
|
|
1443
|
+
});
|
|
1444
|
+
onBeforeUnmount(() => {
|
|
1445
|
+
const { pluginKey, editor } = props;
|
|
1446
|
+
editor.unregisterPlugin(pluginKey);
|
|
1447
|
+
});
|
|
1448
|
+
return () => {
|
|
1449
|
+
var _a;
|
|
1450
|
+
return h(Teleport, { to: "body" }, h("div", { ref: root }, (_a = slots.default) == null ? void 0 : _a.call(slots)));
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
});
|
|
1454
|
+
export {
|
|
1455
|
+
BubbleMenu2 as BubbleMenu,
|
|
1456
|
+
FloatingMenu2 as FloatingMenu
|
|
1457
|
+
};
|