@aicayzer/inkkit 0.0.18 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +4 -2
- package/README.md +11 -7
- package/dist/THIRD-PARTY-NOTICES.txt +2742 -0
- package/dist/chunks/core-vtCr4MBS.js +56503 -0
- package/dist/chunks/highlight-Daj2fv_u.js +14122 -0
- package/dist/core.d.ts +2 -5
- package/dist/core.js +2 -2
- package/dist/editor.d.ts +229 -47
- package/dist/index.js +5 -3
- package/dist/style.css +231 -202
- package/dist/types.d.ts +143 -18
- package/package.json +16 -13
- package/dist/autolink.d.ts +0 -1
- package/dist/autolink.js +0 -18
- package/dist/callouts.d.ts +0 -25
- package/dist/callouts.js +0 -288
- package/dist/clipboard.d.ts +0 -11
- package/dist/clipboard.js +0 -261
- package/dist/code-fences.d.ts +0 -8
- package/dist/code-fences.js +0 -171
- package/dist/comments.d.ts +0 -76
- package/dist/comments.js +0 -545
- package/dist/cursor.d.ts +0 -2
- package/dist/cursor.js +0 -40
- package/dist/decorations.d.ts +0 -2
- package/dist/decorations.js +0 -67
- package/dist/dialect.d.ts +0 -9
- package/dist/dialect.js +0 -446
- package/dist/drop-placement.d.ts +0 -19
- package/dist/drop-placement.js +0 -47
- package/dist/editor.js +0 -2673
- package/dist/files.d.ts +0 -40
- package/dist/files.js +0 -133
- package/dist/highlight.d.ts +0 -1
- package/dist/highlight.js +0 -136
- package/dist/html-import.d.ts +0 -13
- package/dist/html-import.js +0 -477
- package/dist/image-blocks.d.ts +0 -86
- package/dist/image-blocks.js +0 -329
- package/dist/images.d.ts +0 -51
- package/dist/images.js +0 -398
- package/dist/inline-highlight.d.ts +0 -6
- package/dist/inline-highlight.js +0 -112
- package/dist/labels.d.ts +0 -36
- package/dist/labels.js +0 -34
- package/dist/link-safety.d.ts +0 -17
- package/dist/link-safety.js +0 -29
- package/dist/linked-syntax.d.ts +0 -48
- package/dist/linked-syntax.js +0 -320
- package/dist/literals.d.ts +0 -20
- package/dist/literals.js +0 -216
- package/dist/mermaid.d.ts +0 -28
- package/dist/mermaid.js +0 -404
- package/dist/outline.d.ts +0 -22
- package/dist/outline.js +0 -79
- package/dist/paste-html.d.ts +0 -31
- package/dist/paste-html.js +0 -462
- package/dist/paste.d.ts +0 -33
- package/dist/paste.js +0 -591
- package/dist/portable-files.d.ts +0 -10
- package/dist/portable-files.js +0 -36
- package/dist/preserve.d.ts +0 -38
- package/dist/preserve.js +0 -1396
- package/dist/print.d.ts +0 -7
- package/dist/print.js +0 -406
- package/dist/reference-clipboard.d.ts +0 -8
- package/dist/reference-clipboard.js +0 -201
- package/dist/references.d.ts +0 -16
- package/dist/references.js +0 -418
- package/dist/scroll.d.ts +0 -15
- package/dist/scroll.js +0 -27
- package/dist/search.d.ts +0 -15
- package/dist/search.js +0 -202
- package/dist/selection.d.ts +0 -1
- package/dist/selection.js +0 -59
- package/dist/source.d.ts +0 -16
- package/dist/source.js +0 -57
- package/dist/spreadsheet.d.ts +0 -8
- package/dist/spreadsheet.js +0 -289
- package/dist/table-alignment.d.ts +0 -2
- package/dist/table-alignment.js +0 -46
- package/dist/tables.d.ts +0 -27
- package/dist/tables.js +0 -344
- package/dist/tasks.d.ts +0 -3
- package/dist/tasks.js +0 -51
- package/dist/text-ranges.d.ts +0 -29
- package/dist/text-ranges.js +0 -256
- package/dist/types.js +0 -8
- package/dist/wiki-view.d.ts +0 -21
- package/dist/wiki-view.js +0 -78
package/dist/tables.js
DELETED
|
@@ -1,344 +0,0 @@
|
|
|
1
|
-
import { editorLabels } from './labels.js';
|
|
2
|
-
import { commandsCtx, editorViewCtx } from '@milkdown/kit/core';
|
|
3
|
-
import { tableBlock, tableBlockConfig, } from '@milkdown/kit/component/table-block';
|
|
4
|
-
import { insertTableCommand, exitTable, moveRowCommand, moveColCommand, } from '@milkdown/kit/preset/gfm';
|
|
5
|
-
import { addRowAfter, addRowBefore, addColumnAfter, addColumnBefore, deleteRow, deleteColumn, deleteTable, goToNextCell, selectedRect, TableMap, isInTable, CellSelection, } from '@milkdown/kit/prose/tables';
|
|
6
|
-
import { Fragment } from '@milkdown/kit/prose/model';
|
|
7
|
-
import { closeHistory } from '@milkdown/kit/prose/history';
|
|
8
|
-
import { keymap } from '@milkdown/kit/prose/keymap';
|
|
9
|
-
import { $prose } from '@milkdown/kit/utils';
|
|
10
|
-
import { clipboardText } from './clipboard.js';
|
|
11
|
-
export const tableCommands = [
|
|
12
|
-
'insert',
|
|
13
|
-
'addRowBefore',
|
|
14
|
-
'addRowAfter',
|
|
15
|
-
'addColumnBefore',
|
|
16
|
-
'addColumnAfter',
|
|
17
|
-
'deleteRow',
|
|
18
|
-
'deleteColumn',
|
|
19
|
-
'deleteTable',
|
|
20
|
-
'alignLeft',
|
|
21
|
-
'alignCenter',
|
|
22
|
-
'alignRight',
|
|
23
|
-
'moveRowUp',
|
|
24
|
-
'moveRowDown',
|
|
25
|
-
'moveColumnLeft',
|
|
26
|
-
'moveColumnRight',
|
|
27
|
-
'sortRows',
|
|
28
|
-
'exit',
|
|
29
|
-
];
|
|
30
|
-
export function tableContext(state) {
|
|
31
|
-
if (!isInTable(state))
|
|
32
|
-
return undefined;
|
|
33
|
-
const rect = selectedRect(state);
|
|
34
|
-
return {
|
|
35
|
-
row: rect.top,
|
|
36
|
-
column: rect.left,
|
|
37
|
-
rows: rect.map.height,
|
|
38
|
-
columns: rect.map.width,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
/** Checks the same default operations without dispatching a transaction. */
|
|
42
|
-
export function tableAvailability(ctx) {
|
|
43
|
-
const view = ctx.get(editorViewCtx);
|
|
44
|
-
const state = view.state;
|
|
45
|
-
const commands = ctx.get(commandsCtx);
|
|
46
|
-
const available = Object.fromEntries(tableCommands.map((name) => [name, false]));
|
|
47
|
-
available.insert = commands.get(insertTableCommand.key)({ row: 3, col: 2 })(state);
|
|
48
|
-
const actions = {
|
|
49
|
-
addRowBefore,
|
|
50
|
-
addRowAfter,
|
|
51
|
-
addColumnBefore,
|
|
52
|
-
addColumnAfter,
|
|
53
|
-
deleteRow,
|
|
54
|
-
deleteColumn,
|
|
55
|
-
deleteTable,
|
|
56
|
-
};
|
|
57
|
-
for (const [name, action] of Object.entries(actions))
|
|
58
|
-
available[name] = action(state);
|
|
59
|
-
available.exit = commands.get(exitTable.key)()(state);
|
|
60
|
-
if (!isInTable(state))
|
|
61
|
-
return available;
|
|
62
|
-
const rect = selectedRect(state);
|
|
63
|
-
available.alignLeft = available.alignCenter = available.alignRight = true;
|
|
64
|
-
if (!editableTable(rect.table))
|
|
65
|
-
return available;
|
|
66
|
-
available.moveRowUp = rect.top > 1;
|
|
67
|
-
available.moveRowDown = rect.top > 0 && rect.bottom < rect.map.height;
|
|
68
|
-
available.moveColumnLeft = rect.left > 0;
|
|
69
|
-
available.moveColumnRight = rect.right < rect.map.width;
|
|
70
|
-
const body = [];
|
|
71
|
-
rect.table.forEach((row, _offset, index) => {
|
|
72
|
-
if (index)
|
|
73
|
-
body.push({ key: clipboardText(row.child(rect.left).content), index });
|
|
74
|
-
});
|
|
75
|
-
const sorted = [...body].sort((a, b) => compareCells(a.key, b.key, 'text', 'ascending') || a.index - b.index);
|
|
76
|
-
available.sortRows = sorted.some((row, index) => row !== body[index]);
|
|
77
|
-
return available;
|
|
78
|
-
}
|
|
79
|
-
const tableLabels = {
|
|
80
|
-
add_row: 'tableAddRow',
|
|
81
|
-
add_col: 'tableAddColumn',
|
|
82
|
-
delete_row: 'tableDeleteRow',
|
|
83
|
-
delete_col: 'tableDeleteColumn',
|
|
84
|
-
align_col_left: 'tableAlignLeft',
|
|
85
|
-
align_col_center: 'tableAlignCenter',
|
|
86
|
-
align_col_right: 'tableAlignRight',
|
|
87
|
-
col_drag_handle: 'tableMoveColumn',
|
|
88
|
-
row_drag_handle: 'tableMoveRow',
|
|
89
|
-
};
|
|
90
|
-
function tableButton(label) {
|
|
91
|
-
const span = document.createElement('span');
|
|
92
|
-
span.setAttribute('role', 'img');
|
|
93
|
-
span.setAttribute('aria-label', label);
|
|
94
|
-
span.textContent = label;
|
|
95
|
-
return span.outerHTML;
|
|
96
|
-
}
|
|
97
|
-
export const tablePlugins = [
|
|
98
|
-
moveRowCommand,
|
|
99
|
-
moveColCommand,
|
|
100
|
-
tableBlockConfig,
|
|
101
|
-
(ctx) => () => {
|
|
102
|
-
ctx.update(tableBlockConfig.key, (config) => ({
|
|
103
|
-
...config,
|
|
104
|
-
renderButton: (type) => tableButton(editorLabels(ctx)[tableLabels[type]]),
|
|
105
|
-
}));
|
|
106
|
-
},
|
|
107
|
-
tableBlock,
|
|
108
|
-
$prose(() => keymap({ Tab: goToNextCell(1), 'Shift-Tab': goToNextCell(-1) })),
|
|
109
|
-
].flat();
|
|
110
|
-
export function tableCommand(ctx, command, options) {
|
|
111
|
-
const view = ctx.get(editorViewCtx);
|
|
112
|
-
const commands = ctx.get(commandsCtx);
|
|
113
|
-
if (command === 'insert') {
|
|
114
|
-
const row = options?.rows ?? 3, col = options?.columns ?? 2;
|
|
115
|
-
if (!Number.isInteger(row) ||
|
|
116
|
-
!Number.isInteger(col) ||
|
|
117
|
-
row < 1 ||
|
|
118
|
-
row > 100 ||
|
|
119
|
-
col < 1 ||
|
|
120
|
-
col > 100)
|
|
121
|
-
throw new RangeError('Table dimensions must be integers from 1 to 100');
|
|
122
|
-
return commands.call(insertTableCommand.key, { row, col });
|
|
123
|
-
}
|
|
124
|
-
if (command === 'exit')
|
|
125
|
-
return commands.call(exitTable.key);
|
|
126
|
-
if (command.startsWith('move') || command === 'sortRows')
|
|
127
|
-
return refineTable(view, command, options);
|
|
128
|
-
if (command === 'alignLeft' ||
|
|
129
|
-
command === 'alignCenter' ||
|
|
130
|
-
command === 'alignRight') {
|
|
131
|
-
if (!isInTable(view.state))
|
|
132
|
-
return false;
|
|
133
|
-
const rect = selectedRect(view.state), map = TableMap.get(rect.table);
|
|
134
|
-
const alignment = command === 'alignLeft'
|
|
135
|
-
? 'left'
|
|
136
|
-
: command === 'alignRight'
|
|
137
|
-
? 'right'
|
|
138
|
-
: 'center';
|
|
139
|
-
const tr = view.state.tr;
|
|
140
|
-
// GFM stores alignment on the header; apply it to the entire column so
|
|
141
|
-
// editing a body cell does not disappear when Markdown is saved.
|
|
142
|
-
const positions = new Set();
|
|
143
|
-
for (let row = 0; row < map.height; row++)
|
|
144
|
-
for (let col = rect.left; col < rect.right; col++)
|
|
145
|
-
positions.add(map.map[row * map.width + col]);
|
|
146
|
-
for (const offset of positions) {
|
|
147
|
-
const pos = rect.tableStart + offset, cell = tr.doc.nodeAt(pos);
|
|
148
|
-
tr.setNodeMarkup(pos, undefined, { ...cell.attrs, alignment });
|
|
149
|
-
}
|
|
150
|
-
view.dispatch(tr);
|
|
151
|
-
return true;
|
|
152
|
-
}
|
|
153
|
-
if (command === 'addRowBefore' || command === 'addRowAfter') {
|
|
154
|
-
if (!isInTable(view.state))
|
|
155
|
-
return false;
|
|
156
|
-
const { tableStart } = selectedRect(view.state);
|
|
157
|
-
const add = command === 'addRowBefore' ? addRowBefore : addRowAfter;
|
|
158
|
-
return add(view.state, (tr) => {
|
|
159
|
-
// GFM keeps alignment once per column, so a new row's cells take the
|
|
160
|
-
// header's; otherwise they read back aligned and the edit is refused.
|
|
161
|
-
const table = tr.doc.nodeAt(tableStart - 1);
|
|
162
|
-
const map = TableMap.get(table);
|
|
163
|
-
for (let row = 1; row < map.height; row++)
|
|
164
|
-
for (let col = 0; col < map.width; col++) {
|
|
165
|
-
const offset = map.map[row * map.width + col];
|
|
166
|
-
const cell = table.nodeAt(offset);
|
|
167
|
-
const { alignment } = table.nodeAt(map.map[col]).attrs;
|
|
168
|
-
if (cell.attrs.alignment !== alignment)
|
|
169
|
-
tr.setNodeMarkup(tableStart + offset, undefined, {
|
|
170
|
-
...cell.attrs,
|
|
171
|
-
alignment,
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
view.dispatch(tr);
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
const actions = {
|
|
178
|
-
addColumnBefore,
|
|
179
|
-
addColumnAfter,
|
|
180
|
-
deleteRow,
|
|
181
|
-
deleteColumn,
|
|
182
|
-
deleteTable,
|
|
183
|
-
};
|
|
184
|
-
return actions[command](view.state, view.dispatch);
|
|
185
|
-
}
|
|
186
|
-
export function dispatchTableOperation(view, tr) {
|
|
187
|
-
view.dispatch(closeHistory(tr).scrollIntoView());
|
|
188
|
-
view.dispatch(closeHistory(view.state.tr).setMeta('addToHistory', false));
|
|
189
|
-
}
|
|
190
|
-
export function configureTableMovement(ctx, canEdit) {
|
|
191
|
-
const commands = ctx.get(commandsCtx);
|
|
192
|
-
for (const [key, rowMovement] of [
|
|
193
|
-
[moveRowCommand.key, true],
|
|
194
|
-
[moveColCommand.key, false],
|
|
195
|
-
]) {
|
|
196
|
-
commands.remove(key);
|
|
197
|
-
commands.create(key, (options = {}) => () => {
|
|
198
|
-
const view = ctx.get(editorViewCtx);
|
|
199
|
-
if (!canEdit() ||
|
|
200
|
-
!view.editable ||
|
|
201
|
-
view.composing ||
|
|
202
|
-
!isInTable(view.state))
|
|
203
|
-
return false;
|
|
204
|
-
const rect = selectedRect(view.state);
|
|
205
|
-
const from = options.from ?? 0, to = options.to ?? 0;
|
|
206
|
-
const length = rowMovement ? rect.map.height : rect.map.width;
|
|
207
|
-
if (!editableTable(rect.table) ||
|
|
208
|
-
(options.pos != null && options.pos !== rect.tableStart) ||
|
|
209
|
-
!Number.isInteger(from) ||
|
|
210
|
-
!Number.isInteger(to) ||
|
|
211
|
-
from < 0 ||
|
|
212
|
-
to < 0 ||
|
|
213
|
-
from >= length ||
|
|
214
|
-
to >= length ||
|
|
215
|
-
from === to ||
|
|
216
|
-
(rowMovement && (from === 0 || to === 0)))
|
|
217
|
-
return false;
|
|
218
|
-
const rows = [];
|
|
219
|
-
rect.table.forEach((row) => rows.push(row));
|
|
220
|
-
if (rowMovement) {
|
|
221
|
-
const moved = rows.splice(from, 1)[0];
|
|
222
|
-
rows.splice(to, 0, moved);
|
|
223
|
-
}
|
|
224
|
-
else {
|
|
225
|
-
for (let index = 0; index < rows.length; index++) {
|
|
226
|
-
const row = rows[index], cells = [];
|
|
227
|
-
row.forEach((cell) => cells.push(cell));
|
|
228
|
-
cells.splice(to, 0, cells.splice(from, 1)[0]);
|
|
229
|
-
rows[index] = row.copy(Fragment.fromArray(cells));
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
const table = rect.table.copy(Fragment.fromArray(rows));
|
|
233
|
-
const tr = view.state.tr.replaceWith(rect.tableStart - 1, rect.tableStart - 1 + rect.table.nodeSize, table);
|
|
234
|
-
selectTableRectangle(tr, rect.tableStart, table, rowMovement ? to : 0, rowMovement ? 0 : to, rowMovement ? to + 1 : rect.map.height, rowMovement ? rect.map.width : to + 1);
|
|
235
|
-
dispatchTableOperation(view, tr);
|
|
236
|
-
return true;
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
export function editableTable(table) {
|
|
241
|
-
const map = TableMap.get(table);
|
|
242
|
-
if (map.problems?.length || map.width > 100 || map.height > 100)
|
|
243
|
-
return false;
|
|
244
|
-
let valid = table.firstChild?.type.name === 'table_header_row';
|
|
245
|
-
table.forEach((row, _offset, index) => {
|
|
246
|
-
valid &&= row.type.name === (index ? 'table_row' : 'table_header_row');
|
|
247
|
-
valid &&= row.childCount === map.width;
|
|
248
|
-
row.forEach((cell) => {
|
|
249
|
-
valid &&= cell.attrs.colspan === 1 && cell.attrs.rowspan === 1;
|
|
250
|
-
});
|
|
251
|
-
});
|
|
252
|
-
return Boolean(valid);
|
|
253
|
-
}
|
|
254
|
-
function refineTable(view, command, options) {
|
|
255
|
-
if (!isInTable(view.state))
|
|
256
|
-
return false;
|
|
257
|
-
const rect = selectedRect(view.state);
|
|
258
|
-
if (!editableTable(rect.table))
|
|
259
|
-
return false;
|
|
260
|
-
const rows = [];
|
|
261
|
-
rect.table.forEach((row) => rows.push(row));
|
|
262
|
-
let top = rect.top, bottom = rect.bottom, left = rect.left, right = rect.right;
|
|
263
|
-
if (command === 'sortRows') {
|
|
264
|
-
const column = options?.column ?? rect.left;
|
|
265
|
-
if (!Number.isInteger(column) || column < 0 || column >= rect.map.width)
|
|
266
|
-
throw new RangeError('Sort column must identify an existing table column');
|
|
267
|
-
const order = options?.order ?? 'ascending';
|
|
268
|
-
const comparison = options?.comparison ?? 'text';
|
|
269
|
-
if (!['ascending', 'descending'].includes(order))
|
|
270
|
-
throw new RangeError('Sort order must be ascending or descending');
|
|
271
|
-
if (!['text', 'number'].includes(comparison))
|
|
272
|
-
throw new RangeError('Sort comparison must be text or number');
|
|
273
|
-
const body = rows.slice(1).map((row, index) => ({
|
|
274
|
-
row,
|
|
275
|
-
index,
|
|
276
|
-
key: clipboardText(row.child(column).content),
|
|
277
|
-
}));
|
|
278
|
-
if (comparison === 'number' &&
|
|
279
|
-
body.some(({ key }) => {
|
|
280
|
-
const value = key.trim();
|
|
281
|
-
return value !== '' && decimalNumber(value) === undefined;
|
|
282
|
-
}))
|
|
283
|
-
throw new RangeError('Numeric sorting requires finite decimal values or blank cells');
|
|
284
|
-
body.sort((a, b) => compareCells(a.key, b.key, comparison, order) || a.index - b.index);
|
|
285
|
-
if (body.every(({ row }, index) => row === rows[index + 1]))
|
|
286
|
-
return false;
|
|
287
|
-
const activeIndex = top - 1;
|
|
288
|
-
rows.splice(1, rows.length - 1, ...body.map(({ row }) => row));
|
|
289
|
-
top =
|
|
290
|
-
top === 0 ? 0 : body.findIndex(({ index }) => index === activeIndex) + 1;
|
|
291
|
-
bottom = top + 1;
|
|
292
|
-
}
|
|
293
|
-
else if (command === 'moveRowUp' || command === 'moveRowDown') {
|
|
294
|
-
const up = command === 'moveRowUp';
|
|
295
|
-
if (top === 0 || (up ? top === 1 : bottom === rows.length))
|
|
296
|
-
return false;
|
|
297
|
-
const moved = rows.splice(top, bottom - top);
|
|
298
|
-
const destination = top + (up ? -1 : 1);
|
|
299
|
-
rows.splice(destination, 0, ...moved);
|
|
300
|
-
top = destination;
|
|
301
|
-
bottom += up ? -1 : 1;
|
|
302
|
-
}
|
|
303
|
-
else {
|
|
304
|
-
const backward = command === 'moveColumnLeft';
|
|
305
|
-
if (backward ? left === 0 : right === rect.map.width)
|
|
306
|
-
return false;
|
|
307
|
-
for (let index = 0; index < rows.length; index++) {
|
|
308
|
-
const row = rows[index];
|
|
309
|
-
const cells = [];
|
|
310
|
-
row.forEach((cell) => cells.push(cell));
|
|
311
|
-
const moved = cells.splice(left, right - left);
|
|
312
|
-
cells.splice(left + (backward ? -1 : 1), 0, ...moved);
|
|
313
|
-
rows[index] = row.copy(Fragment.fromArray(cells));
|
|
314
|
-
}
|
|
315
|
-
left += backward ? -1 : 1;
|
|
316
|
-
right += backward ? -1 : 1;
|
|
317
|
-
}
|
|
318
|
-
const table = rect.table.copy(Fragment.fromArray(rows));
|
|
319
|
-
const tr = view.state.tr.replaceWith(rect.tableStart - 1, rect.tableStart - 1 + rect.table.nodeSize, table);
|
|
320
|
-
selectTableRectangle(tr, rect.tableStart, table, top, left, bottom, right);
|
|
321
|
-
dispatchTableOperation(view, tr);
|
|
322
|
-
return true;
|
|
323
|
-
}
|
|
324
|
-
export function selectTableRectangle(tr, tableStart, table, top, left, bottom, right) {
|
|
325
|
-
const map = TableMap.get(table);
|
|
326
|
-
tr.setSelection(CellSelection.create(tr.doc, tableStart + map.map[top * map.width + left], tableStart + map.map[(bottom - 1) * map.width + right - 1]));
|
|
327
|
-
}
|
|
328
|
-
function compareCells(a, b, comparison, order) {
|
|
329
|
-
const x = a.trim(), y = b.trim();
|
|
330
|
-
if (!x || !y)
|
|
331
|
-
return x === y ? 0 : x ? -1 : 1;
|
|
332
|
-
const direction = order === 'ascending' ? 1 : -1;
|
|
333
|
-
const text = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
|
|
334
|
-
if (comparison === 'text')
|
|
335
|
-
return direction * text(a, b);
|
|
336
|
-
const nx = decimalNumber(x), ny = decimalNumber(y);
|
|
337
|
-
return direction * (nx < ny ? -1 : nx > ny ? 1 : 0);
|
|
338
|
-
}
|
|
339
|
-
function decimalNumber(value) {
|
|
340
|
-
return /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/.test(value) &&
|
|
341
|
-
Number.isFinite(Number(value))
|
|
342
|
-
? Number(value)
|
|
343
|
-
: undefined;
|
|
344
|
-
}
|
package/dist/tasks.d.ts
DELETED
package/dist/tasks.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { commandsCtx, editorViewCtx } from '@milkdown/kit/core';
|
|
2
|
-
import { wrapInBulletListCommand } from '@milkdown/kit/preset/commonmark';
|
|
3
|
-
import { Plugin, PluginKey } from '@milkdown/kit/prose/state';
|
|
4
|
-
import { $prose } from '@milkdown/kit/utils';
|
|
5
|
-
// A click on the task marker lands on the <li> itself, since the marker is a
|
|
6
|
-
// pseudo-element; clicks inside the item's text land on its children.
|
|
7
|
-
export const taskListPlugin = $prose(() => new Plugin({
|
|
8
|
-
key: new PluginKey('taskToggle'),
|
|
9
|
-
props: {
|
|
10
|
-
handleClickOn(view, _pos, node, nodePos, event) {
|
|
11
|
-
if (!view.editable)
|
|
12
|
-
return false;
|
|
13
|
-
if (node.type.name !== 'list_item' || node.attrs.checked == null)
|
|
14
|
-
return false;
|
|
15
|
-
const target = event.target;
|
|
16
|
-
if (!target.matches('li[data-item-type="task"]'))
|
|
17
|
-
return false;
|
|
18
|
-
view.dispatch(view.state.tr.setNodeMarkup(nodePos, undefined, {
|
|
19
|
-
...node.attrs,
|
|
20
|
-
checked: !node.attrs.checked,
|
|
21
|
-
}));
|
|
22
|
-
return true;
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
}));
|
|
26
|
-
function listItemsInSelection(view) {
|
|
27
|
-
const { from, to } = view.state.selection;
|
|
28
|
-
const items = [];
|
|
29
|
-
view.state.doc.nodesBetween(from, to, (node, pos) => {
|
|
30
|
-
if (node.type.name === 'list_item')
|
|
31
|
-
items.push({ pos, node });
|
|
32
|
-
});
|
|
33
|
-
return items;
|
|
34
|
-
}
|
|
35
|
-
export function toggleTaskList(ctx) {
|
|
36
|
-
const view = ctx.get(editorViewCtx);
|
|
37
|
-
let items = listItemsInSelection(view);
|
|
38
|
-
if (items.length === 0) {
|
|
39
|
-
ctx.get(commandsCtx).call(wrapInBulletListCommand.key);
|
|
40
|
-
items = listItemsInSelection(view);
|
|
41
|
-
}
|
|
42
|
-
const allTasks = items.every(({ node }) => node.attrs.checked != null);
|
|
43
|
-
let tr = view.state.tr;
|
|
44
|
-
for (const { pos, node } of items) {
|
|
45
|
-
tr = tr.setNodeMarkup(pos, undefined, {
|
|
46
|
-
...node.attrs,
|
|
47
|
-
checked: allTasks ? null : (node.attrs.checked ?? false),
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
view.dispatch(tr);
|
|
51
|
-
}
|
package/dist/text-ranges.d.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { Node as ProseNode } from '@milkdown/kit/prose/model';
|
|
2
|
-
import type { EditorView } from '@milkdown/kit/prose/view';
|
|
3
|
-
import { type TextRect } from './types.js';
|
|
4
|
-
export interface TextSpan {
|
|
5
|
-
from: number;
|
|
6
|
-
to: number;
|
|
7
|
-
start: number;
|
|
8
|
-
end: number;
|
|
9
|
-
kind: 'text' | 'break' | 'embed' | 'separator';
|
|
10
|
-
}
|
|
11
|
-
export interface TextProjection {
|
|
12
|
-
text: string;
|
|
13
|
-
spans: TextSpan[];
|
|
14
|
-
}
|
|
15
|
-
export declare function readableProjection(doc: ProseNode): TextProjection;
|
|
16
|
-
export declare function projectionPosition(projection: TextProjection, offset: number, side: -1 | 1): number;
|
|
17
|
-
export declare function projectionOffset(projection: TextProjection, position: number): number;
|
|
18
|
-
export declare function validateOffsets(text: string, from: number, to: number): void;
|
|
19
|
-
export declare function textRect(rect: Pick<TextRect, 'left' | 'top' | 'right' | 'bottom'>): TextRect;
|
|
20
|
-
export declare function formattedRects(view: EditorView, projection: TextProjection, from: number, to: number): TextRect[];
|
|
21
|
-
export declare function literalRangesRects(plain: HTMLTextAreaElement, ranges: readonly {
|
|
22
|
-
from: number;
|
|
23
|
-
to: number;
|
|
24
|
-
}[]): TextRect[][];
|
|
25
|
-
export declare function intersectsViewport(rect: Pick<TextRect, 'top' | 'right' | 'bottom' | 'left'>, viewport: TextRect): boolean;
|
|
26
|
-
export declare function literalVisibleRanges(plain: HTMLTextAreaElement, viewport: TextRect): {
|
|
27
|
-
from: number;
|
|
28
|
-
to: number;
|
|
29
|
-
}[];
|
package/dist/text-ranges.js
DELETED
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
import { InkKitError } from './types.js';
|
|
2
|
-
import { fileReference } from './linked-syntax.js';
|
|
3
|
-
import { imageBlockName } from './image-blocks.js';
|
|
4
|
-
export function readableProjection(doc) {
|
|
5
|
-
const result = { text: '', spans: [] };
|
|
6
|
-
let blocks = 0;
|
|
7
|
-
const append = (text, start, end, kind) => {
|
|
8
|
-
const from = result.text.length;
|
|
9
|
-
result.text += text;
|
|
10
|
-
result.spans.push({ from, to: result.text.length, start, end, kind });
|
|
11
|
-
};
|
|
12
|
-
const block = (start) => {
|
|
13
|
-
if (blocks++)
|
|
14
|
-
append('\n', result.spans.at(-1)?.end ?? start, start, 'separator');
|
|
15
|
-
};
|
|
16
|
-
doc.descendants((node, position) => {
|
|
17
|
-
const name = node.type.name;
|
|
18
|
-
if (name === 'comment_inline' ||
|
|
19
|
-
name === 'comment_block' ||
|
|
20
|
-
name === 'reference_definition')
|
|
21
|
-
return false;
|
|
22
|
-
if (name === 'inkkit_callout') {
|
|
23
|
-
block(position);
|
|
24
|
-
append(node.attrs.title ||
|
|
25
|
-
String(node.attrs.kind).replace(/^./, (value) => value.toUpperCase()), position, position + 1, 'embed');
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
|
-
if (name === imageBlockName) {
|
|
29
|
-
block(position);
|
|
30
|
-
append(fileReference(node).label || 'Image', position, position + node.nodeSize, 'embed');
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
if (node.isTextblock) {
|
|
34
|
-
block(position + 1);
|
|
35
|
-
if (!node.content.size)
|
|
36
|
-
append('', position + 1, position + 1, 'text');
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
39
|
-
if (node.isText) {
|
|
40
|
-
append(node.text ?? '', position, position + node.nodeSize, 'text');
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
if (name === 'hardbreak' || name === 'hard_break') {
|
|
44
|
-
append('\n', position, position + node.nodeSize, 'break');
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
if (name === 'image' ||
|
|
48
|
-
name === 'footnote_reference' ||
|
|
49
|
-
name === 'inkkit_wiki_link') {
|
|
50
|
-
append(name === 'image'
|
|
51
|
-
? fileReference(node).label || 'Image'
|
|
52
|
-
: name === 'inkkit_wiki_link'
|
|
53
|
-
? String(node.attrs.label || node.attrs.target || 'Link')
|
|
54
|
-
: `[${node.attrs.label}]`, position, position + node.nodeSize, 'embed');
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
return true;
|
|
58
|
-
});
|
|
59
|
-
return result;
|
|
60
|
-
}
|
|
61
|
-
export function projectionPosition(projection, offset, side) {
|
|
62
|
-
const spans = projection.spans;
|
|
63
|
-
const span = spans.find((span) => (offset > span.from && offset < span.to) ||
|
|
64
|
-
(side > 0 ? offset === span.from : offset === span.to)) ?? (side > 0 ? spans.at(-1) : spans[0]);
|
|
65
|
-
if (!span)
|
|
66
|
-
return 0;
|
|
67
|
-
if (span.kind === 'text')
|
|
68
|
-
return (span.start +
|
|
69
|
-
Math.max(0, Math.min(offset - span.from, span.to - span.from)));
|
|
70
|
-
return offset <= span.from ? span.start : span.end;
|
|
71
|
-
}
|
|
72
|
-
export function projectionOffset(projection, position) {
|
|
73
|
-
for (const span of projection.spans) {
|
|
74
|
-
if (position < span.start)
|
|
75
|
-
return span.from;
|
|
76
|
-
if (position <= span.end)
|
|
77
|
-
return span.kind === 'text'
|
|
78
|
-
? span.from + Math.max(0, position - span.start)
|
|
79
|
-
: position === span.start
|
|
80
|
-
? span.from
|
|
81
|
-
: span.to;
|
|
82
|
-
}
|
|
83
|
-
return projection.text.length;
|
|
84
|
-
}
|
|
85
|
-
export function validateOffsets(text, from, to) {
|
|
86
|
-
const split = (offset) => offset > 0 &&
|
|
87
|
-
offset < text.length &&
|
|
88
|
-
/[\uD800-\uDBFF]/.test(text[offset - 1]) &&
|
|
89
|
-
/[\uDC00-\uDFFF]/.test(text[offset]);
|
|
90
|
-
if (!Number.isInteger(from) ||
|
|
91
|
-
!Number.isInteger(to) ||
|
|
92
|
-
from < 0 ||
|
|
93
|
-
to < from ||
|
|
94
|
-
to > text.length ||
|
|
95
|
-
split(from) ||
|
|
96
|
-
split(to))
|
|
97
|
-
throw new InkKitError('invalid-range', 'Range must use valid UTF-16 boundaries in the text snapshot');
|
|
98
|
-
}
|
|
99
|
-
export function textRect(rect) {
|
|
100
|
-
return {
|
|
101
|
-
left: rect.left,
|
|
102
|
-
top: rect.top,
|
|
103
|
-
right: rect.right,
|
|
104
|
-
bottom: rect.bottom,
|
|
105
|
-
width: Math.max(0, rect.right - rect.left),
|
|
106
|
-
height: Math.max(0, rect.bottom - rect.top),
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
export function formattedRects(view, projection, from, to) {
|
|
110
|
-
if (from === to) {
|
|
111
|
-
const position = projectionPosition(projection, from, 1);
|
|
112
|
-
const dom = view.domAtPos(position);
|
|
113
|
-
const element = dom.node.nodeType === 1 ? dom.node : dom.node.parentElement;
|
|
114
|
-
if (!element?.getClientRects().length)
|
|
115
|
-
return [];
|
|
116
|
-
return [textRect(view.coordsAtPos(position))];
|
|
117
|
-
}
|
|
118
|
-
const rects = [];
|
|
119
|
-
let low = 0;
|
|
120
|
-
let high = projection.spans.length;
|
|
121
|
-
while (low < high) {
|
|
122
|
-
const middle = (low + high) >>> 1;
|
|
123
|
-
if (projection.spans[middle].to <= from)
|
|
124
|
-
low = middle + 1;
|
|
125
|
-
else
|
|
126
|
-
high = middle;
|
|
127
|
-
}
|
|
128
|
-
for (let index = low; index < projection.spans.length; index++) {
|
|
129
|
-
const span = projection.spans[index];
|
|
130
|
-
if (span.from >= to)
|
|
131
|
-
break;
|
|
132
|
-
if (span.kind === 'separator')
|
|
133
|
-
continue;
|
|
134
|
-
if (span.kind === 'embed' || span.kind === 'break') {
|
|
135
|
-
const node = view.nodeDOM(span.start);
|
|
136
|
-
if (node instanceof Element) {
|
|
137
|
-
// A standalone image's node is its full-width row; the card is what shows.
|
|
138
|
-
const label = node.matches('.inkkit-callout')
|
|
139
|
-
? (node.querySelector(':scope > .inkkit-callout-header > .inkkit-callout-title') ?? node)
|
|
140
|
-
: node.matches('.inkkit-image-block')
|
|
141
|
-
? (node.firstElementChild ?? node)
|
|
142
|
-
: node;
|
|
143
|
-
rects.push(...Array.from(label.getClientRects(), textRect));
|
|
144
|
-
}
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
const start = view.domAtPos(span.start + Math.max(0, from - span.from), 1);
|
|
148
|
-
const end = view.domAtPos(span.start + Math.min(span.to - span.from, to - span.from), -1);
|
|
149
|
-
const range = view.dom.ownerDocument.createRange();
|
|
150
|
-
range.setStart(start.node, start.offset);
|
|
151
|
-
range.setEnd(end.node, end.offset);
|
|
152
|
-
rects.push(...Array.from(range.getClientRects(), textRect));
|
|
153
|
-
}
|
|
154
|
-
return rects.filter((rect) => rect.height > 0 && rect.width >= 0);
|
|
155
|
-
}
|
|
156
|
-
function withLiteralLayout(plain, measure) {
|
|
157
|
-
if (!plain.clientWidth || !plain.clientHeight)
|
|
158
|
-
return undefined;
|
|
159
|
-
const document = plain.ownerDocument;
|
|
160
|
-
const style = document.defaultView.getComputedStyle(plain);
|
|
161
|
-
const mirror = document.createElement('div');
|
|
162
|
-
for (const property of [
|
|
163
|
-
'font',
|
|
164
|
-
'font-family',
|
|
165
|
-
'font-size',
|
|
166
|
-
'font-weight',
|
|
167
|
-
'font-style',
|
|
168
|
-
'font-stretch',
|
|
169
|
-
'font-variant',
|
|
170
|
-
'line-height',
|
|
171
|
-
'letter-spacing',
|
|
172
|
-
'word-spacing',
|
|
173
|
-
'tab-size',
|
|
174
|
-
'padding',
|
|
175
|
-
'text-indent',
|
|
176
|
-
'text-transform',
|
|
177
|
-
'direction',
|
|
178
|
-
'word-break',
|
|
179
|
-
])
|
|
180
|
-
mirror.style.setProperty(property, style.getPropertyValue(property));
|
|
181
|
-
const origin = plain.getBoundingClientRect();
|
|
182
|
-
Object.assign(mirror.style, {
|
|
183
|
-
position: 'fixed',
|
|
184
|
-
visibility: 'hidden',
|
|
185
|
-
pointerEvents: 'none',
|
|
186
|
-
left: `${origin.left + plain.clientLeft - plain.scrollLeft}px`,
|
|
187
|
-
top: `${origin.top + plain.clientTop - plain.scrollTop}px`,
|
|
188
|
-
width: `${plain.clientWidth}px`,
|
|
189
|
-
boxSizing: 'border-box',
|
|
190
|
-
whiteSpace: plain.wrap === 'off' ? 'pre' : 'pre-wrap',
|
|
191
|
-
overflowWrap: plain.wrap === 'off' ? 'normal' : 'break-word',
|
|
192
|
-
});
|
|
193
|
-
mirror.setAttribute('aria-hidden', 'true');
|
|
194
|
-
const text = document.createTextNode(plain.value + '\u200b');
|
|
195
|
-
mirror.append(text);
|
|
196
|
-
document.body.append(mirror);
|
|
197
|
-
try {
|
|
198
|
-
return measure(text);
|
|
199
|
-
}
|
|
200
|
-
finally {
|
|
201
|
-
mirror.remove();
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
export function literalRangesRects(plain, ranges) {
|
|
205
|
-
return (withLiteralLayout(plain, (text) => {
|
|
206
|
-
const range = plain.ownerDocument.createRange();
|
|
207
|
-
return ranges.map(({ from, to }) => {
|
|
208
|
-
range.setStart(text, from);
|
|
209
|
-
range.setEnd(text, from === to ? Math.min(to + 1, text.length) : to);
|
|
210
|
-
return Array.from(range.getClientRects(), (rect) => textRect({
|
|
211
|
-
left: rect.left,
|
|
212
|
-
right: from === to ? rect.left : rect.right,
|
|
213
|
-
top: rect.top,
|
|
214
|
-
bottom: rect.bottom,
|
|
215
|
-
}));
|
|
216
|
-
});
|
|
217
|
-
}) ?? ranges.map(() => []));
|
|
218
|
-
}
|
|
219
|
-
export function intersectsViewport(rect, viewport) {
|
|
220
|
-
return (viewport.width > 0 &&
|
|
221
|
-
viewport.height > 0 &&
|
|
222
|
-
rect.bottom > viewport.top &&
|
|
223
|
-
rect.top < viewport.bottom &&
|
|
224
|
-
rect.right >= viewport.left &&
|
|
225
|
-
rect.left < viewport.right);
|
|
226
|
-
}
|
|
227
|
-
export function literalVisibleRanges(plain, viewport) {
|
|
228
|
-
return (withLiteralLayout(plain, (text) => {
|
|
229
|
-
const range = plain.ownerDocument.createRange();
|
|
230
|
-
const ranges = [];
|
|
231
|
-
const visible = (from, to) => {
|
|
232
|
-
range.setStart(text, from);
|
|
233
|
-
range.setEnd(text, to);
|
|
234
|
-
return Array.from(range.getClientRects()).some((rect) => intersectsViewport(rect, viewport));
|
|
235
|
-
};
|
|
236
|
-
for (let start = 0; start < plain.value.length;) {
|
|
237
|
-
const newline = plain.value.indexOf('\n', start);
|
|
238
|
-
const end = newline < 0 ? plain.value.length : newline + 1;
|
|
239
|
-
if (visible(start, end)) {
|
|
240
|
-
for (let from = start; from < end;) {
|
|
241
|
-
const to = from + (plain.value.codePointAt(from) > 0xffff ? 2 : 1);
|
|
242
|
-
if (visible(from, to)) {
|
|
243
|
-
const previous = ranges.at(-1);
|
|
244
|
-
if (previous?.to === from)
|
|
245
|
-
previous.to = to;
|
|
246
|
-
else
|
|
247
|
-
ranges.push({ from, to });
|
|
248
|
-
}
|
|
249
|
-
from = to;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
start = end;
|
|
253
|
-
}
|
|
254
|
-
return ranges;
|
|
255
|
-
}) ?? []);
|
|
256
|
-
}
|