@threadlabs/looma 0.1.0 → 0.1.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/README.md +4 -4
- package/editor/chunk-YGJLGDQC.js +4010 -0
- package/editor/extensions/index.d.ts +4 -8
- package/editor/extensions/index.js +1 -1
- package/editor/index.d.ts +0 -3
- package/editor/index.js +1 -1
- package/package.json +1 -125
- package/editor/chunk-JKRA4D4W.js +0 -435
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import * as _tiptap_core from '@tiptap/core';
|
|
2
1
|
import { AnyExtension, Editor, Range } from '@tiptap/core';
|
|
3
2
|
import { a as TableOverlayActionEventDetail } from '../table-overlay-DTr3KC9e.js';
|
|
4
|
-
import * as _tiptap_extension_table_cell from '@tiptap/extension-table-cell';
|
|
5
|
-
import * as _tiptap_extension_table_header from '@tiptap/extension-table-header';
|
|
6
|
-
import * as _tiptap_extension_table from '@tiptap/extension-table';
|
|
7
3
|
|
|
8
4
|
/**
|
|
9
5
|
* Default Tiptap extension preset for Looma editor.
|
|
10
|
-
* Uses Vanilla JS Tiptap API; apps
|
|
6
|
+
* Uses the Vanilla JS Tiptap API; apps provide @tiptap/core and Looma ships the preset extensions.
|
|
11
7
|
*/
|
|
12
8
|
|
|
13
9
|
interface DefaultEditorExtensionsOptions {
|
|
@@ -67,9 +63,9 @@ declare const TABLE_CELL_BACKGROUND_PRESETS: {
|
|
|
67
63
|
readonly green: "#dcfce7";
|
|
68
64
|
readonly red: "#fee2e2";
|
|
69
65
|
};
|
|
70
|
-
declare const LoomaTable:
|
|
71
|
-
declare const LoomaTableHeader:
|
|
72
|
-
declare const LoomaTableCell:
|
|
66
|
+
declare const LoomaTable: AnyExtension;
|
|
67
|
+
declare const LoomaTableHeader: AnyExtension;
|
|
68
|
+
declare const LoomaTableCell: AnyExtension;
|
|
73
69
|
declare function getActiveTableCellAlignment(editor: Editor): TableCellAlignment;
|
|
74
70
|
declare function getActiveTableCellBackground(editor: Editor): TableCellBackground;
|
|
75
71
|
declare function setActiveTableCellAlignment(editor: Editor, alignment: TableCellAlignment): boolean;
|
package/editor/index.d.ts
CHANGED
|
@@ -2,6 +2,3 @@ export { InsertTableEventDetail, SlashMenuAnchorRect, SlashMenuHighlightEventDet
|
|
|
2
2
|
export { T as TableOverlayAction, a as TableOverlayActionEventDetail } from './table-overlay-DTr3KC9e.js';
|
|
3
3
|
export { DefaultEditorExtensionsOptions, InsertTableAtRangeOptions, LoomaTable, LoomaTableCell, LoomaTableHeader, TABLE_CELL_BACKGROUND_PRESETS, TableCellAlignment, TableCellBackground, getActiveTableCellAlignment, getActiveTableCellBackground, getDefaultEditorExtensions, handleTableOverlayAction, insertTableAtRange, normalizeActiveTableColumnWidths, setActiveTableCellAlignment, setActiveTableCellBackground } from './extensions/index.js';
|
|
4
4
|
import '@tiptap/core';
|
|
5
|
-
import '@tiptap/extension-table-cell';
|
|
6
|
-
import '@tiptap/extension-table-header';
|
|
7
|
-
import '@tiptap/extension-table';
|
package/editor/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@threadlabs/looma",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Looma web components, layout primitives, editor UI, and supported Vue adapters.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -95,140 +95,16 @@
|
|
|
95
95
|
],
|
|
96
96
|
"peerDependencies": {
|
|
97
97
|
"@tiptap/core": ">=2 <3",
|
|
98
|
-
"@tiptap/extension-blockquote": ">=2 <3",
|
|
99
|
-
"@tiptap/extension-bold": ">=2 <3",
|
|
100
|
-
"@tiptap/extension-bullet-list": ">=2 <3",
|
|
101
|
-
"@tiptap/extension-code": ">=2 <3",
|
|
102
|
-
"@tiptap/extension-code-block": ">=2 <3",
|
|
103
|
-
"@tiptap/extension-document": ">=2 <3",
|
|
104
|
-
"@tiptap/extension-dropcursor": ">=2 <3",
|
|
105
|
-
"@tiptap/extension-gapcursor": ">=2 <3",
|
|
106
|
-
"@tiptap/extension-hard-break": ">=2 <3",
|
|
107
|
-
"@tiptap/extension-heading": ">=2 <3",
|
|
108
|
-
"@tiptap/extension-highlight": ">=2 <3",
|
|
109
|
-
"@tiptap/extension-history": ">=2 <3",
|
|
110
|
-
"@tiptap/extension-horizontal-rule": ">=2 <3",
|
|
111
|
-
"@tiptap/extension-image": ">=2 <3",
|
|
112
|
-
"@tiptap/extension-italic": ">=2 <3",
|
|
113
|
-
"@tiptap/extension-link": ">=2 <3",
|
|
114
|
-
"@tiptap/extension-list-item": ">=2 <3",
|
|
115
|
-
"@tiptap/extension-ordered-list": ">=2 <3",
|
|
116
|
-
"@tiptap/extension-paragraph": ">=2 <3",
|
|
117
|
-
"@tiptap/extension-placeholder": ">=2 <3",
|
|
118
|
-
"@tiptap/extension-strike": ">=2 <3",
|
|
119
|
-
"@tiptap/extension-table": ">=2 <3",
|
|
120
|
-
"@tiptap/extension-table-cell": ">=2 <3",
|
|
121
|
-
"@tiptap/extension-table-header": ">=2 <3",
|
|
122
|
-
"@tiptap/extension-table-row": ">=2 <3",
|
|
123
|
-
"@tiptap/extension-task-item": ">=2 <3",
|
|
124
|
-
"@tiptap/extension-task-list": ">=2 <3",
|
|
125
|
-
"@tiptap/extension-text": ">=2 <3",
|
|
126
|
-
"@tiptap/extension-typography": ">=2 <3",
|
|
127
|
-
"@tiptap/extension-underline": ">=2 <3",
|
|
128
98
|
"@tiptap/pm": ">=2 <3",
|
|
129
|
-
"prosemirror-tables": "^1.8.5",
|
|
130
99
|
"vue": "^3.5.0"
|
|
131
100
|
},
|
|
132
101
|
"peerDependenciesMeta": {
|
|
133
102
|
"@tiptap/core": {
|
|
134
103
|
"optional": true
|
|
135
104
|
},
|
|
136
|
-
"@tiptap/extension-blockquote": {
|
|
137
|
-
"optional": true
|
|
138
|
-
},
|
|
139
|
-
"@tiptap/extension-bold": {
|
|
140
|
-
"optional": true
|
|
141
|
-
},
|
|
142
|
-
"@tiptap/extension-bullet-list": {
|
|
143
|
-
"optional": true
|
|
144
|
-
},
|
|
145
|
-
"@tiptap/extension-code": {
|
|
146
|
-
"optional": true
|
|
147
|
-
},
|
|
148
|
-
"@tiptap/extension-code-block": {
|
|
149
|
-
"optional": true
|
|
150
|
-
},
|
|
151
|
-
"@tiptap/extension-document": {
|
|
152
|
-
"optional": true
|
|
153
|
-
},
|
|
154
|
-
"@tiptap/extension-dropcursor": {
|
|
155
|
-
"optional": true
|
|
156
|
-
},
|
|
157
|
-
"@tiptap/extension-gapcursor": {
|
|
158
|
-
"optional": true
|
|
159
|
-
},
|
|
160
|
-
"@tiptap/extension-hard-break": {
|
|
161
|
-
"optional": true
|
|
162
|
-
},
|
|
163
|
-
"@tiptap/extension-heading": {
|
|
164
|
-
"optional": true
|
|
165
|
-
},
|
|
166
|
-
"@tiptap/extension-highlight": {
|
|
167
|
-
"optional": true
|
|
168
|
-
},
|
|
169
|
-
"@tiptap/extension-history": {
|
|
170
|
-
"optional": true
|
|
171
|
-
},
|
|
172
|
-
"@tiptap/extension-horizontal-rule": {
|
|
173
|
-
"optional": true
|
|
174
|
-
},
|
|
175
|
-
"@tiptap/extension-image": {
|
|
176
|
-
"optional": true
|
|
177
|
-
},
|
|
178
|
-
"@tiptap/extension-italic": {
|
|
179
|
-
"optional": true
|
|
180
|
-
},
|
|
181
|
-
"@tiptap/extension-link": {
|
|
182
|
-
"optional": true
|
|
183
|
-
},
|
|
184
|
-
"@tiptap/extension-list-item": {
|
|
185
|
-
"optional": true
|
|
186
|
-
},
|
|
187
|
-
"@tiptap/extension-ordered-list": {
|
|
188
|
-
"optional": true
|
|
189
|
-
},
|
|
190
|
-
"@tiptap/extension-paragraph": {
|
|
191
|
-
"optional": true
|
|
192
|
-
},
|
|
193
|
-
"@tiptap/extension-placeholder": {
|
|
194
|
-
"optional": true
|
|
195
|
-
},
|
|
196
|
-
"@tiptap/extension-strike": {
|
|
197
|
-
"optional": true
|
|
198
|
-
},
|
|
199
|
-
"@tiptap/extension-table": {
|
|
200
|
-
"optional": true
|
|
201
|
-
},
|
|
202
|
-
"@tiptap/extension-table-cell": {
|
|
203
|
-
"optional": true
|
|
204
|
-
},
|
|
205
|
-
"@tiptap/extension-table-header": {
|
|
206
|
-
"optional": true
|
|
207
|
-
},
|
|
208
|
-
"@tiptap/extension-table-row": {
|
|
209
|
-
"optional": true
|
|
210
|
-
},
|
|
211
|
-
"@tiptap/extension-task-item": {
|
|
212
|
-
"optional": true
|
|
213
|
-
},
|
|
214
|
-
"@tiptap/extension-task-list": {
|
|
215
|
-
"optional": true
|
|
216
|
-
},
|
|
217
|
-
"@tiptap/extension-text": {
|
|
218
|
-
"optional": true
|
|
219
|
-
},
|
|
220
|
-
"@tiptap/extension-typography": {
|
|
221
|
-
"optional": true
|
|
222
|
-
},
|
|
223
|
-
"@tiptap/extension-underline": {
|
|
224
|
-
"optional": true
|
|
225
|
-
},
|
|
226
105
|
"@tiptap/pm": {
|
|
227
106
|
"optional": true
|
|
228
107
|
},
|
|
229
|
-
"prosemirror-tables": {
|
|
230
|
-
"optional": true
|
|
231
|
-
},
|
|
232
108
|
"vue": {
|
|
233
109
|
"optional": true
|
|
234
110
|
}
|
package/editor/chunk-JKRA4D4W.js
DELETED
|
@@ -1,435 +0,0 @@
|
|
|
1
|
-
// src/extensions/preset.ts
|
|
2
|
-
import Document from "@tiptap/extension-document";
|
|
3
|
-
import Paragraph from "@tiptap/extension-paragraph";
|
|
4
|
-
import Text from "@tiptap/extension-text";
|
|
5
|
-
import Bold from "@tiptap/extension-bold";
|
|
6
|
-
import Italic from "@tiptap/extension-italic";
|
|
7
|
-
import Strike from "@tiptap/extension-strike";
|
|
8
|
-
import Underline from "@tiptap/extension-underline";
|
|
9
|
-
import Heading from "@tiptap/extension-heading";
|
|
10
|
-
import BulletList from "@tiptap/extension-bullet-list";
|
|
11
|
-
import OrderedList from "@tiptap/extension-ordered-list";
|
|
12
|
-
import ListItem from "@tiptap/extension-list-item";
|
|
13
|
-
import TaskList from "@tiptap/extension-task-list";
|
|
14
|
-
import TaskItem from "@tiptap/extension-task-item";
|
|
15
|
-
import Blockquote from "@tiptap/extension-blockquote";
|
|
16
|
-
import HorizontalRule from "@tiptap/extension-horizontal-rule";
|
|
17
|
-
import HardBreak from "@tiptap/extension-hard-break";
|
|
18
|
-
import History from "@tiptap/extension-history";
|
|
19
|
-
import Dropcursor from "@tiptap/extension-dropcursor";
|
|
20
|
-
import Gapcursor from "@tiptap/extension-gapcursor";
|
|
21
|
-
import Link from "@tiptap/extension-link";
|
|
22
|
-
import Image from "@tiptap/extension-image";
|
|
23
|
-
import Highlight from "@tiptap/extension-highlight";
|
|
24
|
-
import Typography from "@tiptap/extension-typography";
|
|
25
|
-
import Placeholder from "@tiptap/extension-placeholder";
|
|
26
|
-
import Code from "@tiptap/extension-code";
|
|
27
|
-
import CodeBlock from "@tiptap/extension-code-block";
|
|
28
|
-
import TableRow from "@tiptap/extension-table-row";
|
|
29
|
-
|
|
30
|
-
// src/extensions/list-behavior.ts
|
|
31
|
-
import { Extension } from "@tiptap/core";
|
|
32
|
-
function isEmptyParagraphAtStart(editor) {
|
|
33
|
-
const { selection } = editor.state;
|
|
34
|
-
return selection.empty && selection.$from.parent.isTextblock && selection.$from.parent.content.size === 0 && selection.$from.parentOffset === 0;
|
|
35
|
-
}
|
|
36
|
-
var LoomaListBehavior = Extension.create({
|
|
37
|
-
name: "loomaListBehavior",
|
|
38
|
-
addKeyboardShortcuts() {
|
|
39
|
-
return {
|
|
40
|
-
Enter: () => {
|
|
41
|
-
if (this.editor.isActive("taskItem")) {
|
|
42
|
-
return this.editor.commands.splitListItem("taskItem");
|
|
43
|
-
}
|
|
44
|
-
if (this.editor.isActive("listItem")) {
|
|
45
|
-
return this.editor.commands.splitListItem("listItem");
|
|
46
|
-
}
|
|
47
|
-
return false;
|
|
48
|
-
},
|
|
49
|
-
Backspace: () => {
|
|
50
|
-
if (!isEmptyParagraphAtStart(this.editor)) {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
if (this.editor.isActive("taskItem")) {
|
|
54
|
-
return this.editor.commands.liftListItem("taskItem");
|
|
55
|
-
}
|
|
56
|
-
if (this.editor.isActive("listItem")) {
|
|
57
|
-
return this.editor.commands.liftListItem("listItem");
|
|
58
|
-
}
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
// src/extensions/table-formatting.ts
|
|
66
|
-
import TableBase from "@tiptap/extension-table";
|
|
67
|
-
import TableCellBase from "@tiptap/extension-table-cell";
|
|
68
|
-
import TableHeaderBase from "@tiptap/extension-table-header";
|
|
69
|
-
var TABLE_CELL_BACKGROUND_PRESETS = {
|
|
70
|
-
none: null,
|
|
71
|
-
gray: "#f3f4f6",
|
|
72
|
-
yellow: "#fef3c7",
|
|
73
|
-
blue: "#dbeafe",
|
|
74
|
-
green: "#dcfce7",
|
|
75
|
-
red: "#fee2e2"
|
|
76
|
-
};
|
|
77
|
-
var LoomaTable = TableBase.configure({
|
|
78
|
-
resizable: true,
|
|
79
|
-
lastColumnResizable: false
|
|
80
|
-
});
|
|
81
|
-
function normalizeTableCellAlignment(value) {
|
|
82
|
-
if (value === "left" || value === "center" || value === "right") {
|
|
83
|
-
return value;
|
|
84
|
-
}
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
function normalizeTableCellBackground(value) {
|
|
88
|
-
if (typeof value !== "string") {
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
const normalized = value.trim();
|
|
92
|
-
return normalized.length > 0 ? normalized : null;
|
|
93
|
-
}
|
|
94
|
-
function renderTableCellStyle(attributes) {
|
|
95
|
-
const styleFragments = [];
|
|
96
|
-
const textAlign = normalizeTableCellAlignment(attributes.textAlign);
|
|
97
|
-
const backgroundColor = normalizeTableCellBackground(attributes.backgroundColor);
|
|
98
|
-
if (textAlign && textAlign !== "left") {
|
|
99
|
-
styleFragments.push(`text-align: ${textAlign}`);
|
|
100
|
-
}
|
|
101
|
-
if (backgroundColor) {
|
|
102
|
-
styleFragments.push(`background-color: ${backgroundColor}`);
|
|
103
|
-
}
|
|
104
|
-
return styleFragments.length > 0 ? `${styleFragments.join("; ")};` : null;
|
|
105
|
-
}
|
|
106
|
-
var tableAlignmentAttributes = {
|
|
107
|
-
textAlign: {
|
|
108
|
-
default: null,
|
|
109
|
-
parseHTML: (element) => normalizeTableCellAlignment(element.style.textAlign),
|
|
110
|
-
renderHTML: (attributes) => {
|
|
111
|
-
const style = renderTableCellStyle(attributes);
|
|
112
|
-
return style ? { style } : {};
|
|
113
|
-
}
|
|
114
|
-
},
|
|
115
|
-
backgroundColor: {
|
|
116
|
-
default: null,
|
|
117
|
-
parseHTML: (element) => normalizeTableCellBackground(element.style.backgroundColor),
|
|
118
|
-
renderHTML: (attributes) => {
|
|
119
|
-
const style = renderTableCellStyle(attributes);
|
|
120
|
-
return style ? { style } : {};
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
var LoomaTableHeader = TableHeaderBase.extend({
|
|
125
|
-
addAttributes() {
|
|
126
|
-
return {
|
|
127
|
-
...this.parent?.(),
|
|
128
|
-
...tableAlignmentAttributes
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
var LoomaTableCell = TableCellBase.extend({
|
|
133
|
-
addAttributes() {
|
|
134
|
-
return {
|
|
135
|
-
...this.parent?.(),
|
|
136
|
-
...tableAlignmentAttributes
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
function getActiveTableCellAlignment(editor) {
|
|
141
|
-
const { $from } = editor.state.selection;
|
|
142
|
-
for (let depth = $from.depth; depth > 0; depth -= 1) {
|
|
143
|
-
const node = $from.node(depth);
|
|
144
|
-
if (node.type.name === "tableCell" || node.type.name === "tableHeader") {
|
|
145
|
-
return normalizeTableCellAlignment(node.attrs.textAlign) ?? "left";
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return "left";
|
|
149
|
-
}
|
|
150
|
-
function getActiveTableCellBackground(editor) {
|
|
151
|
-
const { $from } = editor.state.selection;
|
|
152
|
-
for (let depth = $from.depth; depth > 0; depth -= 1) {
|
|
153
|
-
const node = $from.node(depth);
|
|
154
|
-
if (node.type.name === "tableCell" || node.type.name === "tableHeader") {
|
|
155
|
-
return normalizeTableCellBackground(node.attrs.backgroundColor);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
return null;
|
|
159
|
-
}
|
|
160
|
-
function setActiveTableCellAlignment(editor, alignment) {
|
|
161
|
-
const textAlign = alignment === "left" ? null : alignment;
|
|
162
|
-
if (editor.isActive("tableHeader")) {
|
|
163
|
-
return editor.chain().focus().updateAttributes("tableHeader", { textAlign }).run();
|
|
164
|
-
}
|
|
165
|
-
if (editor.isActive("tableCell")) {
|
|
166
|
-
return editor.chain().focus().updateAttributes("tableCell", { textAlign }).run();
|
|
167
|
-
}
|
|
168
|
-
return false;
|
|
169
|
-
}
|
|
170
|
-
function setActiveTableCellBackground(editor, backgroundColor) {
|
|
171
|
-
const normalizedBackgroundColor = normalizeTableCellBackground(backgroundColor);
|
|
172
|
-
if (editor.isActive("tableHeader")) {
|
|
173
|
-
return editor.chain().focus().updateAttributes("tableHeader", {
|
|
174
|
-
backgroundColor: normalizedBackgroundColor
|
|
175
|
-
}).run();
|
|
176
|
-
}
|
|
177
|
-
if (editor.isActive("tableCell")) {
|
|
178
|
-
return editor.chain().focus().updateAttributes("tableCell", {
|
|
179
|
-
backgroundColor: normalizedBackgroundColor
|
|
180
|
-
}).run();
|
|
181
|
-
}
|
|
182
|
-
return false;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// src/extensions/preset.ts
|
|
186
|
-
function getDefaultEditorExtensions(options = {}) {
|
|
187
|
-
const {
|
|
188
|
-
placeholder = "Type \u201C/\u201D for commands, or start writing\u2026",
|
|
189
|
-
linkOpenOnClick = false,
|
|
190
|
-
imageInline = false
|
|
191
|
-
} = options;
|
|
192
|
-
return [
|
|
193
|
-
Document,
|
|
194
|
-
Paragraph,
|
|
195
|
-
Text,
|
|
196
|
-
Bold,
|
|
197
|
-
Italic,
|
|
198
|
-
Strike,
|
|
199
|
-
Underline,
|
|
200
|
-
Heading.configure({ levels: [1, 2, 3] }),
|
|
201
|
-
BulletList,
|
|
202
|
-
OrderedList,
|
|
203
|
-
ListItem,
|
|
204
|
-
TaskList,
|
|
205
|
-
TaskItem.configure({ nested: false }),
|
|
206
|
-
Blockquote,
|
|
207
|
-
HorizontalRule,
|
|
208
|
-
HardBreak,
|
|
209
|
-
History,
|
|
210
|
-
Dropcursor,
|
|
211
|
-
Gapcursor,
|
|
212
|
-
Link.configure({
|
|
213
|
-
openOnClick: linkOpenOnClick,
|
|
214
|
-
HTMLAttributes: { rel: "noopener noreferrer", target: "_blank" }
|
|
215
|
-
}),
|
|
216
|
-
Image.configure({ inline: imageInline }),
|
|
217
|
-
Highlight.configure({ multicolor: false }),
|
|
218
|
-
Code,
|
|
219
|
-
CodeBlock,
|
|
220
|
-
Typography,
|
|
221
|
-
Placeholder.configure({
|
|
222
|
-
placeholder: ({ node }) => node.type.name === "paragraph" ? placeholder : "",
|
|
223
|
-
emptyNodeClass: "is-editor-empty"
|
|
224
|
-
}),
|
|
225
|
-
LoomaTable,
|
|
226
|
-
TableRow,
|
|
227
|
-
LoomaTableHeader,
|
|
228
|
-
LoomaTableCell,
|
|
229
|
-
LoomaListBehavior
|
|
230
|
-
];
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// src/extensions/table-commands.ts
|
|
234
|
-
import { TableMap } from "prosemirror-tables";
|
|
235
|
-
function arrayEquals(left, right) {
|
|
236
|
-
if (!left || left.length !== right.length) {
|
|
237
|
-
return false;
|
|
238
|
-
}
|
|
239
|
-
return left.every((value, index) => value === right[index]);
|
|
240
|
-
}
|
|
241
|
-
function readRenderedColumnWidths(tableElement) {
|
|
242
|
-
const colElements = Array.from(tableElement.querySelectorAll("colgroup col"));
|
|
243
|
-
if (colElements.length > 0) {
|
|
244
|
-
return colElements.map((column) => Math.max(1, Math.round(column.getBoundingClientRect().width)));
|
|
245
|
-
}
|
|
246
|
-
const firstRow = tableElement.rows.item(0);
|
|
247
|
-
if (!firstRow) {
|
|
248
|
-
return [];
|
|
249
|
-
}
|
|
250
|
-
return Array.from(firstRow.cells).map((cell) => Math.max(1, Math.round(cell.getBoundingClientRect().width)));
|
|
251
|
-
}
|
|
252
|
-
function distributeWidthDelta(widths, availableWidth, minWidth) {
|
|
253
|
-
const normalized = [...widths];
|
|
254
|
-
let delta = availableWidth - normalized.reduce((sum, width) => sum + width, 0);
|
|
255
|
-
while (delta !== 0) {
|
|
256
|
-
const adjustableIndices = normalized.map((width, index) => ({ width, index })).filter(({ width }) => delta > 0 || width > minWidth).sort((left, right) => {
|
|
257
|
-
if (delta > 0) {
|
|
258
|
-
return left.width - right.width;
|
|
259
|
-
}
|
|
260
|
-
return right.width - left.width;
|
|
261
|
-
});
|
|
262
|
-
if (adjustableIndices.length === 0) {
|
|
263
|
-
break;
|
|
264
|
-
}
|
|
265
|
-
for (const { index } of adjustableIndices) {
|
|
266
|
-
if (delta === 0) {
|
|
267
|
-
break;
|
|
268
|
-
}
|
|
269
|
-
const currentWidth = normalized[index];
|
|
270
|
-
if (currentWidth === void 0) {
|
|
271
|
-
continue;
|
|
272
|
-
}
|
|
273
|
-
if (delta > 0) {
|
|
274
|
-
normalized[index] = currentWidth + 1;
|
|
275
|
-
delta -= 1;
|
|
276
|
-
continue;
|
|
277
|
-
}
|
|
278
|
-
if (currentWidth <= minWidth) {
|
|
279
|
-
continue;
|
|
280
|
-
}
|
|
281
|
-
normalized[index] = currentWidth - 1;
|
|
282
|
-
delta += 1;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
return normalized;
|
|
286
|
-
}
|
|
287
|
-
function normalizeColumnWidths(widths, availableWidth, minWidth) {
|
|
288
|
-
if (widths.length === 0 || availableWidth <= 0) {
|
|
289
|
-
return widths;
|
|
290
|
-
}
|
|
291
|
-
const totalWidth = widths.reduce((sum, width) => sum + width, 0);
|
|
292
|
-
if (totalWidth <= 0) {
|
|
293
|
-
return widths;
|
|
294
|
-
}
|
|
295
|
-
const scaled = widths.map(
|
|
296
|
-
(width) => Math.max(minWidth, Math.round(width / totalWidth * availableWidth))
|
|
297
|
-
);
|
|
298
|
-
return distributeWidthDelta(scaled, availableWidth, minWidth);
|
|
299
|
-
}
|
|
300
|
-
function getTextPositionInCell(tablePos, table, rowIndex, colIndex) {
|
|
301
|
-
let pos = tablePos + 1;
|
|
302
|
-
for (let r = 0; r < rowIndex; r++) {
|
|
303
|
-
pos += table.child(r).nodeSize;
|
|
304
|
-
}
|
|
305
|
-
const row = table.child(rowIndex);
|
|
306
|
-
for (let c = 0; c < colIndex; c++) {
|
|
307
|
-
pos += row.child(c).nodeSize;
|
|
308
|
-
}
|
|
309
|
-
return pos + 3;
|
|
310
|
-
}
|
|
311
|
-
function findTable(editor) {
|
|
312
|
-
const { $from } = editor.state.selection;
|
|
313
|
-
for (let d = $from.depth; d > 0; d--) {
|
|
314
|
-
const node = $from.node(d);
|
|
315
|
-
if (node.type.name === "table") {
|
|
316
|
-
return { pos: $from.before(d), node };
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
return null;
|
|
320
|
-
}
|
|
321
|
-
function insertTableAtRange(editor, range, options = {}) {
|
|
322
|
-
const rows = Math.min(10, Math.max(1, options.rows ?? 3));
|
|
323
|
-
const cols = Math.min(10, Math.max(1, options.cols ?? 3));
|
|
324
|
-
const withHeaderRow = options.withHeaderRow ?? true;
|
|
325
|
-
return editor.chain().focus().deleteRange(range).insertTable({ rows, cols, withHeaderRow }).run();
|
|
326
|
-
}
|
|
327
|
-
function normalizeActiveTableColumnWidths(editor, tableElement, minWidth = 25) {
|
|
328
|
-
const tableInfo = findTable(editor);
|
|
329
|
-
if (!tableInfo) {
|
|
330
|
-
return false;
|
|
331
|
-
}
|
|
332
|
-
const renderedColumnWidths = readRenderedColumnWidths(tableElement);
|
|
333
|
-
if (renderedColumnWidths.length === 0) {
|
|
334
|
-
return false;
|
|
335
|
-
}
|
|
336
|
-
const availableWidth = Math.max(1, Math.round(tableElement.getBoundingClientRect().width));
|
|
337
|
-
const normalizedColumnWidths = normalizeColumnWidths(
|
|
338
|
-
renderedColumnWidths,
|
|
339
|
-
availableWidth,
|
|
340
|
-
minWidth
|
|
341
|
-
);
|
|
342
|
-
const { pos: tablePos, node: table } = tableInfo;
|
|
343
|
-
const map = TableMap.get(table);
|
|
344
|
-
const tableStart = tablePos + 1;
|
|
345
|
-
let tr = editor.state.tr;
|
|
346
|
-
let changed = false;
|
|
347
|
-
for (let row = 0; row < map.height; row += 1) {
|
|
348
|
-
for (let col = 0; col < map.width; col += 1) {
|
|
349
|
-
const mapIndex = row * map.width + col;
|
|
350
|
-
const cellPos = map.map[mapIndex];
|
|
351
|
-
if (cellPos === void 0) {
|
|
352
|
-
continue;
|
|
353
|
-
}
|
|
354
|
-
if (col > 0 && map.map[mapIndex - 1] === cellPos || row > 0 && map.map[mapIndex - map.width] === cellPos) {
|
|
355
|
-
continue;
|
|
356
|
-
}
|
|
357
|
-
const cellNode = table.nodeAt(cellPos);
|
|
358
|
-
if (!cellNode) {
|
|
359
|
-
continue;
|
|
360
|
-
}
|
|
361
|
-
const startCol = map.colCount(cellPos);
|
|
362
|
-
const cellWidths = normalizedColumnWidths.slice(startCol, startCol + cellNode.attrs.colspan);
|
|
363
|
-
if (cellWidths.length !== cellNode.attrs.colspan || arrayEquals(cellNode.attrs.colwidth, cellWidths)) {
|
|
364
|
-
continue;
|
|
365
|
-
}
|
|
366
|
-
tr = tr.setNodeMarkup(tableStart + cellPos, null, {
|
|
367
|
-
...cellNode.attrs,
|
|
368
|
-
colwidth: cellWidths
|
|
369
|
-
});
|
|
370
|
-
changed = true;
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
if (changed) {
|
|
374
|
-
editor.view.dispatch(tr);
|
|
375
|
-
}
|
|
376
|
-
return changed;
|
|
377
|
-
}
|
|
378
|
-
function handleTableOverlayAction(editor, detail) {
|
|
379
|
-
const tableInfo = findTable(editor);
|
|
380
|
-
if (!tableInfo) return false;
|
|
381
|
-
const { action, boundaryIndex } = detail;
|
|
382
|
-
const { pos: tablePos, node: table } = tableInfo;
|
|
383
|
-
const rows = table.childCount;
|
|
384
|
-
const cols = rows > 0 ? table.child(0).childCount : 0;
|
|
385
|
-
let cellPos;
|
|
386
|
-
let command;
|
|
387
|
-
switch (action) {
|
|
388
|
-
case "add-row-before": {
|
|
389
|
-
const rowIndex = Math.min(boundaryIndex, rows - 1);
|
|
390
|
-
if (rowIndex < 0) return false;
|
|
391
|
-
cellPos = getTextPositionInCell(tablePos, table, rowIndex, 0);
|
|
392
|
-
command = () => editor.chain().focus().setTextSelection(cellPos).addRowBefore().run();
|
|
393
|
-
break;
|
|
394
|
-
}
|
|
395
|
-
case "add-row-after": {
|
|
396
|
-
const rowIndex = Math.min(boundaryIndex, rows - 1);
|
|
397
|
-
if (rowIndex < 0) return false;
|
|
398
|
-
cellPos = getTextPositionInCell(tablePos, table, rowIndex, 0);
|
|
399
|
-
command = () => editor.chain().focus().setTextSelection(cellPos).addRowAfter().run();
|
|
400
|
-
break;
|
|
401
|
-
}
|
|
402
|
-
case "add-column-before": {
|
|
403
|
-
const colIndex = Math.min(boundaryIndex, cols - 1);
|
|
404
|
-
if (colIndex < 0) return false;
|
|
405
|
-
cellPos = getTextPositionInCell(tablePos, table, 0, colIndex);
|
|
406
|
-
command = () => editor.chain().focus().setTextSelection(cellPos).addColumnBefore().run();
|
|
407
|
-
break;
|
|
408
|
-
}
|
|
409
|
-
case "add-column-after": {
|
|
410
|
-
const colIndex = Math.min(boundaryIndex, cols - 1);
|
|
411
|
-
if (colIndex < 0) return false;
|
|
412
|
-
cellPos = getTextPositionInCell(tablePos, table, 0, colIndex);
|
|
413
|
-
command = () => editor.chain().focus().setTextSelection(cellPos).addColumnAfter().run();
|
|
414
|
-
break;
|
|
415
|
-
}
|
|
416
|
-
default:
|
|
417
|
-
return false;
|
|
418
|
-
}
|
|
419
|
-
return command();
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
export {
|
|
423
|
-
TABLE_CELL_BACKGROUND_PRESETS,
|
|
424
|
-
LoomaTable,
|
|
425
|
-
LoomaTableHeader,
|
|
426
|
-
LoomaTableCell,
|
|
427
|
-
getActiveTableCellAlignment,
|
|
428
|
-
getActiveTableCellBackground,
|
|
429
|
-
setActiveTableCellAlignment,
|
|
430
|
-
setActiveTableCellBackground,
|
|
431
|
-
getDefaultEditorExtensions,
|
|
432
|
-
insertTableAtRange,
|
|
433
|
-
normalizeActiveTableColumnWidths,
|
|
434
|
-
handleTableOverlayAction
|
|
435
|
-
};
|