@aicayzer/inkkit 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/source.js ADDED
@@ -0,0 +1,117 @@
1
+ import { literalCommentSpans } from './comments.js';
2
+ export const sourceAttribute = 'inkkitSource';
3
+ export function cleanSourceDoc(doc) {
4
+ return doc.attrs[sourceAttribute] == null
5
+ ? doc
6
+ : doc.type.create({ ...doc.attrs, [sourceAttribute]: null }, doc.content);
7
+ }
8
+ export function rawOffset(source, normalized) {
9
+ let position = 0, count = 0;
10
+ while (position < source.length && count < normalized) {
11
+ if (source[position] === '\r' && source[position + 1] === '\n')
12
+ position++;
13
+ position++;
14
+ count++;
15
+ }
16
+ return position;
17
+ }
18
+ export function normalizedOffset(source, raw) {
19
+ return source.slice(0, raw).replace(/\r\n?/g, '\n').length;
20
+ }
21
+ export function editedPlainSource(previous, value) {
22
+ const normalized = previous.replace(/\r\n?/g, '\n');
23
+ if (normalized === value)
24
+ return previous;
25
+ let prefix = 0, suffix = 0;
26
+ while (prefix < normalized.length &&
27
+ prefix < value.length &&
28
+ normalized[prefix] === value[prefix])
29
+ prefix++;
30
+ while (suffix < normalized.length - prefix &&
31
+ suffix < value.length - prefix &&
32
+ normalized[normalized.length - suffix - 1] ===
33
+ value[value.length - suffix - 1])
34
+ suffix++;
35
+ const ending = /\r\n|\r|\n/.exec(previous)?.[0] ?? '\n';
36
+ return (previous.slice(0, rawOffset(previous, prefix)) +
37
+ value
38
+ .slice(prefix, value.length - suffix)
39
+ .replace(/\r\n?/g, '\n')
40
+ .replaceAll('\n', ending) +
41
+ previous.slice(rawOffset(previous, normalized.length - suffix)));
42
+ }
43
+ export function sourceSelection(source, start, end) {
44
+ const from = rawOffset(source, start), to = rawOffset(source, end);
45
+ let shareable = '', cursor = from;
46
+ const bom = source.startsWith('\uFEFF') ? 1 : 0;
47
+ for (const parsed of literalCommentSpans(source.slice(bom))) {
48
+ const span = { start: parsed.start + bom, end: parsed.end + bom };
49
+ if (span.end <= from || span.start >= to)
50
+ continue;
51
+ if (span.start > cursor)
52
+ shareable += source.slice(cursor, Math.min(span.start, to));
53
+ cursor = Math.max(cursor, Math.min(span.end, to));
54
+ }
55
+ shareable += source.slice(cursor, to);
56
+ return { markdown: source.slice(from, to), shareable };
57
+ }
58
+ export function revealSourceCaret(plain) {
59
+ if (!plain.clientWidth || !plain.clientHeight)
60
+ return;
61
+ const document = plain.ownerDocument;
62
+ const style = document.defaultView.getComputedStyle(plain);
63
+ const mirror = document.createElement('div');
64
+ for (const property of [
65
+ 'font',
66
+ 'font-family',
67
+ 'font-size',
68
+ 'font-weight',
69
+ 'font-style',
70
+ 'font-stretch',
71
+ 'font-variant',
72
+ 'line-height',
73
+ 'letter-spacing',
74
+ 'word-spacing',
75
+ 'tab-size',
76
+ 'padding',
77
+ 'text-indent',
78
+ 'text-transform',
79
+ 'direction',
80
+ 'word-break',
81
+ ])
82
+ mirror.style.setProperty(property, style.getPropertyValue(property));
83
+ Object.assign(mirror.style, {
84
+ position: 'fixed',
85
+ visibility: 'hidden',
86
+ left: '-10000px',
87
+ top: '0',
88
+ width: `${plain.clientWidth}px`,
89
+ boxSizing: 'border-box',
90
+ whiteSpace: plain.wrap === 'off' ? 'pre' : 'pre-wrap',
91
+ overflowWrap: plain.wrap === 'off' ? 'normal' : 'break-word',
92
+ });
93
+ mirror.setAttribute('aria-hidden', 'true');
94
+ const caret = document.createElement('span');
95
+ caret.setAttribute('data-inkkit-source-caret', '');
96
+ caret.textContent = plain.value.slice(plain.selectionStart) || '\u200b';
97
+ mirror.append(document.createTextNode(plain.value.slice(0, plain.selectionStart)), caret);
98
+ document.body.append(mirror);
99
+ try {
100
+ // Textareas expose selection offsets but no caret geometry; matching their layout also accounts for wrapped lines.
101
+ const rect = caret.getClientRects()[0] ?? caret.getBoundingClientRect();
102
+ const top = rect.top - mirror.getBoundingClientRect().top;
103
+ const lineHeight = Math.max(rect.height, Number.parseFloat(style.lineHeight) || rect.height);
104
+ const insetTop = Number.parseFloat(style.paddingTop) || 0;
105
+ const insetBottom = Number.parseFloat(style.paddingBottom) || 0;
106
+ if (plain.selectionStart === 0)
107
+ plain.scrollTop = 0;
108
+ else if (top < plain.scrollTop + insetTop)
109
+ plain.scrollTop = Math.max(0, top - insetTop);
110
+ else if (top + lineHeight >
111
+ plain.scrollTop + plain.clientHeight - insetBottom)
112
+ plain.scrollTop = Math.max(0, top + lineHeight - plain.clientHeight + insetBottom);
113
+ }
114
+ finally {
115
+ mirror.remove();
116
+ }
117
+ }