quoin-editor 0.4.2 → 1.0.1
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/CHANGELOG.md +251 -0
- package/MIGRATION.md +233 -0
- package/README.md +78 -716
- package/dist/ai.cjs +1148 -0
- package/dist/ai.cjs.map +1 -0
- package/dist/ai.d.cts +68 -0
- package/dist/ai.d.ts +68 -0
- package/dist/ai.js +1148 -0
- package/dist/ai.js.map +1 -0
- package/dist/catalogue.cjs +59 -0
- package/dist/catalogue.cjs.map +1 -0
- package/dist/catalogue.d.cts +39 -0
- package/dist/catalogue.d.ts +39 -0
- package/dist/catalogue.js +59 -0
- package/dist/catalogue.js.map +1 -0
- package/dist/chunk-26Q4LSIU.js +100 -0
- package/dist/chunk-26Q4LSIU.js.map +1 -0
- package/dist/chunk-56C7GCKO.cjs +1385 -0
- package/dist/chunk-56C7GCKO.cjs.map +1 -0
- package/dist/chunk-5M4QG3ZC.cjs +3303 -0
- package/dist/chunk-5M4QG3ZC.cjs.map +1 -0
- package/dist/chunk-5R3ISX4A.cjs +6643 -0
- package/dist/chunk-5R3ISX4A.cjs.map +1 -0
- package/dist/chunk-62WKUAQY.js +3335 -0
- package/dist/chunk-62WKUAQY.js.map +1 -0
- package/dist/chunk-6LMS5J3Y.js +320 -0
- package/dist/chunk-6LMS5J3Y.js.map +1 -0
- package/dist/chunk-6PKVJZQV.cjs +100 -0
- package/dist/chunk-6PKVJZQV.cjs.map +1 -0
- package/dist/chunk-6YSGUAVW.js +376 -0
- package/dist/chunk-6YSGUAVW.js.map +1 -0
- package/dist/chunk-75C6PX2L.cjs +239 -0
- package/dist/chunk-75C6PX2L.cjs.map +1 -0
- package/dist/chunk-A4IJSJKL.js +598 -0
- package/dist/chunk-A4IJSJKL.js.map +1 -0
- package/dist/chunk-BTBHHBVR.cjs +3335 -0
- package/dist/chunk-BTBHHBVR.cjs.map +1 -0
- package/dist/chunk-CLTHD5GO.cjs +34 -0
- package/dist/chunk-CLTHD5GO.cjs.map +1 -0
- package/dist/chunk-EH5KXQXY.cjs +62 -0
- package/dist/chunk-EH5KXQXY.cjs.map +1 -0
- package/dist/chunk-ESMAW4NK.cjs +184 -0
- package/dist/chunk-ESMAW4NK.cjs.map +1 -0
- package/dist/chunk-EYFCOV3T.cjs +30 -0
- package/dist/chunk-EYFCOV3T.cjs.map +1 -0
- package/dist/chunk-F5V3IEEE.cjs +326 -0
- package/dist/chunk-F5V3IEEE.cjs.map +1 -0
- package/dist/chunk-GPIDU3GN.js +239 -0
- package/dist/chunk-GPIDU3GN.js.map +1 -0
- package/dist/chunk-HOIDJEVI.cjs +4063 -0
- package/dist/chunk-HOIDJEVI.cjs.map +1 -0
- package/dist/chunk-JJ3RASQS.cjs +706 -0
- package/dist/chunk-JJ3RASQS.cjs.map +1 -0
- package/dist/chunk-LE3F7WIP.js +6643 -0
- package/dist/chunk-LE3F7WIP.js.map +1 -0
- package/dist/chunk-LE5XMIFJ.cjs +14 -0
- package/dist/chunk-LE5XMIFJ.cjs.map +1 -0
- package/dist/chunk-LMAEPFTX.js +30 -0
- package/dist/chunk-LMAEPFTX.js.map +1 -0
- package/dist/chunk-LV6EYPJO.js +34 -0
- package/dist/chunk-LV6EYPJO.js.map +1 -0
- package/dist/chunk-MLRAVUFG.cjs +376 -0
- package/dist/chunk-MLRAVUFG.cjs.map +1 -0
- package/dist/chunk-MQUCCSWG.js +14 -0
- package/dist/chunk-MQUCCSWG.js.map +1 -0
- package/dist/chunk-O4Z2WMFF.js +62 -0
- package/dist/chunk-O4Z2WMFF.js.map +1 -0
- package/dist/chunk-OCCKQHCY.js +25 -0
- package/dist/chunk-OCCKQHCY.js.map +1 -0
- package/dist/chunk-PGSS4IOS.js +706 -0
- package/dist/chunk-PGSS4IOS.js.map +1 -0
- package/dist/chunk-PIWRSX7U.js +562 -0
- package/dist/chunk-PIWRSX7U.js.map +1 -0
- package/dist/chunk-PX6LZMH4.cjs +598 -0
- package/dist/chunk-PX6LZMH4.cjs.map +1 -0
- package/dist/chunk-QXG3HWDS.js +184 -0
- package/dist/chunk-QXG3HWDS.js.map +1 -0
- package/dist/chunk-RQW3P3GH.js +504 -0
- package/dist/chunk-RQW3P3GH.js.map +1 -0
- package/dist/chunk-SSIRYUCK.js +3303 -0
- package/dist/chunk-SSIRYUCK.js.map +1 -0
- package/dist/chunk-UBNG5YCG.js +326 -0
- package/dist/chunk-UBNG5YCG.js.map +1 -0
- package/dist/chunk-UCXLRRWY.js +1385 -0
- package/dist/chunk-UCXLRRWY.js.map +1 -0
- package/dist/chunk-UDAVVEFC.cjs +562 -0
- package/dist/chunk-UDAVVEFC.cjs.map +1 -0
- package/dist/chunk-UPSLDTLT.js +4063 -0
- package/dist/chunk-UPSLDTLT.js.map +1 -0
- package/dist/chunk-UWNZG2SD.cjs +25 -0
- package/dist/chunk-UWNZG2SD.cjs.map +1 -0
- package/dist/chunk-V3KLMSRO.cjs +504 -0
- package/dist/chunk-V3KLMSRO.cjs.map +1 -0
- package/dist/chunk-VACTAZWS.cjs +249 -0
- package/dist/chunk-VACTAZWS.cjs.map +1 -0
- package/dist/chunk-WMN6566P.js +249 -0
- package/dist/chunk-WMN6566P.js.map +1 -0
- package/dist/chunk-XX5FTPJR.cjs +320 -0
- package/dist/chunk-XX5FTPJR.cjs.map +1 -0
- package/dist/comments.cjs +1008 -0
- package/dist/comments.cjs.map +1 -0
- package/dist/comments.d.cts +93 -0
- package/dist/comments.d.ts +93 -0
- package/dist/comments.js +1008 -0
- package/dist/comments.js.map +1 -0
- package/dist/diff.cjs +346 -0
- package/dist/diff.cjs.map +1 -0
- package/dist/diff.d.cts +67 -0
- package/dist/diff.d.ts +67 -0
- package/dist/diff.js +346 -0
- package/dist/diff.js.map +1 -0
- package/dist/docx.cjs +874 -0
- package/dist/docx.cjs.map +1 -0
- package/dist/docx.d.cts +33 -0
- package/dist/docx.d.ts +33 -0
- package/dist/docx.js +874 -0
- package/dist/docx.js.map +1 -0
- package/dist/embed-provider-jXwlRmnp.d.cts +19 -0
- package/dist/embed-provider-jXwlRmnp.d.ts +19 -0
- package/dist/embed.cjs +17 -0
- package/dist/embed.cjs.map +1 -0
- package/dist/embed.d.cts +56 -0
- package/dist/embed.d.ts +56 -0
- package/dist/embed.js +17 -0
- package/dist/embed.js.map +1 -0
- package/dist/emoji-data.cjs +1968 -0
- package/dist/emoji-data.cjs.map +1 -0
- package/dist/emoji-data.js +1968 -0
- package/dist/emoji-data.js.map +1 -0
- package/dist/emoji-extension-CmPlRssm.d.ts +46 -0
- package/dist/emoji-extension-zJ6F7hW8.d.cts +46 -0
- package/dist/emoji.cjs +18 -0
- package/dist/emoji.cjs.map +1 -0
- package/dist/emoji.d.cts +31 -0
- package/dist/emoji.d.ts +31 -0
- package/dist/emoji.js +18 -0
- package/dist/emoji.js.map +1 -0
- package/dist/engine.cjs +119 -0
- package/dist/engine.cjs.map +1 -0
- package/dist/engine.d.cts +144 -0
- package/dist/engine.d.ts +144 -0
- package/dist/engine.js +119 -0
- package/dist/engine.js.map +1 -0
- package/dist/find-extension-BcRyE9K4.d.cts +41 -0
- package/dist/find-extension-CmFehyul.d.ts +41 -0
- package/dist/find.cjs +20 -0
- package/dist/find.cjs.map +1 -0
- package/dist/find.d.cts +44 -0
- package/dist/find.d.ts +44 -0
- package/dist/find.js +20 -0
- package/dist/find.js.map +1 -0
- package/dist/headless.cjs +151 -518
- package/dist/headless.cjs.map +1 -1
- package/dist/headless.d.cts +102 -69
- package/dist/headless.d.ts +102 -69
- package/dist/headless.js +149 -467
- package/dist/headless.js.map +1 -1
- package/dist/index-CFPmCee4.d.cts +68 -0
- package/dist/index-DiCGV60d.d.ts +68 -0
- package/dist/index.cjs +183 -2753
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +345 -253
- package/dist/index.d.ts +345 -253
- package/dist/index.js +168 -2696
- package/dist/index.js.map +1 -1
- package/dist/math.cjs +18 -0
- package/dist/math.cjs.map +1 -0
- package/dist/math.d.cts +49 -0
- package/dist/math.d.ts +49 -0
- package/dist/math.js +18 -0
- package/dist/math.js.map +1 -0
- package/dist/mention.cjs +18 -0
- package/dist/mention.cjs.map +1 -0
- package/dist/mention.d.cts +50 -0
- package/dist/mention.d.ts +50 -0
- package/dist/mention.js +18 -0
- package/dist/mention.js.map +1 -0
- package/dist/presence.cjs +562 -0
- package/dist/presence.cjs.map +1 -0
- package/dist/presence.d.cts +30 -0
- package/dist/presence.d.ts +30 -0
- package/dist/presence.js +562 -0
- package/dist/presence.js.map +1 -0
- package/dist/registry-CWBOSAHm.d.cts +121 -0
- package/dist/registry-CWBOSAHm.d.ts +121 -0
- package/dist/stats-extension-DisOEbbI.d.ts +40 -0
- package/dist/stats-extension-Dt1lgP3m.d.cts +40 -0
- package/dist/stats.cjs +19 -0
- package/dist/stats.cjs.map +1 -0
- package/dist/stats.d.cts +19 -0
- package/dist/stats.d.ts +19 -0
- package/dist/stats.js +19 -0
- package/dist/stats.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/table-extension-BTMJnT7J.d.ts +57 -0
- package/dist/table-extension-DxZz3jqp.d.cts +57 -0
- package/dist/table.cjs +50 -0
- package/dist/table.cjs.map +1 -0
- package/dist/table.d.cts +57 -0
- package/dist/table.d.ts +57 -0
- package/dist/table.js +50 -0
- package/dist/table.js.map +1 -0
- package/dist/to-html-C5t7xyaM.d.ts +21 -0
- package/dist/to-html-CNCITCln.d.cts +21 -0
- package/dist/toc-extension-CR9U-l6j.d.ts +25 -0
- package/dist/toc-extension-DGHywOBv.d.cts +25 -0
- package/dist/toc.cjs +18 -0
- package/dist/toc.cjs.map +1 -0
- package/dist/toc.d.cts +24 -0
- package/dist/toc.d.ts +24 -0
- package/dist/toc.js +18 -0
- package/dist/toc.js.map +1 -0
- package/dist/types-C6_QkXzy.d.ts +358 -0
- package/dist/types-CJ7Gq3GX.d.cts +358 -0
- package/dist/types-DULc8wwg.d.cts +120 -0
- package/dist/types-DULc8wwg.d.ts +120 -0
- package/dist/view-controller-BD1KwYfE.d.cts +105 -0
- package/dist/view-controller-y4cb60ue.d.ts +105 -0
- package/dist/view.cjs +23 -0
- package/dist/view.cjs.map +1 -0
- package/dist/view.d.cts +40 -0
- package/dist/view.d.ts +40 -0
- package/dist/view.js +23 -0
- package/dist/view.js.map +1 -0
- package/dist/yjs.cjs +864 -0
- package/dist/yjs.cjs.map +1 -0
- package/dist/yjs.d.cts +22 -0
- package/dist/yjs.d.ts +22 -0
- package/dist/yjs.js +864 -0
- package/dist/yjs.js.map +1 -0
- package/package.json +217 -18
|
@@ -0,0 +1,1385 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DropdownMenu,
|
|
3
|
+
DropdownMenuCheckboxItem,
|
|
4
|
+
DropdownMenuContent,
|
|
5
|
+
DropdownMenuItem,
|
|
6
|
+
DropdownMenuRadioGroup,
|
|
7
|
+
DropdownMenuRadioItem,
|
|
8
|
+
DropdownMenuSeparator,
|
|
9
|
+
DropdownMenuTrigger,
|
|
10
|
+
FOCUS_RING,
|
|
11
|
+
MenuIcon,
|
|
12
|
+
bubblePart,
|
|
13
|
+
interceptKeys,
|
|
14
|
+
keepFocus,
|
|
15
|
+
returnFocusToText
|
|
16
|
+
} from "./chunk-LE3F7WIP.js";
|
|
17
|
+
import {
|
|
18
|
+
EditableRegion,
|
|
19
|
+
NATIVE_INTERACTION,
|
|
20
|
+
caretClientRect,
|
|
21
|
+
caretFromPoint,
|
|
22
|
+
domToPos,
|
|
23
|
+
handleCopy,
|
|
24
|
+
isComposingKey,
|
|
25
|
+
isOnFirstLine,
|
|
26
|
+
isOnLastLine,
|
|
27
|
+
lineEdgeRect,
|
|
28
|
+
neighbourBlock,
|
|
29
|
+
posToDom,
|
|
30
|
+
useEditorState,
|
|
31
|
+
useIsomorphicLayoutEffect,
|
|
32
|
+
useReadOnly
|
|
33
|
+
} from "./chunk-SSIRYUCK.js";
|
|
34
|
+
import {
|
|
35
|
+
Transaction,
|
|
36
|
+
createPluginKey,
|
|
37
|
+
defineExtension,
|
|
38
|
+
descendantsEnd,
|
|
39
|
+
headBlockId,
|
|
40
|
+
insertBlocksStep,
|
|
41
|
+
insertHardBreak,
|
|
42
|
+
insertTextAt,
|
|
43
|
+
isCollapsed,
|
|
44
|
+
isParagraph,
|
|
45
|
+
markCoverage,
|
|
46
|
+
primaryRegion,
|
|
47
|
+
regionLength,
|
|
48
|
+
replaceBlockStep,
|
|
49
|
+
replaceInlineStep,
|
|
50
|
+
setMark,
|
|
51
|
+
textSelection,
|
|
52
|
+
toggleMark
|
|
53
|
+
} from "./chunk-UPSLDTLT.js";
|
|
54
|
+
import {
|
|
55
|
+
blockById,
|
|
56
|
+
cellKey,
|
|
57
|
+
countOf,
|
|
58
|
+
equalInline,
|
|
59
|
+
inlineLength,
|
|
60
|
+
newId,
|
|
61
|
+
requireBlockIndex,
|
|
62
|
+
sameItems
|
|
63
|
+
} from "./chunk-62WKUAQY.js";
|
|
64
|
+
|
|
65
|
+
// src/engine/commands/table-shape.ts
|
|
66
|
+
var CELL = /^cell:(\d+):(\d+)$/;
|
|
67
|
+
var tableShape = (block) => ({
|
|
68
|
+
rows: countOf(block.attrs.rows),
|
|
69
|
+
cols: countOf(block.attrs.cols)
|
|
70
|
+
});
|
|
71
|
+
var ALIGNS = ["left", "center", "right"];
|
|
72
|
+
var columnAligns = (block, cols) => Array.from({ length: cols }, (_, col) => {
|
|
73
|
+
const align = Array.isArray(block.attrs.align) ? block.attrs.align[col] : null;
|
|
74
|
+
return ALIGNS.includes(align) ? align : null;
|
|
75
|
+
});
|
|
76
|
+
var validWidths = (value, cols) => Array.isArray(value) && value.length === cols && value.every((width) => typeof width === "number" && width > 0) ? value : null;
|
|
77
|
+
var storedWidths = (block, cols) => validWidths(block.attrs.widths, cols);
|
|
78
|
+
function cellOf(region) {
|
|
79
|
+
const match = CELL.exec(region);
|
|
80
|
+
return match === null ? null : [Number(match[1]), Number(match[2])];
|
|
81
|
+
}
|
|
82
|
+
function tableBlock(doc, id) {
|
|
83
|
+
const block = blockById(doc, id);
|
|
84
|
+
return block?.type === "TABLE" ? block : null;
|
|
85
|
+
}
|
|
86
|
+
var isIndex = (index, length) => Number.isInteger(index) && index >= 0 && index < length;
|
|
87
|
+
function movedOrder(length, from, to) {
|
|
88
|
+
const order = Array.from({ length }, (_, i) => i).filter((i) => i !== from);
|
|
89
|
+
order.splice(to, 0, from);
|
|
90
|
+
return order;
|
|
91
|
+
}
|
|
92
|
+
function rebuiltTable(block, plan) {
|
|
93
|
+
const regions = {};
|
|
94
|
+
for (let row = 0; row < plan.rows; row++) {
|
|
95
|
+
for (let col = 0; col < plan.cols; col++) {
|
|
96
|
+
const from = plan.source(row, col);
|
|
97
|
+
regions[cellKey(row, col)] = from === null ? [] : block.regions[cellKey(...from)] ?? [];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return { ...block, attrs: { ...block.attrs, ...plan.attrs, rows: plan.rows, cols: plan.cols }, regions };
|
|
101
|
+
}
|
|
102
|
+
function followedPos(pos, blockId, plan) {
|
|
103
|
+
const cell = pos.block === blockId ? cellOf(pos.region) : null;
|
|
104
|
+
if (cell === null) return pos;
|
|
105
|
+
const moved = plan.target(cell);
|
|
106
|
+
return moved === null ? { block: blockId, region: cellKey(...plan.landing(cell)), offset: 0 } : { ...pos, region: cellKey(...moved) };
|
|
107
|
+
}
|
|
108
|
+
function followedSelection(selection, blockId, plan) {
|
|
109
|
+
if (selection?.kind !== "text") return selection;
|
|
110
|
+
const anchor = followedPos(selection.anchor, blockId, plan);
|
|
111
|
+
const head = followedPos(selection.head, blockId, plan);
|
|
112
|
+
return anchor === selection.anchor && head === selection.head ? selection : textSelection(anchor, head);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// src/engine/state/cell-selection.ts
|
|
116
|
+
var cellSelectionKey = createPluginKey("cellSelection");
|
|
117
|
+
function rangeOfSelection({ doc, selection }) {
|
|
118
|
+
if (selection?.kind !== "text") return null;
|
|
119
|
+
const { anchor, head } = selection;
|
|
120
|
+
if (anchor.block !== head.block || anchor.region === head.region || tableBlock(doc, anchor.block) === null) return null;
|
|
121
|
+
const from = cellOf(anchor.region);
|
|
122
|
+
const to = cellOf(head.region);
|
|
123
|
+
return from && to ? { block: anchor.block, anchor: from, head: to } : null;
|
|
124
|
+
}
|
|
125
|
+
var sameCell = (a, b) => a[0] === b[0] && a[1] === b[1];
|
|
126
|
+
var sameRange = (a, b) => a === b || a !== null && b !== null && a.block === b.block && sameCell(a.anchor, b.anchor) && sameCell(a.head, b.head);
|
|
127
|
+
var cellSelectionPlugin = {
|
|
128
|
+
key: cellSelectionKey,
|
|
129
|
+
init: rangeOfSelection,
|
|
130
|
+
apply(_tr, value, _old, next) {
|
|
131
|
+
const range = rangeOfSelection(next);
|
|
132
|
+
return sameRange(range, value) ? value : range;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
function cellSelection(state) {
|
|
136
|
+
const held = state.pluginState.get(cellSelectionKey.name);
|
|
137
|
+
return held === void 0 ? rangeOfSelection(state) : held;
|
|
138
|
+
}
|
|
139
|
+
var between = (value, a, b) => value >= Math.min(a, b) && value <= Math.max(a, b);
|
|
140
|
+
var rangeHasCell = ({ anchor, head }, [row, col]) => between(row, anchor[0], head[0]) && between(col, anchor[1], head[1]);
|
|
141
|
+
function cellsInRange({ anchor, head }) {
|
|
142
|
+
const cells = [];
|
|
143
|
+
for (let row = Math.min(anchor[0], head[0]); row <= Math.max(anchor[0], head[0]); row++) {
|
|
144
|
+
for (let col = Math.min(anchor[1], head[1]); col <= Math.max(anchor[1], head[1]); col++) cells.push([row, col]);
|
|
145
|
+
}
|
|
146
|
+
return cells;
|
|
147
|
+
}
|
|
148
|
+
function selectCells(blockId, anchor, head) {
|
|
149
|
+
return (state, dispatch) => {
|
|
150
|
+
const block = tableBlock(state.doc, blockId);
|
|
151
|
+
const { rows, cols } = block === null ? { rows: 0, cols: 0 } : tableShape(block);
|
|
152
|
+
const inside = ([row, col]) => isIndex(row, rows) && isIndex(col, cols);
|
|
153
|
+
if (block === null || !inside(anchor) || !inside(head)) return false;
|
|
154
|
+
const end2 = cellKey(...head);
|
|
155
|
+
const selection = textSelection(
|
|
156
|
+
{ block: blockId, region: cellKey(...anchor), offset: 0 },
|
|
157
|
+
{ block: blockId, region: end2, offset: inlineLength(block.regions[end2] ?? []) }
|
|
158
|
+
);
|
|
159
|
+
dispatch?.(new Transaction(state).setSelection(selection));
|
|
160
|
+
return true;
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// src/engine/commands/cell-commands.ts
|
|
165
|
+
function filledCells(doc, range) {
|
|
166
|
+
const regions = blockById(doc, range.block)?.regions ?? {};
|
|
167
|
+
return cellsInRange(range).flatMap((cell) => {
|
|
168
|
+
const region = cellKey(...cell);
|
|
169
|
+
const length = inlineLength(regions[region] ?? []);
|
|
170
|
+
return length > 0 ? [{ region, length }] : [];
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
function firstCell({ block, anchor, head }) {
|
|
174
|
+
return { block, region: cellKey(Math.min(anchor[0], head[0]), Math.min(anchor[1], head[1])), offset: 0 };
|
|
175
|
+
}
|
|
176
|
+
function emptied(state, range) {
|
|
177
|
+
const tr = new Transaction(state);
|
|
178
|
+
for (const { region, length } of filledCells(state.doc, range)) {
|
|
179
|
+
tr.step(replaceInlineStep(range.block, region, 0, length, []));
|
|
180
|
+
}
|
|
181
|
+
return tr;
|
|
182
|
+
}
|
|
183
|
+
var deleteCellContents = (state, dispatch) => {
|
|
184
|
+
const range = cellSelection(state);
|
|
185
|
+
if (range === null) return false;
|
|
186
|
+
dispatch?.(emptied(state, range).setSelection(textSelection(firstCell(range))));
|
|
187
|
+
return true;
|
|
188
|
+
};
|
|
189
|
+
function typeOverCells(text) {
|
|
190
|
+
return (state, dispatch) => {
|
|
191
|
+
const range = cellSelection(state);
|
|
192
|
+
if (range === null || text === "") return false;
|
|
193
|
+
const tr = emptied(state, range);
|
|
194
|
+
dispatch?.(tr.setSelection(textSelection(insertTextAt(tr, state.schema, firstCell(range), text))));
|
|
195
|
+
return true;
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function setCellsMark(type, attrs) {
|
|
199
|
+
return (state, dispatch) => {
|
|
200
|
+
const range = cellSelection(state);
|
|
201
|
+
const cells = range === null ? [] : filledCells(state.doc, range);
|
|
202
|
+
const regions = range === null ? void 0 : blockById(state.doc, range.block)?.regions;
|
|
203
|
+
if (range === null || regions === void 0 || cells.length === 0) return false;
|
|
204
|
+
const carried = cells.every(({ region }) => markCoverage(regions[region], type, attrs).every);
|
|
205
|
+
const mark = carried ? toggleMark(type, attrs) : setMark(type, attrs);
|
|
206
|
+
const tr = new Transaction(state);
|
|
207
|
+
for (const { region, length } of cells) {
|
|
208
|
+
const start = { block: range.block, region, offset: 0 };
|
|
209
|
+
const whole = textSelection(start, { ...start, offset: length });
|
|
210
|
+
mark({ ...state, doc: tr.doc, selection: whole, storedMarks: null }, (cell) => {
|
|
211
|
+
for (const step of cell.steps) tr.step(step);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
if (!tr.docChanged) return false;
|
|
215
|
+
dispatch?.(tr);
|
|
216
|
+
return true;
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// src/extensions/table/TableBlock.tsx
|
|
221
|
+
import { useRef } from "react";
|
|
222
|
+
|
|
223
|
+
// src/extensions/table/controls-slot.ts
|
|
224
|
+
var CONTROLS_SLOT = "data-quoin-table-controls";
|
|
225
|
+
var controlsSlot = (controller, blockId) => controller.blockElement(blockId)?.querySelector(`[${CONTROLS_SLOT}]`) ?? null;
|
|
226
|
+
|
|
227
|
+
// src/extensions/table/TableCell.tsx
|
|
228
|
+
import { memo, useCallback } from "react";
|
|
229
|
+
import { jsx } from "react/jsx-runtime";
|
|
230
|
+
var TableCell = memo(function TableCell2({ controller, blockId, row, col, header, align, label }) {
|
|
231
|
+
const inRange = useEditorState(
|
|
232
|
+
controller,
|
|
233
|
+
useCallback(
|
|
234
|
+
(state) => {
|
|
235
|
+
const range = cellSelection(state);
|
|
236
|
+
return range?.block === blockId && rangeHasCell(range, [row, col]);
|
|
237
|
+
},
|
|
238
|
+
[blockId, row, col]
|
|
239
|
+
)
|
|
240
|
+
);
|
|
241
|
+
const Cell = header ? "th" : "td";
|
|
242
|
+
return /* @__PURE__ */ jsx(
|
|
243
|
+
Cell,
|
|
244
|
+
{
|
|
245
|
+
scope: header ? "col" : void 0,
|
|
246
|
+
"data-row": row,
|
|
247
|
+
"data-col": col,
|
|
248
|
+
"data-in-range": inRange ? "" : void 0,
|
|
249
|
+
style: align === null ? void 0 : { textAlign: align },
|
|
250
|
+
children: /* @__PURE__ */ jsx(EditableRegion, { block: blockId, region: cellKey(row, col), label, className: "quoin-table-text" })
|
|
251
|
+
}
|
|
252
|
+
);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// src/extensions/table/table-ui-store.ts
|
|
256
|
+
import { useCallback as useCallback2, useSyncExternalStore } from "react";
|
|
257
|
+
function createTableUiStore() {
|
|
258
|
+
let state = { preview: null };
|
|
259
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
260
|
+
return {
|
|
261
|
+
get: () => state,
|
|
262
|
+
set(patch) {
|
|
263
|
+
state = { ...state, ...patch };
|
|
264
|
+
for (const listener of [...listeners]) listener();
|
|
265
|
+
},
|
|
266
|
+
subscribe(listener) {
|
|
267
|
+
listeners.add(listener);
|
|
268
|
+
return () => void listeners.delete(listener);
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
var stores = /* @__PURE__ */ new WeakMap();
|
|
273
|
+
function tableUiStore(controller) {
|
|
274
|
+
let store = stores.get(controller);
|
|
275
|
+
if (store === void 0) {
|
|
276
|
+
store = createTableUiStore();
|
|
277
|
+
stores.set(controller, store);
|
|
278
|
+
}
|
|
279
|
+
return store;
|
|
280
|
+
}
|
|
281
|
+
function useWidthPreview(controller, blockId) {
|
|
282
|
+
const store = tableUiStore(controller);
|
|
283
|
+
const read = useCallback2(() => {
|
|
284
|
+
const { preview } = store.get();
|
|
285
|
+
return preview?.block === blockId ? preview.widths : null;
|
|
286
|
+
}, [store, blockId]);
|
|
287
|
+
return useSyncExternalStore(store.subscribe, read, read);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// src/extensions/table/use-cell-press.ts
|
|
291
|
+
import { useEffect } from "react";
|
|
292
|
+
|
|
293
|
+
// src/engine/commands/table-commands.ts
|
|
294
|
+
function changeTable(blockId, change, plan) {
|
|
295
|
+
return (state, dispatch) => {
|
|
296
|
+
const block = tableBlock(state.doc, blockId);
|
|
297
|
+
const next = block && change(block);
|
|
298
|
+
if (!next) return false;
|
|
299
|
+
const tr = new Transaction(state).step(replaceBlockStep(next));
|
|
300
|
+
dispatch?.(plan ? tr.setSelection(followedSelection(state.selection, blockId, plan)) : tr);
|
|
301
|
+
return true;
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
function reshape(blockId, plan) {
|
|
305
|
+
return (state, dispatch) => {
|
|
306
|
+
const block = tableBlock(state.doc, blockId);
|
|
307
|
+
const made = block && plan(block, tableShape(block));
|
|
308
|
+
return made ? changeTable(blockId, (table) => rebuiltTable(table, made), made)(state, dispatch) : false;
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
function spliced(list, index, remove, ...insert) {
|
|
312
|
+
const copy = [...list];
|
|
313
|
+
copy.splice(index, remove, ...insert);
|
|
314
|
+
return copy;
|
|
315
|
+
}
|
|
316
|
+
var reordered = (list, order) => order.map((i) => list[i]);
|
|
317
|
+
var columnAttrs = (align, widths) => widths === null ? { align } : { align, widths };
|
|
318
|
+
var addRow = (blockId, index) => reshape(
|
|
319
|
+
blockId,
|
|
320
|
+
(_, { rows, cols }) => isIndex(index, rows + 1) ? {
|
|
321
|
+
rows: rows + 1,
|
|
322
|
+
cols,
|
|
323
|
+
source: (row, col) => row === index ? null : [row < index ? row : row - 1, col],
|
|
324
|
+
target: ([row, col]) => [row < index ? row : row + 1, col],
|
|
325
|
+
landing: (cell) => cell
|
|
326
|
+
} : null
|
|
327
|
+
);
|
|
328
|
+
var removeRow = (blockId, index) => reshape(
|
|
329
|
+
blockId,
|
|
330
|
+
(_, { rows, cols }) => isIndex(index, rows) && rows > 1 ? {
|
|
331
|
+
rows: rows - 1,
|
|
332
|
+
cols,
|
|
333
|
+
source: (row, col) => [row < index ? row : row + 1, col],
|
|
334
|
+
target: ([row, col]) => row === index ? null : [row < index ? row : row - 1, col],
|
|
335
|
+
landing: ([, col]) => [Math.min(index, rows - 2), col]
|
|
336
|
+
} : null
|
|
337
|
+
);
|
|
338
|
+
var moveRow = (blockId, from, to) => reshape(blockId, (_, { rows, cols }) => {
|
|
339
|
+
if (!isIndex(from, rows) || !isIndex(to, rows) || from === to) return null;
|
|
340
|
+
const order = movedOrder(rows, from, to);
|
|
341
|
+
return {
|
|
342
|
+
rows,
|
|
343
|
+
cols,
|
|
344
|
+
source: (row, col) => [order[row], col],
|
|
345
|
+
target: ([row, col]) => [order.indexOf(row), col],
|
|
346
|
+
landing: (cell) => cell
|
|
347
|
+
};
|
|
348
|
+
});
|
|
349
|
+
var addColumn = (blockId, index) => reshape(blockId, (block, { rows, cols }) => {
|
|
350
|
+
if (!isIndex(index, cols + 1)) return null;
|
|
351
|
+
const widths = storedWidths(block, cols);
|
|
352
|
+
return {
|
|
353
|
+
rows,
|
|
354
|
+
cols: cols + 1,
|
|
355
|
+
source: (row, col) => col === index ? null : [row, col < index ? col : col - 1],
|
|
356
|
+
target: ([row, col]) => [row, col < index ? col : col + 1],
|
|
357
|
+
landing: (cell) => cell,
|
|
358
|
+
attrs: columnAttrs(
|
|
359
|
+
spliced(columnAligns(block, cols), index, 0, null),
|
|
360
|
+
widths && spliced(widths, index, 0, widths[Math.max(index - 1, 0)])
|
|
361
|
+
)
|
|
362
|
+
};
|
|
363
|
+
});
|
|
364
|
+
var removeColumn = (blockId, index) => reshape(blockId, (block, { rows, cols }) => {
|
|
365
|
+
if (!isIndex(index, cols) || cols < 2) return null;
|
|
366
|
+
const widths = storedWidths(block, cols);
|
|
367
|
+
return {
|
|
368
|
+
rows,
|
|
369
|
+
cols: cols - 1,
|
|
370
|
+
source: (row, col) => [row, col < index ? col : col + 1],
|
|
371
|
+
target: ([row, col]) => col === index ? null : [row, col < index ? col : col - 1],
|
|
372
|
+
landing: ([row]) => [row, Math.min(index, cols - 2)],
|
|
373
|
+
attrs: columnAttrs(spliced(columnAligns(block, cols), index, 1), widths && spliced(widths, index, 1))
|
|
374
|
+
};
|
|
375
|
+
});
|
|
376
|
+
var moveColumn = (blockId, from, to) => reshape(blockId, (block, { rows, cols }) => {
|
|
377
|
+
if (!isIndex(from, cols) || !isIndex(to, cols) || from === to) return null;
|
|
378
|
+
const order = movedOrder(cols, from, to);
|
|
379
|
+
const widths = storedWidths(block, cols);
|
|
380
|
+
return {
|
|
381
|
+
rows,
|
|
382
|
+
cols,
|
|
383
|
+
source: (row, col) => [row, order[col]],
|
|
384
|
+
target: ([row, col]) => [row, order.indexOf(col)],
|
|
385
|
+
landing: (cell) => cell,
|
|
386
|
+
attrs: columnAttrs(reordered(columnAligns(block, cols), order), widths && reordered(widths, order))
|
|
387
|
+
};
|
|
388
|
+
});
|
|
389
|
+
var toggleHeaderRow = (blockId) => changeTable(blockId, (block) => ({ ...block, attrs: { ...block.attrs, header: block.attrs.header === false } }));
|
|
390
|
+
var withAttrs = (block, attrs) => ({ ...block, attrs: { ...block.attrs, ...attrs } });
|
|
391
|
+
var setColumnAlign = (blockId, col, align) => changeTable(blockId, (block) => {
|
|
392
|
+
const aligns = columnAligns(block, tableShape(block).cols);
|
|
393
|
+
if (!isIndex(col, aligns.length) || aligns[col] === align) return null;
|
|
394
|
+
return withAttrs(block, { align: spliced(aligns, col, 1, align) });
|
|
395
|
+
});
|
|
396
|
+
var DEFAULT_COLUMN_WIDTH = 120;
|
|
397
|
+
var setColumnWidth = (blockId, col, px, drawn) => changeTable(blockId, (block) => {
|
|
398
|
+
const { cols } = tableShape(block);
|
|
399
|
+
const width = Math.round(px);
|
|
400
|
+
if (!isIndex(col, cols) || !(width > 0)) return null;
|
|
401
|
+
const stored = storedWidths(block, cols);
|
|
402
|
+
if (stored?.[col] === width) return null;
|
|
403
|
+
const measured = drawn && validWidths(drawn.map(Math.round), cols);
|
|
404
|
+
const widths = stored ?? measured ?? Array(cols).fill(DEFAULT_COLUMN_WIDTH);
|
|
405
|
+
return withAttrs(block, { widths: spliced(widths, col, 1, width) });
|
|
406
|
+
});
|
|
407
|
+
var isCount = (value) => Number.isInteger(value) && value > 0;
|
|
408
|
+
function emptyCells({ rows, cols }) {
|
|
409
|
+
const regions = {};
|
|
410
|
+
for (let row = 0; row < rows; row++) for (let col = 0; col < cols; col++) regions[cellKey(row, col)] = [];
|
|
411
|
+
return regions;
|
|
412
|
+
}
|
|
413
|
+
function insertTable(rows, cols, options = {}) {
|
|
414
|
+
return (state, dispatch) => {
|
|
415
|
+
const { doc, schema } = state;
|
|
416
|
+
const id = headBlockId(state.selection);
|
|
417
|
+
if (id === null || !isCount(rows) || !isCount(cols)) return false;
|
|
418
|
+
const index = requireBlockIndex(doc, id);
|
|
419
|
+
const current = doc.blocks[index];
|
|
420
|
+
const fills = isParagraph(current) && regionLength(current, primaryRegion(schema, current) ?? "") === 0;
|
|
421
|
+
const table = {
|
|
422
|
+
id: fills ? current.id : (options.newId ?? newId)(),
|
|
423
|
+
type: "TABLE",
|
|
424
|
+
indent: current.indent,
|
|
425
|
+
attrs: { header: true, align: Array.from({ length: cols }, () => null), rows, cols },
|
|
426
|
+
regions: emptyCells({ rows, cols })
|
|
427
|
+
};
|
|
428
|
+
const tr = new Transaction(state).step(
|
|
429
|
+
fills ? replaceBlockStep(table) : insertBlocksStep(descendantsEnd(doc, index), [table])
|
|
430
|
+
);
|
|
431
|
+
dispatch?.(tr.setSelection(textSelection({ block: table.id, region: cellKey(0, 0), offset: 0 })));
|
|
432
|
+
return true;
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// src/extensions/table/table-keys.ts
|
|
437
|
+
function headCell({ doc, selection }) {
|
|
438
|
+
if (selection?.kind !== "text") return null;
|
|
439
|
+
const { head } = selection;
|
|
440
|
+
const block = tableBlock(doc, head.block);
|
|
441
|
+
const cell = block && cellOf(head.region);
|
|
442
|
+
return block && cell ? { block, cell, head, shape: tableShape(block) } : null;
|
|
443
|
+
}
|
|
444
|
+
var cellLength = (block, [row, col]) => inlineLength(block.regions[cellKey(row, col)] ?? []);
|
|
445
|
+
var cellPos = (block, cell, atEnd = false) => ({
|
|
446
|
+
block: block.id,
|
|
447
|
+
region: cellKey(...cell),
|
|
448
|
+
offset: atEnd ? cellLength(block, cell) : 0
|
|
449
|
+
});
|
|
450
|
+
var moveTo = (state, pos) => new Transaction(state).setSelection(textSelection(pos));
|
|
451
|
+
var thenCaretIn = (command, blockId, at) => (state, dispatch) => {
|
|
452
|
+
const caret = textSelection({ block: blockId, region: cellKey(...at), offset: 0 });
|
|
453
|
+
return command(state, dispatch && ((tr) => dispatch(tr.setSelection(caret))));
|
|
454
|
+
};
|
|
455
|
+
var cellAtIndex = (index, { cols }) => [Math.floor(index / cols), index % cols];
|
|
456
|
+
var indexOfCell = ([row, col], { cols }) => row * cols + col;
|
|
457
|
+
var nextCell = (state, dispatch) => {
|
|
458
|
+
const caret = headCell(state);
|
|
459
|
+
if (caret === null) return false;
|
|
460
|
+
const { block, cell, shape } = caret;
|
|
461
|
+
const next = indexOfCell(cell, shape) + 1;
|
|
462
|
+
if (next === shape.rows * shape.cols) {
|
|
463
|
+
return thenCaretIn(addRow(block.id, shape.rows), block.id, [shape.rows, 0])(state, dispatch);
|
|
464
|
+
}
|
|
465
|
+
dispatch?.(moveTo(state, cellPos(block, cellAtIndex(next, shape), true)));
|
|
466
|
+
return true;
|
|
467
|
+
};
|
|
468
|
+
var previousCell = (state, dispatch) => {
|
|
469
|
+
const caret = headCell(state);
|
|
470
|
+
if (caret === null) return false;
|
|
471
|
+
const { block, cell, shape } = caret;
|
|
472
|
+
const previous = indexOfCell(cell, shape) - 1;
|
|
473
|
+
if (previous >= 0) dispatch?.(moveTo(state, cellPos(block, cellAtIndex(previous, shape), true)));
|
|
474
|
+
return true;
|
|
475
|
+
};
|
|
476
|
+
var enterInCell = (state, dispatch) => {
|
|
477
|
+
const caret = headCell(state);
|
|
478
|
+
if (caret === null) return false;
|
|
479
|
+
if (cellSelection(state) !== null) return true;
|
|
480
|
+
const { block, cell, shape } = caret;
|
|
481
|
+
const [row, col] = cell;
|
|
482
|
+
if (row === shape.rows - 1 && cellLength(block, cell) === 0) {
|
|
483
|
+
return thenCaretIn(addRow(block.id, shape.rows), block.id, [shape.rows, col])(state, dispatch);
|
|
484
|
+
}
|
|
485
|
+
return insertHardBreak(state, dispatch);
|
|
486
|
+
};
|
|
487
|
+
var stopAtCellEdge = (atEnd) => (state) => {
|
|
488
|
+
const caret = headCell(state);
|
|
489
|
+
if (caret === null || !isCollapsed(state.selection)) return false;
|
|
490
|
+
return caret.head.offset === (atEnd ? cellLength(caret.block, caret.cell) : 0);
|
|
491
|
+
};
|
|
492
|
+
var firstThatApplies = (...commands) => (state, dispatch) => commands.some((command) => command(state, dispatch));
|
|
493
|
+
var MARK_KEYS = {
|
|
494
|
+
"Mod-b": "bold",
|
|
495
|
+
"Mod-i": "italic",
|
|
496
|
+
"Mod-u": "underline",
|
|
497
|
+
"Mod-Shift-s": "strike",
|
|
498
|
+
"Mod-e": "code",
|
|
499
|
+
"Mod-Shift-h": "highlight"
|
|
500
|
+
};
|
|
501
|
+
var tableKeymap = {
|
|
502
|
+
Tab: nextCell,
|
|
503
|
+
"Shift-Tab": previousCell,
|
|
504
|
+
Enter: enterInCell,
|
|
505
|
+
Backspace: firstThatApplies(deleteCellContents, stopAtCellEdge(false)),
|
|
506
|
+
Delete: firstThatApplies(deleteCellContents, stopAtCellEdge(true)),
|
|
507
|
+
...Object.fromEntries(Object.entries(MARK_KEYS).map(([name, mark]) => [name, setCellsMark(mark)]))
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
// src/extensions/table/use-cell-press.ts
|
|
511
|
+
function cellOf2(element) {
|
|
512
|
+
const row = element.getAttribute("data-row");
|
|
513
|
+
const col = element.getAttribute("data-col");
|
|
514
|
+
return element.matches("td, th") && row !== null && col !== null ? [Number(row), Number(col)] : null;
|
|
515
|
+
}
|
|
516
|
+
function useCellPress(controller, blockId, table, editable) {
|
|
517
|
+
useEffect(() => {
|
|
518
|
+
const element = table.current;
|
|
519
|
+
if (!editable || element === null) return;
|
|
520
|
+
const onPointerDown = (event) => {
|
|
521
|
+
const cell = event.button === 0 && event.pointerType !== "touch" ? cellOf2(event.target) : null;
|
|
522
|
+
const block = cell && blockById(controller.editor.state.doc, blockId);
|
|
523
|
+
if (!cell || !block) return;
|
|
524
|
+
event.preventDefault();
|
|
525
|
+
event.stopPropagation();
|
|
526
|
+
controller.focus(cellPos(block, cell, true));
|
|
527
|
+
};
|
|
528
|
+
element.addEventListener("pointerdown", onPointerDown);
|
|
529
|
+
return () => element.removeEventListener("pointerdown", onPointerDown);
|
|
530
|
+
}, [controller, blockId, table, editable]);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// src/extensions/table/use-reveal-cell.ts
|
|
534
|
+
import { useCallback as useCallback3, useEffect as useEffect2 } from "react";
|
|
535
|
+
function useRevealCell(controller, blockId) {
|
|
536
|
+
const region = useEditorState(
|
|
537
|
+
controller,
|
|
538
|
+
useCallback3(
|
|
539
|
+
(state) => {
|
|
540
|
+
const caret = headCell(state);
|
|
541
|
+
return caret?.block.id === blockId ? caret.head.region : null;
|
|
542
|
+
},
|
|
543
|
+
[blockId]
|
|
544
|
+
)
|
|
545
|
+
);
|
|
546
|
+
useEffect2(() => {
|
|
547
|
+
const host = region === null ? void 0 : controller.registry.get(blockId, region);
|
|
548
|
+
const root = controller.root;
|
|
549
|
+
if (!host || !root?.contains(root.ownerDocument.activeElement)) return;
|
|
550
|
+
host.closest("td, th")?.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
551
|
+
}, [controller, blockId, region]);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// src/extensions/table/use-table-keys.ts
|
|
555
|
+
import { useEffect as useEffect3 } from "react";
|
|
556
|
+
|
|
557
|
+
// src/extensions/table/vertical-cell-move.ts
|
|
558
|
+
var VERTICAL = { ArrowUp: -1, ArrowDown: 1 };
|
|
559
|
+
function caretAtGoal(controller, blockId, cell, direction) {
|
|
560
|
+
const region = cellKey(...cell);
|
|
561
|
+
const host = controller.registry.get(blockId, region);
|
|
562
|
+
const { goalX } = controller;
|
|
563
|
+
const line = host && lineEdgeRect(host, direction < 0);
|
|
564
|
+
if (!host || !line || goalX === null) return null;
|
|
565
|
+
const box = host.getBoundingClientRect();
|
|
566
|
+
const x = Math.min(Math.max(goalX, box.left), box.right - 1);
|
|
567
|
+
const point = caretFromPoint(host.ownerDocument, x, line.top + line.height / 2);
|
|
568
|
+
const pos = point && domToPos(controller.registry, point.node, point.offset);
|
|
569
|
+
return pos && pos.block === blockId && pos.region === region ? pos : null;
|
|
570
|
+
}
|
|
571
|
+
var plainArrow = (event) => event.altKey || event.ctrlKey || event.metaKey ? void 0 : VERTICAL[event.key];
|
|
572
|
+
function caretOnEdgeLine(controller, head, direction) {
|
|
573
|
+
const host = controller.registry.get(head.block, head.region);
|
|
574
|
+
const point = posToDom(controller.registry, head);
|
|
575
|
+
if (!host || !point || !(direction < 0 ? isOnFirstLine(host, point) : isOnLastLine(host, point))) return null;
|
|
576
|
+
return { left: caretClientRect(point)?.left ?? null };
|
|
577
|
+
}
|
|
578
|
+
function columnAt(controller, blockId, row, x) {
|
|
579
|
+
const cells = Array.from(controller.blockElement(blockId)?.querySelector("table")?.rows[row]?.cells ?? []);
|
|
580
|
+
const index = cells.findIndex((cell) => x < cell.getBoundingClientRect().right);
|
|
581
|
+
return index === -1 ? Math.max(cells.length - 1, 0) : index;
|
|
582
|
+
}
|
|
583
|
+
function enterTable(controller, blockId, event) {
|
|
584
|
+
const direction = plainArrow(event);
|
|
585
|
+
const { state } = controller.editor;
|
|
586
|
+
const { selection } = state;
|
|
587
|
+
const block = tableBlock(state.doc, blockId);
|
|
588
|
+
if (direction === void 0 || event.shiftKey || block === null || selection?.kind !== "text") return false;
|
|
589
|
+
if (!isCollapsed(selection) || neighbourBlock(state.doc, selection.head.block, direction)?.id !== blockId) return false;
|
|
590
|
+
const caret = caretOnEdgeLine(controller, selection.head, direction);
|
|
591
|
+
if (caret === null) return false;
|
|
592
|
+
controller.goalX ??= caret.left;
|
|
593
|
+
const { rows, cols } = tableShape(block);
|
|
594
|
+
const row = direction > 0 ? 0 : rows - 1;
|
|
595
|
+
const { goalX } = controller;
|
|
596
|
+
const cell = [row, goalX === null ? direction > 0 ? 0 : cols - 1 : columnAt(controller, blockId, row, goalX)];
|
|
597
|
+
const pos = caretAtGoal(controller, blockId, cell, direction) ?? cellPos(block, cell, direction < 0);
|
|
598
|
+
controller.dispatch(controller.editor.createTransaction().setSelection(textSelection(pos)));
|
|
599
|
+
return true;
|
|
600
|
+
}
|
|
601
|
+
function moveBetweenRows(controller, blockId, event) {
|
|
602
|
+
const direction = plainArrow(event);
|
|
603
|
+
const { state } = controller.editor;
|
|
604
|
+
const caret = headCell(state);
|
|
605
|
+
if (direction === void 0 || caret === null || caret.block.id !== blockId || state.selection?.kind !== "text") {
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
608
|
+
const target = [caret.cell[0] + direction, caret.cell[1]];
|
|
609
|
+
if (target[0] < 0 || target[0] >= caret.shape.rows) return false;
|
|
610
|
+
const edge = caretOnEdgeLine(controller, caret.head, direction);
|
|
611
|
+
if (edge === null) return false;
|
|
612
|
+
controller.goalX ??= edge.left;
|
|
613
|
+
const pos = caretAtGoal(controller, blockId, target, direction) ?? cellPos(caret.block, target, direction < 0);
|
|
614
|
+
const selection = event.shiftKey ? textSelection(state.selection.anchor, pos) : textSelection(pos);
|
|
615
|
+
controller.dispatch(controller.editor.createTransaction().setSelection(selection));
|
|
616
|
+
return true;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// src/extensions/table/use-table-keys.ts
|
|
620
|
+
var printable = (event) => [...event.key].length === 1 && !event.ctrlKey && !event.metaKey;
|
|
621
|
+
function typeOver(controller, blockId, event) {
|
|
622
|
+
if (cellSelection(controller.editor.state)?.block !== blockId || !printable(event)) return false;
|
|
623
|
+
return controller.run(typeOverCells(event.key));
|
|
624
|
+
}
|
|
625
|
+
function useTableKeys(controller, blockId, editable) {
|
|
626
|
+
useEffect3(() => {
|
|
627
|
+
if (!editable) return;
|
|
628
|
+
const intercept = (event) => {
|
|
629
|
+
if (isComposingKey(controller, event)) return false;
|
|
630
|
+
const handled = typeOver(controller, blockId, event) || moveBetweenRows(controller, blockId, event) || enterTable(controller, blockId, event);
|
|
631
|
+
if (handled) event.preventDefault();
|
|
632
|
+
return handled;
|
|
633
|
+
};
|
|
634
|
+
return interceptKeys(controller, intercept);
|
|
635
|
+
}, [controller, blockId, editable]);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// src/extensions/table/TableBlock.tsx
|
|
639
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
640
|
+
var indexes = (from, to) => Array.from({ length: Math.max(to - from, 0) }, (_, i) => from + i);
|
|
641
|
+
function TableBlock({ block, controller, labels }) {
|
|
642
|
+
const readOnly = useReadOnly(controller);
|
|
643
|
+
const table = useRef(null);
|
|
644
|
+
const { rows, cols } = tableShape(block);
|
|
645
|
+
const header = block.attrs.header !== false && rows > 0;
|
|
646
|
+
const aligns = columnAligns(block, cols);
|
|
647
|
+
const preview = useWidthPreview(controller, block.id);
|
|
648
|
+
const widths = preview?.length === cols ? preview : storedWidths(block, cols);
|
|
649
|
+
useTableKeys(controller, block.id, !readOnly);
|
|
650
|
+
useCellPress(controller, block.id, table, !readOnly);
|
|
651
|
+
useRevealCell(controller, block.id);
|
|
652
|
+
const row = (index) => /* @__PURE__ */ jsx2("tr", { children: indexes(0, cols).map((col) => /* @__PURE__ */ jsx2(
|
|
653
|
+
TableCell,
|
|
654
|
+
{
|
|
655
|
+
controller,
|
|
656
|
+
blockId: block.id,
|
|
657
|
+
row: index,
|
|
658
|
+
col,
|
|
659
|
+
header: header && index === 0,
|
|
660
|
+
align: aligns[col],
|
|
661
|
+
label: labels.cell(index + 1, col + 1)
|
|
662
|
+
},
|
|
663
|
+
col
|
|
664
|
+
)) }, index);
|
|
665
|
+
const scroller = readOnly ? { role: "region", "aria-label": labels.table, tabIndex: 0 } : void 0;
|
|
666
|
+
return /* @__PURE__ */ jsx2("div", { contentEditable: false, className: "quoin-table", "data-readonly": readOnly ? "" : void 0, children: /* @__PURE__ */ jsxs("div", { className: `quoin-table-scroll ${readOnly ? FOCUS_RING : ""}`, ...scroller, children: [
|
|
667
|
+
/* @__PURE__ */ jsxs(
|
|
668
|
+
"table",
|
|
669
|
+
{
|
|
670
|
+
ref: table,
|
|
671
|
+
"aria-label": readOnly ? void 0 : labels.table,
|
|
672
|
+
style: widths === null ? void 0 : { width: widths.reduce((sum, width) => sum + width, 0), tableLayout: "fixed" },
|
|
673
|
+
children: [
|
|
674
|
+
widths !== null && /* @__PURE__ */ jsx2("colgroup", { children: widths.map((width, col) => /* @__PURE__ */ jsx2("col", { style: { width } }, col)) }),
|
|
675
|
+
header && /* @__PURE__ */ jsx2("thead", { children: row(0) }),
|
|
676
|
+
rows > (header ? 1 : 0) && /* @__PURE__ */ jsx2("tbody", { children: indexes(header ? 1 : 0, rows).map(row) })
|
|
677
|
+
]
|
|
678
|
+
}
|
|
679
|
+
),
|
|
680
|
+
!readOnly && /* @__PURE__ */ jsx2("div", { className: "quoin-table-controls", ...{ [CONTROLS_SLOT]: "" } })
|
|
681
|
+
] }) });
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// src/extensions/table/TableControls.tsx
|
|
685
|
+
import { useCallback as useCallback5, useEffect as useEffect7, useState as useState3 } from "react";
|
|
686
|
+
import { createPortal } from "react-dom";
|
|
687
|
+
|
|
688
|
+
// src/extensions/table/menu-cells.ts
|
|
689
|
+
var EMPTY = [];
|
|
690
|
+
function lineCells(block, index, axis) {
|
|
691
|
+
const { rows, cols } = tableShape(block);
|
|
692
|
+
return Array.from(
|
|
693
|
+
{ length: axis === "row" ? cols : rows },
|
|
694
|
+
(_, other) => axis === "row" ? block.regions[cellKey(index, other)] ?? EMPTY : block.regions[cellKey(other, index)] ?? EMPTY
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
var sameLine = (before, after, index, axis) => sameItems(lineCells(before, index, axis), lineCells(after, index, axis), equalInline);
|
|
698
|
+
function sameMenuCells(opened, current, target, axis) {
|
|
699
|
+
const shape = tableShape(opened);
|
|
700
|
+
const lines = axis === "row" ? shape.rows : shape.cols;
|
|
701
|
+
const index = Math.min(axis === "row" ? target.row : target.col, lines - 1);
|
|
702
|
+
if (sameLine(opened, current, index, axis)) return true;
|
|
703
|
+
const reshaped = tableShape(current);
|
|
704
|
+
if (reshaped.rows !== shape.rows || reshaped.cols !== shape.cols) return false;
|
|
705
|
+
const others = Array.from({ length: lines }, (_, other) => other);
|
|
706
|
+
return others.every((other) => other === index || sameLine(opened, current, other, axis));
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// src/extensions/table/TableHandles.tsx
|
|
710
|
+
import { useRef as useRef3 } from "react";
|
|
711
|
+
import { Plus } from "lucide-react";
|
|
712
|
+
|
|
713
|
+
// src/extensions/table/ColumnResizer.tsx
|
|
714
|
+
import { useEffect as useEffect4, useRef as useRef2 } from "react";
|
|
715
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
716
|
+
var MIN_COLUMN_WIDTH = 48;
|
|
717
|
+
var MAX_COLUMN_WIDTH = 1200;
|
|
718
|
+
var STEP = 10;
|
|
719
|
+
var LARGE_STEP = 50;
|
|
720
|
+
var clampWidth = (px) => Math.min(MAX_COLUMN_WIDTH, Math.max(MIN_COLUMN_WIDTH, Math.round(px)));
|
|
721
|
+
function ColumnResizer(props) {
|
|
722
|
+
const { controller, labels, blockId, col, drawn, style, resizerRef, onHold, onBack } = props;
|
|
723
|
+
const drag = useRef2(null);
|
|
724
|
+
const width = Math.round(drawn[col] ?? 0);
|
|
725
|
+
const store = tableUiStore(controller);
|
|
726
|
+
const write = (px, widths) => {
|
|
727
|
+
if (!controller.readOnly) controller.run(setColumnWidth(blockId, col, px, widths));
|
|
728
|
+
};
|
|
729
|
+
const onKeyDown = (event) => {
|
|
730
|
+
if (isComposingKey(controller, event.nativeEvent)) return;
|
|
731
|
+
const step = event.shiftKey ? LARGE_STEP : STEP;
|
|
732
|
+
const tab = event.key === "Tab" && !event.altKey && !event.ctrlKey && !event.metaKey;
|
|
733
|
+
if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
|
|
734
|
+
const next = clampWidth(width + (event.key === "ArrowLeft" ? -step : step));
|
|
735
|
+
if (next !== width) write(next, drawn);
|
|
736
|
+
} else if (tab && event.shiftKey) onBack();
|
|
737
|
+
else if (tab || event.key === "Escape") controller.focus();
|
|
738
|
+
else return;
|
|
739
|
+
event.preventDefault();
|
|
740
|
+
};
|
|
741
|
+
const onPointerDown = (event) => {
|
|
742
|
+
if (event.button !== 0) return;
|
|
743
|
+
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
744
|
+
drag.current = { x: event.clientX, widths: [...drawn], to: null };
|
|
745
|
+
onHold(true);
|
|
746
|
+
};
|
|
747
|
+
const onPointerMove = (event) => {
|
|
748
|
+
const current = drag.current;
|
|
749
|
+
if (current === null) return;
|
|
750
|
+
current.to = clampWidth(current.widths[col] + event.clientX - current.x);
|
|
751
|
+
const widths = current.widths.map((px, i) => i === col ? current.to ?? px : px);
|
|
752
|
+
store.set({ preview: { block: blockId, widths } });
|
|
753
|
+
};
|
|
754
|
+
const stop = () => {
|
|
755
|
+
const current = drag.current;
|
|
756
|
+
drag.current = null;
|
|
757
|
+
store.set({ preview: null });
|
|
758
|
+
onHold(false);
|
|
759
|
+
return current;
|
|
760
|
+
};
|
|
761
|
+
useEffect4(
|
|
762
|
+
() => () => {
|
|
763
|
+
if (drag.current !== null) store.set({ preview: null });
|
|
764
|
+
},
|
|
765
|
+
[store]
|
|
766
|
+
);
|
|
767
|
+
const end2 = () => {
|
|
768
|
+
const ended = stop();
|
|
769
|
+
if (ended?.to != null && ended.to !== Math.round(ended.widths[col])) write(ended.to, ended.widths);
|
|
770
|
+
};
|
|
771
|
+
return /* @__PURE__ */ jsx3(
|
|
772
|
+
"div",
|
|
773
|
+
{
|
|
774
|
+
ref: resizerRef,
|
|
775
|
+
role: "separator",
|
|
776
|
+
tabIndex: -1,
|
|
777
|
+
"aria-orientation": "vertical",
|
|
778
|
+
"aria-label": labels.resizeColumn(col + 1),
|
|
779
|
+
"aria-valuenow": width,
|
|
780
|
+
"aria-valuemin": MIN_COLUMN_WIDTH,
|
|
781
|
+
"aria-valuemax": MAX_COLUMN_WIDTH,
|
|
782
|
+
"aria-valuetext": labels.columnWidth(width),
|
|
783
|
+
className: "quoin-table-resizer",
|
|
784
|
+
style,
|
|
785
|
+
...{ [NATIVE_INTERACTION]: "" },
|
|
786
|
+
onKeyDown,
|
|
787
|
+
onPointerDown,
|
|
788
|
+
onPointerMove,
|
|
789
|
+
onPointerUp: end2,
|
|
790
|
+
onPointerCancel: stop
|
|
791
|
+
}
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// src/extensions/table/HandleMenu.tsx
|
|
796
|
+
import { Fragment } from "react";
|
|
797
|
+
import { GripHorizontal, GripVertical } from "lucide-react";
|
|
798
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
799
|
+
var DESTRUCTIVE = "text-destructive focus:text-destructive";
|
|
800
|
+
function HandleMenu({ controller, axis, label, style, items, open, onOpenChange, buttonRef, children }) {
|
|
801
|
+
const run = (item3) => {
|
|
802
|
+
if (controller.run(item3.command)) controller.announce(item3.done);
|
|
803
|
+
};
|
|
804
|
+
const item2 = (entry) => /* @__PURE__ */ jsxs2(
|
|
805
|
+
DropdownMenuItem,
|
|
806
|
+
{
|
|
807
|
+
disabled: entry.disabled,
|
|
808
|
+
className: entry.destructive ? DESTRUCTIVE : void 0,
|
|
809
|
+
onSelect: () => run(entry),
|
|
810
|
+
children: [
|
|
811
|
+
/* @__PURE__ */ jsx4(MenuIcon, { icon: entry.icon }),
|
|
812
|
+
entry.label
|
|
813
|
+
]
|
|
814
|
+
},
|
|
815
|
+
entry.id
|
|
816
|
+
);
|
|
817
|
+
return /* @__PURE__ */ jsxs2(DropdownMenu, { open, onOpenChange, children: [
|
|
818
|
+
/* @__PURE__ */ jsx4(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx4(
|
|
819
|
+
"button",
|
|
820
|
+
{
|
|
821
|
+
ref: buttonRef,
|
|
822
|
+
type: "button",
|
|
823
|
+
tabIndex: -1,
|
|
824
|
+
"aria-label": label,
|
|
825
|
+
"data-axis": axis,
|
|
826
|
+
className: "quoin-table-handle",
|
|
827
|
+
style,
|
|
828
|
+
children: axis === "row" ? /* @__PURE__ */ jsx4(GripVertical, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx4(GripHorizontal, { "aria-hidden": "true" })
|
|
829
|
+
}
|
|
830
|
+
) }),
|
|
831
|
+
open && /* @__PURE__ */ jsxs2(
|
|
832
|
+
DropdownMenuContent,
|
|
833
|
+
{
|
|
834
|
+
align: "start",
|
|
835
|
+
"aria-label": label,
|
|
836
|
+
"aria-labelledby": void 0,
|
|
837
|
+
onCloseAutoFocus: returnFocusToText(controller),
|
|
838
|
+
...bubblePart(controller),
|
|
839
|
+
children: [
|
|
840
|
+
items.filter((entry) => !entry.destructive).map(item2),
|
|
841
|
+
children,
|
|
842
|
+
items.filter((entry) => entry.destructive).map((entry) => /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
843
|
+
/* @__PURE__ */ jsx4(DropdownMenuSeparator, {}),
|
|
844
|
+
item2(entry)
|
|
845
|
+
] }, entry.id))
|
|
846
|
+
]
|
|
847
|
+
}
|
|
848
|
+
)
|
|
849
|
+
] });
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// src/extensions/table/table-menu-items.ts
|
|
853
|
+
import {
|
|
854
|
+
AlignCenter,
|
|
855
|
+
AlignLeft,
|
|
856
|
+
AlignRight,
|
|
857
|
+
ArrowDown,
|
|
858
|
+
ArrowDownToLine,
|
|
859
|
+
ArrowLeft,
|
|
860
|
+
ArrowLeftToLine,
|
|
861
|
+
ArrowRight,
|
|
862
|
+
ArrowRightToLine,
|
|
863
|
+
ArrowUp,
|
|
864
|
+
ArrowUpToLine,
|
|
865
|
+
Trash
|
|
866
|
+
} from "lucide-react";
|
|
867
|
+
var item = (id, label, icon, command, done, options = {}) => ({ id, label, icon, command, done, ...options });
|
|
868
|
+
function rowMenuItems(labels, blockId, row, { rows }) {
|
|
869
|
+
const { rowInserted, rowMoved, rowDeleted } = labels;
|
|
870
|
+
return [
|
|
871
|
+
item("above", labels.insertRowAbove, ArrowUpToLine, addRow(blockId, row), rowInserted),
|
|
872
|
+
item("below", labels.insertRowBelow, ArrowDownToLine, addRow(blockId, row + 1), rowInserted),
|
|
873
|
+
item("up", labels.moveRowUp, ArrowUp, moveRow(blockId, row, row - 1), rowMoved, { disabled: row === 0 }),
|
|
874
|
+
item("down", labels.moveRowDown, ArrowDown, moveRow(blockId, row, row + 1), rowMoved, { disabled: row === rows - 1 }),
|
|
875
|
+
item("delete", labels.deleteRow, Trash, removeRow(blockId, row), rowDeleted, { disabled: rows === 1, destructive: true })
|
|
876
|
+
];
|
|
877
|
+
}
|
|
878
|
+
function columnMenuItems(labels, blockId, col, { cols }) {
|
|
879
|
+
const { columnInserted, columnMoved, columnDeleted } = labels;
|
|
880
|
+
const last = col === cols - 1;
|
|
881
|
+
return [
|
|
882
|
+
item("left", labels.insertColumnLeft, ArrowLeftToLine, addColumn(blockId, col), columnInserted),
|
|
883
|
+
item("right", labels.insertColumnRight, ArrowRightToLine, addColumn(blockId, col + 1), columnInserted),
|
|
884
|
+
item("move-left", labels.moveColumnLeft, ArrowLeft, moveColumn(blockId, col, col - 1), columnMoved, { disabled: col === 0 }),
|
|
885
|
+
item("move-right", labels.moveColumnRight, ArrowRight, moveColumn(blockId, col, col + 1), columnMoved, { disabled: last }),
|
|
886
|
+
item("delete", labels.deleteColumn, Trash, removeColumn(blockId, col), columnDeleted, {
|
|
887
|
+
disabled: cols === 1,
|
|
888
|
+
destructive: true
|
|
889
|
+
})
|
|
890
|
+
];
|
|
891
|
+
}
|
|
892
|
+
var alignItems = (labels) => [
|
|
893
|
+
{ value: "left", label: labels.alignLeft, icon: AlignLeft, done: labels.alignedLeft },
|
|
894
|
+
{ value: "center", label: labels.alignCenter, icon: AlignCenter, done: labels.alignedCenter },
|
|
895
|
+
{ value: "right", label: labels.alignRight, icon: AlignRight, done: labels.alignedRight }
|
|
896
|
+
];
|
|
897
|
+
|
|
898
|
+
// src/extensions/table/TableHandles.tsx
|
|
899
|
+
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
900
|
+
var BESIDE = 4;
|
|
901
|
+
var end = (span) => span.start + span.size;
|
|
902
|
+
function edgeOf(spans, edge) {
|
|
903
|
+
if (edge === null || !Number.isInteger(edge) || edge < 0 || edge > spans.length || spans.length === 0) return null;
|
|
904
|
+
return edge === spans.length ? end(spans[edge - 1]) : spans[edge].start;
|
|
905
|
+
}
|
|
906
|
+
var middle = (span) => span.start + span.size / 2;
|
|
907
|
+
var isTab = (event) => event.key === "Tab" && !event.altKey && !event.ctrlKey && !event.metaKey;
|
|
908
|
+
function TableHandles(props) {
|
|
909
|
+
const { controller, labels, block, target, geometry, menu, onMenu, onHold, focusRequested, onFocused } = props;
|
|
910
|
+
const rowHandle = useRef3(null);
|
|
911
|
+
const columnHandle = useRef3(null);
|
|
912
|
+
const resizer = useRef3(null);
|
|
913
|
+
const shape = tableShape(block);
|
|
914
|
+
const row = Math.min(target.row, shape.rows - 1);
|
|
915
|
+
const col = Math.min(target.col, shape.cols - 1);
|
|
916
|
+
const align = columnAligns(block, shape.cols)[col];
|
|
917
|
+
const drawn = geometry.cols.map((span) => span.size);
|
|
918
|
+
const { rowEdge, colEdge } = target;
|
|
919
|
+
const rowInsertAt = edgeOf(geometry.rows, rowEdge);
|
|
920
|
+
const columnInsertAt = edgeOf(geometry.cols, colEdge);
|
|
921
|
+
useIsomorphicLayoutEffect(() => {
|
|
922
|
+
if (!focusRequested) return;
|
|
923
|
+
(columnHandle.current ?? rowHandle.current)?.focus();
|
|
924
|
+
onFocused();
|
|
925
|
+
}, [focusRequested, onFocused]);
|
|
926
|
+
const run = (command, done) => {
|
|
927
|
+
if (controller.run(command)) controller.announce(done);
|
|
928
|
+
};
|
|
929
|
+
const onKeyDown = (event) => {
|
|
930
|
+
const handles = [rowHandle.current, columnHandle.current].filter((handle) => handle !== null);
|
|
931
|
+
const index = handles.indexOf(event.target);
|
|
932
|
+
if (index === -1 || isComposingKey(controller, event.nativeEvent)) return;
|
|
933
|
+
if (event.key === "ArrowLeft" || event.key === "ArrowRight") handles[(index + 1) % handles.length].focus();
|
|
934
|
+
else if (isTab(event) && !event.shiftKey && resizer.current !== null) resizer.current.focus();
|
|
935
|
+
else if (isTab(event) || event.key === "Escape") controller.focus();
|
|
936
|
+
else return;
|
|
937
|
+
event.preventDefault();
|
|
938
|
+
};
|
|
939
|
+
const place = (left, top) => ({ left, top });
|
|
940
|
+
const opener = (kind) => (open) => onMenu(open ? kind : null);
|
|
941
|
+
return /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
942
|
+
geometry.cols.map((span, index) => /* @__PURE__ */ jsx5(
|
|
943
|
+
ColumnResizer,
|
|
944
|
+
{
|
|
945
|
+
controller,
|
|
946
|
+
labels,
|
|
947
|
+
blockId: block.id,
|
|
948
|
+
col: index,
|
|
949
|
+
drawn,
|
|
950
|
+
style: { left: end(span), top: geometry.top, height: geometry.height },
|
|
951
|
+
resizerRef: index === col ? resizer : void 0,
|
|
952
|
+
onHold,
|
|
953
|
+
onBack: () => (columnHandle.current ?? rowHandle.current)?.focus()
|
|
954
|
+
},
|
|
955
|
+
index
|
|
956
|
+
)),
|
|
957
|
+
/* @__PURE__ */ jsxs3("div", { role: "toolbar", "aria-label": labels.tableControls, className: "quoin-table-toolbar", onKeyDown, children: [
|
|
958
|
+
rowInsertAt === null && geometry.rows[row] && /* @__PURE__ */ jsx5(
|
|
959
|
+
HandleMenu,
|
|
960
|
+
{
|
|
961
|
+
controller,
|
|
962
|
+
axis: "row",
|
|
963
|
+
label: labels.rowOptions(row + 1),
|
|
964
|
+
style: place(geometry.left - BESIDE, middle(geometry.rows[row])),
|
|
965
|
+
items: rowMenuItems(labels, block.id, row, shape),
|
|
966
|
+
open: menu === "row",
|
|
967
|
+
onOpenChange: opener("row"),
|
|
968
|
+
buttonRef: rowHandle,
|
|
969
|
+
children: row === 0 && /* @__PURE__ */ jsx5(
|
|
970
|
+
DropdownMenuCheckboxItem,
|
|
971
|
+
{
|
|
972
|
+
checked: block.attrs.header !== false,
|
|
973
|
+
onCheckedChange: (on) => run(toggleHeaderRow(block.id), on ? labels.headerRowOn : labels.headerRowOff),
|
|
974
|
+
children: labels.headerRow
|
|
975
|
+
}
|
|
976
|
+
)
|
|
977
|
+
}
|
|
978
|
+
),
|
|
979
|
+
columnInsertAt === null && geometry.cols[col] && /* @__PURE__ */ jsxs3(
|
|
980
|
+
HandleMenu,
|
|
981
|
+
{
|
|
982
|
+
controller,
|
|
983
|
+
axis: "column",
|
|
984
|
+
label: labels.columnOptions(col + 1),
|
|
985
|
+
style: place(middle(geometry.cols[col]), geometry.top),
|
|
986
|
+
items: columnMenuItems(labels, block.id, col, shape),
|
|
987
|
+
open: menu === "column",
|
|
988
|
+
onOpenChange: opener("column"),
|
|
989
|
+
buttonRef: columnHandle,
|
|
990
|
+
children: [
|
|
991
|
+
/* @__PURE__ */ jsx5(DropdownMenuSeparator, {}),
|
|
992
|
+
/* @__PURE__ */ jsx5(DropdownMenuRadioGroup, { value: align ?? "", children: alignItems(labels).map(({ value, label, icon, done }) => /* @__PURE__ */ jsxs3(
|
|
993
|
+
DropdownMenuRadioItem,
|
|
994
|
+
{
|
|
995
|
+
value,
|
|
996
|
+
onSelect: () => align === value ? run(setColumnAlign(block.id, col, null), labels.alignmentCleared) : run(setColumnAlign(block.id, col, value), done),
|
|
997
|
+
children: [
|
|
998
|
+
/* @__PURE__ */ jsx5(MenuIcon, { icon }),
|
|
999
|
+
label
|
|
1000
|
+
]
|
|
1001
|
+
},
|
|
1002
|
+
value
|
|
1003
|
+
)) })
|
|
1004
|
+
]
|
|
1005
|
+
}
|
|
1006
|
+
)
|
|
1007
|
+
] }),
|
|
1008
|
+
rowEdge !== null && rowInsertAt !== null && /* @__PURE__ */ jsx5(
|
|
1009
|
+
"button",
|
|
1010
|
+
{
|
|
1011
|
+
type: "button",
|
|
1012
|
+
tabIndex: -1,
|
|
1013
|
+
"aria-label": labels.insertRowAt(rowEdge + 1),
|
|
1014
|
+
"data-axis": "row",
|
|
1015
|
+
className: "quoin-table-insert",
|
|
1016
|
+
style: place(geometry.left - BESIDE, rowInsertAt),
|
|
1017
|
+
onPointerDown: keepFocus,
|
|
1018
|
+
onMouseDown: keepFocus,
|
|
1019
|
+
onClick: () => run(addRow(block.id, rowEdge), labels.rowInserted),
|
|
1020
|
+
children: /* @__PURE__ */ jsx5(Plus, { "aria-hidden": "true" })
|
|
1021
|
+
}
|
|
1022
|
+
),
|
|
1023
|
+
colEdge !== null && columnInsertAt !== null && /* @__PURE__ */ jsx5(
|
|
1024
|
+
"button",
|
|
1025
|
+
{
|
|
1026
|
+
type: "button",
|
|
1027
|
+
tabIndex: -1,
|
|
1028
|
+
"aria-label": labels.insertColumnAt(colEdge + 1),
|
|
1029
|
+
"data-axis": "column",
|
|
1030
|
+
className: "quoin-table-insert",
|
|
1031
|
+
style: place(columnInsertAt, geometry.top),
|
|
1032
|
+
onPointerDown: keepFocus,
|
|
1033
|
+
onMouseDown: keepFocus,
|
|
1034
|
+
onClick: () => run(addColumn(block.id, colEdge), labels.columnInserted),
|
|
1035
|
+
children: /* @__PURE__ */ jsx5(Plus, { "aria-hidden": "true" })
|
|
1036
|
+
}
|
|
1037
|
+
)
|
|
1038
|
+
] });
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
// src/extensions/table/use-table-geometry.ts
|
|
1042
|
+
import { useState } from "react";
|
|
1043
|
+
|
|
1044
|
+
// src/extensions/table/table-geometry.ts
|
|
1045
|
+
function measureTable(table, origin) {
|
|
1046
|
+
const box = table.getBoundingClientRect();
|
|
1047
|
+
const first = table.rows[0];
|
|
1048
|
+
return {
|
|
1049
|
+
left: box.left - origin.left,
|
|
1050
|
+
top: box.top - origin.top,
|
|
1051
|
+
width: box.width,
|
|
1052
|
+
height: box.height,
|
|
1053
|
+
rows: Array.from(table.rows, (row) => {
|
|
1054
|
+
const rect = row.getBoundingClientRect();
|
|
1055
|
+
return { start: rect.top - origin.top, size: rect.height };
|
|
1056
|
+
}),
|
|
1057
|
+
cols: Array.from(first?.cells ?? [], (cell) => {
|
|
1058
|
+
const rect = cell.getBoundingClientRect();
|
|
1059
|
+
return { start: rect.left - origin.left, size: rect.width };
|
|
1060
|
+
})
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
var sameSpans = (a, b) => a.length === b.length && a.every((span, i) => span.start === b[i].start && span.size === b[i].size);
|
|
1064
|
+
var sameGeometry = (a, b) => a === b || a !== null && b !== null && a.left === b.left && a.top === b.top && a.width === b.width && a.height === b.height && sameSpans(a.rows, b.rows) && sameSpans(a.cols, b.cols);
|
|
1065
|
+
function spanAt(spans, at) {
|
|
1066
|
+
const inside = spans.findIndex((span) => at < span.start + span.size);
|
|
1067
|
+
return inside === -1 ? spans.length - 1 : inside;
|
|
1068
|
+
}
|
|
1069
|
+
function edgeNear(spans, at, reach) {
|
|
1070
|
+
if (spans.length === 0) return null;
|
|
1071
|
+
const edges = [spans[0].start, ...spans.map((span) => span.start + span.size)];
|
|
1072
|
+
const index = edges.findIndex((edge) => Math.abs(edge - at) <= reach);
|
|
1073
|
+
return index === -1 ? null : index;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
// src/extensions/table/use-table-geometry.ts
|
|
1077
|
+
function useTableGeometry(controller, blockId, slot) {
|
|
1078
|
+
const [geometry, setGeometry] = useState(null);
|
|
1079
|
+
useIsomorphicLayoutEffect(() => {
|
|
1080
|
+
const table = controller.blockElement(blockId)?.querySelector("table");
|
|
1081
|
+
const view = slot.ownerDocument.defaultView;
|
|
1082
|
+
if (!table || !view) return;
|
|
1083
|
+
const measure = () => {
|
|
1084
|
+
const next = measureTable(table, slot.getBoundingClientRect());
|
|
1085
|
+
setGeometry((current) => sameGeometry(current, next) ? current : next);
|
|
1086
|
+
};
|
|
1087
|
+
measure();
|
|
1088
|
+
let frame = 0;
|
|
1089
|
+
const later = () => {
|
|
1090
|
+
view.cancelAnimationFrame(frame);
|
|
1091
|
+
frame = view.requestAnimationFrame(measure);
|
|
1092
|
+
};
|
|
1093
|
+
const unsubscribe = controller.editor.subscribe(later);
|
|
1094
|
+
const observer = new ResizeObserver(later);
|
|
1095
|
+
observer.observe(table);
|
|
1096
|
+
view.addEventListener("resize", later);
|
|
1097
|
+
return () => {
|
|
1098
|
+
view.cancelAnimationFrame(frame);
|
|
1099
|
+
unsubscribe();
|
|
1100
|
+
observer.disconnect();
|
|
1101
|
+
view.removeEventListener("resize", later);
|
|
1102
|
+
};
|
|
1103
|
+
}, [controller, blockId, slot]);
|
|
1104
|
+
return geometry;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
// src/extensions/table/use-cut-cells.ts
|
|
1108
|
+
import { useEffect as useEffect5 } from "react";
|
|
1109
|
+
function useCutCells(controller) {
|
|
1110
|
+
useEffect5(() => {
|
|
1111
|
+
const root = controller.root;
|
|
1112
|
+
if (root === null) return;
|
|
1113
|
+
const onCut = (event) => {
|
|
1114
|
+
if (controller.readOnly || cellSelection(controller.editor.state) === null) return;
|
|
1115
|
+
event.stopPropagation();
|
|
1116
|
+
handleCopy(controller, event, false);
|
|
1117
|
+
controller.run(deleteCellContents);
|
|
1118
|
+
};
|
|
1119
|
+
root.addEventListener("cut", onCut, true);
|
|
1120
|
+
return () => root.removeEventListener("cut", onCut, true);
|
|
1121
|
+
}, [controller]);
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// src/extensions/table/use-table-target.ts
|
|
1125
|
+
import { useCallback as useCallback4, useEffect as useEffect6, useState as useState2 } from "react";
|
|
1126
|
+
var EDGE_ZONE = 24;
|
|
1127
|
+
var EDGE_REACH = 8;
|
|
1128
|
+
var VIEWPORT = { left: 0, top: 0 };
|
|
1129
|
+
var CONTROLS = `[${CONTROLS_SLOT}]`;
|
|
1130
|
+
var sameTarget = (a, b) => a === b || a !== null && b !== null && a.block === b.block && a.row === b.row && a.col === b.col && a.rowEdge === b.rowEdge && a.colEdge === b.colEdge;
|
|
1131
|
+
function caretTarget(state) {
|
|
1132
|
+
const caret = headCell(state);
|
|
1133
|
+
return caret && { block: caret.block.id, row: caret.cell[0], col: caret.cell[1], rowEdge: null, colEdge: null };
|
|
1134
|
+
}
|
|
1135
|
+
function pointerTarget(controller, event) {
|
|
1136
|
+
const blockId = controller.blockAt(event.target);
|
|
1137
|
+
const block = blockId === void 0 ? null : tableBlock(controller.editor.state.doc, blockId);
|
|
1138
|
+
const table = block && controller.blockElement(block.id)?.querySelector("table");
|
|
1139
|
+
if (!block || !table) return null;
|
|
1140
|
+
const geometry = measureTable(table, VIEWPORT);
|
|
1141
|
+
const { clientX: x, clientY: y } = event;
|
|
1142
|
+
const row = spanAt(geometry.rows, y);
|
|
1143
|
+
const col = spanAt(geometry.cols, x);
|
|
1144
|
+
if (row < 0 || col < 0) return null;
|
|
1145
|
+
const rowEdge = x < geometry.left + EDGE_ZONE ? edgeNear(geometry.rows, y, EDGE_REACH) : null;
|
|
1146
|
+
const colEdge = y < geometry.top + EDGE_ZONE ? edgeNear(geometry.cols, x, EDGE_REACH) : null;
|
|
1147
|
+
return { block: block.id, row, col, rowEdge, colEdge };
|
|
1148
|
+
}
|
|
1149
|
+
function shapeOf(state, blockId) {
|
|
1150
|
+
const block = tableBlock(state.doc, blockId);
|
|
1151
|
+
if (block === null) return null;
|
|
1152
|
+
const { rows, cols } = tableShape(block);
|
|
1153
|
+
return `${rows}x${cols}`;
|
|
1154
|
+
}
|
|
1155
|
+
function focusOf(root) {
|
|
1156
|
+
const active = root.ownerDocument.activeElement;
|
|
1157
|
+
if (active === null || !root.contains(active)) return "none";
|
|
1158
|
+
return active.closest(CONTROLS) === null ? "editor" : "controls";
|
|
1159
|
+
}
|
|
1160
|
+
function useTableTarget(controller, held) {
|
|
1161
|
+
const [hovered, setHovered] = useState2(null);
|
|
1162
|
+
const [focus, setFocus] = useState2("none");
|
|
1163
|
+
const caret = useEditorState(controller, caretTarget, sameTarget);
|
|
1164
|
+
const hoveredBlock = hovered?.target.block ?? null;
|
|
1165
|
+
const shape = useEditorState(
|
|
1166
|
+
controller,
|
|
1167
|
+
useCallback4((state) => hoveredBlock === null ? null : shapeOf(state, hoveredBlock), [hoveredBlock])
|
|
1168
|
+
);
|
|
1169
|
+
const pointed = hovered !== null && hovered.shape === shape ? hovered.target : null;
|
|
1170
|
+
useEffect6(() => {
|
|
1171
|
+
const root = controller.root;
|
|
1172
|
+
if (root === null) return;
|
|
1173
|
+
const onPointerMove = (event) => {
|
|
1174
|
+
if (event.pointerType === "touch") return;
|
|
1175
|
+
const target = pointerTarget(controller, event);
|
|
1176
|
+
const next = target && { target, shape: shapeOf(controller.editor.state, target.block) };
|
|
1177
|
+
setHovered(
|
|
1178
|
+
(current) => current !== null && next !== null && sameTarget(current.target, next.target) && current.shape === next.shape ? current : next
|
|
1179
|
+
);
|
|
1180
|
+
};
|
|
1181
|
+
const onPointerLeave = () => setHovered(null);
|
|
1182
|
+
const onFocusChange = () => setFocus(focusOf(root));
|
|
1183
|
+
const onFocusOut = (event) => {
|
|
1184
|
+
const next = event.relatedTarget;
|
|
1185
|
+
setFocus(next !== null && root.contains(next) ? next.closest(CONTROLS) ? "controls" : "editor" : "none");
|
|
1186
|
+
};
|
|
1187
|
+
setFocus(focusOf(root));
|
|
1188
|
+
root.addEventListener("pointermove", onPointerMove);
|
|
1189
|
+
root.addEventListener("pointerleave", onPointerLeave);
|
|
1190
|
+
root.addEventListener("focusin", onFocusChange);
|
|
1191
|
+
root.addEventListener("focusout", onFocusOut);
|
|
1192
|
+
return () => {
|
|
1193
|
+
root.removeEventListener("pointermove", onPointerMove);
|
|
1194
|
+
root.removeEventListener("pointerleave", onPointerLeave);
|
|
1195
|
+
root.removeEventListener("focusin", onFocusChange);
|
|
1196
|
+
root.removeEventListener("focusout", onFocusOut);
|
|
1197
|
+
};
|
|
1198
|
+
}, [controller]);
|
|
1199
|
+
if (held !== null) return held;
|
|
1200
|
+
if (focus === "controls") return caret ?? pointed;
|
|
1201
|
+
return pointed ?? (focus === "editor" ? caret : null);
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
// src/extensions/table/TableControls.tsx
|
|
1205
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1206
|
+
var isFocusKey = (event) => event.key === "F10" && event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey;
|
|
1207
|
+
var takesFocusKey = (state) => isCollapsed(state.selection) || cellSelection(state) !== null;
|
|
1208
|
+
function TableControls({ controller, labels }) {
|
|
1209
|
+
const readOnly = useReadOnly(controller);
|
|
1210
|
+
const [held, setHeld] = useState3(null);
|
|
1211
|
+
const [focusFor, setFocusFor] = useState3(null);
|
|
1212
|
+
const [slot, setSlot] = useState3(null);
|
|
1213
|
+
const target = useTableTarget(controller, held?.target ?? null);
|
|
1214
|
+
useCutCells(controller);
|
|
1215
|
+
const blockId = target?.block ?? null;
|
|
1216
|
+
const block = useEditorState(
|
|
1217
|
+
controller,
|
|
1218
|
+
useCallback5((state) => blockId === null ? null : tableBlock(state.doc, blockId), [blockId])
|
|
1219
|
+
);
|
|
1220
|
+
if (held?.menu && held.opened && block && held.opened !== block) {
|
|
1221
|
+
setHeld(sameMenuCells(held.opened, block, held.target, held.menu) ? { ...held, opened: block } : null);
|
|
1222
|
+
}
|
|
1223
|
+
useEffect7(() => {
|
|
1224
|
+
if (!readOnly && block !== null) return;
|
|
1225
|
+
setHeld(null);
|
|
1226
|
+
setFocusFor(null);
|
|
1227
|
+
}, [readOnly, block]);
|
|
1228
|
+
useEffect7(() => {
|
|
1229
|
+
if (readOnly) return;
|
|
1230
|
+
const intercept = (event) => {
|
|
1231
|
+
const { state } = controller.editor;
|
|
1232
|
+
const caret = caretTarget(state);
|
|
1233
|
+
if (!isFocusKey(event) || isComposingKey(controller, event) || caret === null || !takesFocusKey(state)) return false;
|
|
1234
|
+
event.preventDefault();
|
|
1235
|
+
setHeld({ target: caret, menu: null });
|
|
1236
|
+
setFocusFor(caret.block);
|
|
1237
|
+
return true;
|
|
1238
|
+
};
|
|
1239
|
+
return interceptKeys(controller, intercept);
|
|
1240
|
+
}, [controller, readOnly]);
|
|
1241
|
+
const onMenu = useCallback5(
|
|
1242
|
+
(menu) => setHeld(menu === null || target === null || block === null ? null : { target, menu, opened: block }),
|
|
1243
|
+
[target, block]
|
|
1244
|
+
);
|
|
1245
|
+
const onHold = useCallback5((hold) => setHeld(hold && target !== null ? { target, menu: null } : null), [target]);
|
|
1246
|
+
const onFocused = useCallback5(() => {
|
|
1247
|
+
setFocusFor(null);
|
|
1248
|
+
setHeld((current) => current?.menu === null ? null : current);
|
|
1249
|
+
}, []);
|
|
1250
|
+
useIsomorphicLayoutEffect(() => {
|
|
1251
|
+
const drawn = block === null || readOnly ? null : controlsSlot(controller, block.id);
|
|
1252
|
+
setSlot((current) => current === drawn ? current : drawn);
|
|
1253
|
+
});
|
|
1254
|
+
if (target === null || block === null || readOnly || slot === null || !slot.isConnected) return null;
|
|
1255
|
+
return createPortal(
|
|
1256
|
+
/* @__PURE__ */ jsx6(
|
|
1257
|
+
PlacedHandles,
|
|
1258
|
+
{
|
|
1259
|
+
controller,
|
|
1260
|
+
labels,
|
|
1261
|
+
block,
|
|
1262
|
+
target,
|
|
1263
|
+
slot,
|
|
1264
|
+
menu: held?.menu ?? null,
|
|
1265
|
+
onMenu,
|
|
1266
|
+
onHold,
|
|
1267
|
+
focusRequested: focusFor === block.id,
|
|
1268
|
+
onFocused
|
|
1269
|
+
},
|
|
1270
|
+
block.id
|
|
1271
|
+
),
|
|
1272
|
+
slot
|
|
1273
|
+
);
|
|
1274
|
+
}
|
|
1275
|
+
function PlacedHandles({ slot, ...props }) {
|
|
1276
|
+
const geometry = useTableGeometry(props.controller, props.block.id, slot);
|
|
1277
|
+
return geometry === null ? null : /* @__PURE__ */ jsx6(TableHandles, { ...props, geometry });
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
// src/extensions/table/table-labels.ts
|
|
1281
|
+
var englishTableLabels = {
|
|
1282
|
+
table: "Table",
|
|
1283
|
+
tableDescription: "Rows and columns of text",
|
|
1284
|
+
cell: (row, col) => `Row ${row}, column ${col}`,
|
|
1285
|
+
tableControls: "Table controls",
|
|
1286
|
+
rowOptions: (row) => `Row ${row} options`,
|
|
1287
|
+
columnOptions: (col) => `Column ${col} options`,
|
|
1288
|
+
insertRowAbove: "Insert row above",
|
|
1289
|
+
insertRowBelow: "Insert row below",
|
|
1290
|
+
insertColumnLeft: "Insert column left",
|
|
1291
|
+
insertColumnRight: "Insert column right",
|
|
1292
|
+
moveRowUp: "Move row up",
|
|
1293
|
+
moveRowDown: "Move row down",
|
|
1294
|
+
moveColumnLeft: "Move column left",
|
|
1295
|
+
moveColumnRight: "Move column right",
|
|
1296
|
+
deleteRow: "Delete row",
|
|
1297
|
+
deleteColumn: "Delete column",
|
|
1298
|
+
headerRow: "Header row",
|
|
1299
|
+
alignLeft: "Align left",
|
|
1300
|
+
alignCenter: "Align center",
|
|
1301
|
+
alignRight: "Align right",
|
|
1302
|
+
insertRowAt: (row) => `Insert row ${row}`,
|
|
1303
|
+
insertColumnAt: (col) => `Insert column ${col}`,
|
|
1304
|
+
resizeColumn: (col) => `Resize column ${col}`,
|
|
1305
|
+
columnWidth: (px) => `${px} pixels`,
|
|
1306
|
+
rowInserted: "Row inserted",
|
|
1307
|
+
rowDeleted: "Row deleted",
|
|
1308
|
+
rowMoved: "Row moved",
|
|
1309
|
+
columnInserted: "Column inserted",
|
|
1310
|
+
columnDeleted: "Column deleted",
|
|
1311
|
+
columnMoved: "Column moved",
|
|
1312
|
+
headerRowOn: "Header row on",
|
|
1313
|
+
headerRowOff: "Header row off",
|
|
1314
|
+
alignedLeft: "Column aligned left",
|
|
1315
|
+
alignedCenter: "Column aligned center",
|
|
1316
|
+
alignedRight: "Column aligned right",
|
|
1317
|
+
alignmentCleared: "Column alignment cleared"
|
|
1318
|
+
};
|
|
1319
|
+
function resolveTableLabels(overrides) {
|
|
1320
|
+
const given = Object.entries(overrides ?? {}).filter(([, value]) => value !== void 0);
|
|
1321
|
+
return given.length === 0 ? englishTableLabels : { ...englishTableLabels, ...Object.fromEntries(given) };
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
// src/extensions/table/table-slash-item.ts
|
|
1325
|
+
import { Table } from "lucide-react";
|
|
1326
|
+
var NEW_TABLE = { rows: 3, cols: 3 };
|
|
1327
|
+
var tableSlashItem = (labels) => ({
|
|
1328
|
+
id: "table",
|
|
1329
|
+
title: labels.table,
|
|
1330
|
+
description: labels.tableDescription,
|
|
1331
|
+
group: "advanced",
|
|
1332
|
+
icon: Table,
|
|
1333
|
+
keywords: ["grid", "rows", "columns", "spreadsheet", "|"],
|
|
1334
|
+
command: () => insertTable(NEW_TABLE.rows, NEW_TABLE.cols)
|
|
1335
|
+
});
|
|
1336
|
+
|
|
1337
|
+
// src/extensions/table/table-extension.tsx
|
|
1338
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
1339
|
+
var ABOVE_CORE_KEYS = 200;
|
|
1340
|
+
var pasteOverCells = {
|
|
1341
|
+
name: "table-cells",
|
|
1342
|
+
match: (text, state) => cellSelection(state) === null ? null : typeOverCells(text.replace(/\r\n?/g, "\n"))
|
|
1343
|
+
};
|
|
1344
|
+
function tableExtension(options = {}) {
|
|
1345
|
+
const labels = resolveTableLabels(options.labels);
|
|
1346
|
+
const TableRenderer = (props) => /* @__PURE__ */ jsx7(TableBlock, { ...props, labels });
|
|
1347
|
+
const TableOverlay = ({ controller }) => /* @__PURE__ */ jsx7(TableControls, { controller, labels });
|
|
1348
|
+
const ui = {
|
|
1349
|
+
slashItems: [tableSlashItem(labels)],
|
|
1350
|
+
renderers: { TABLE: TableRenderer },
|
|
1351
|
+
blockNames: { TABLE: labels.table },
|
|
1352
|
+
overlays: [TableOverlay]
|
|
1353
|
+
};
|
|
1354
|
+
return defineExtension({
|
|
1355
|
+
name: "table",
|
|
1356
|
+
priority: ABOVE_CORE_KEYS,
|
|
1357
|
+
plugins: [cellSelectionPlugin],
|
|
1358
|
+
keymap: tableKeymap,
|
|
1359
|
+
pasteRules: [pasteOverCells],
|
|
1360
|
+
ui
|
|
1361
|
+
});
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
export {
|
|
1365
|
+
cellSelectionKey,
|
|
1366
|
+
cellSelectionPlugin,
|
|
1367
|
+
cellSelection,
|
|
1368
|
+
cellsInRange,
|
|
1369
|
+
selectCells,
|
|
1370
|
+
deleteCellContents,
|
|
1371
|
+
setCellsMark,
|
|
1372
|
+
addRow,
|
|
1373
|
+
removeRow,
|
|
1374
|
+
moveRow,
|
|
1375
|
+
addColumn,
|
|
1376
|
+
removeColumn,
|
|
1377
|
+
moveColumn,
|
|
1378
|
+
toggleHeaderRow,
|
|
1379
|
+
setColumnAlign,
|
|
1380
|
+
setColumnWidth,
|
|
1381
|
+
insertTable,
|
|
1382
|
+
englishTableLabels,
|
|
1383
|
+
tableExtension
|
|
1384
|
+
};
|
|
1385
|
+
//# sourceMappingURL=chunk-UCXLRRWY.js.map
|