@bendyline/squisq-editor-react 2.9.0 → 2.10.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.md +1 -0
- package/dist/{chunk-OWOKKZAU.js → chunk-IRPOMTYK.js} +4 -0
- package/dist/{chunk-V3J5S7X6.js → chunk-JNJ7XO5L.js} +617 -99
- package/dist/{chunk-SAYCG257.js → chunk-JYPLPGYJ.js} +1 -1
- package/dist/chunk-SAKLIEOX.js +144 -0
- package/dist/{chunk-TLRB3IQC.js → chunk-TCLNRATG.js} +32 -2
- package/dist/{chunk-53PXOIMU.js → chunk-TQPZ6VVM.js} +4445 -2760
- package/dist/{chunk-AZ5ME4XG.js → chunk-WCGDDZB6.js} +3 -1
- package/dist/{chunk-IQFPX2CE.js → chunk-ZZTB6BEQ.js} +1 -1
- package/dist/index.d.ts +149 -6
- package/dist/index.js +39 -9
- package/dist/json-editor/index.js +2 -2
- package/dist/proofing/index.d.ts +32 -0
- package/dist/proofing/index.js +10 -0
- package/dist/recorder/index.d.ts +2 -2
- package/dist/recorder/index.js +3 -3
- package/dist/{recorder-DFP0Dw4v.d.ts → recorder-GrEh4xE8.d.ts} +67 -7
- package/dist/shell/index.d.ts +3 -1
- package/dist/shell/index.js +5 -5
- package/dist/{shell-Bv6neeA6.d.ts → shell-Dlh-mkn9.d.ts} +59 -2
- package/dist/styles/index.css +412 -14
- package/dist/teleprompter/index.d.ts +2 -2
- package/dist/teleprompter/index.js +2 -2
- package/dist/types-B_aHRuSc.d.ts +156 -0
- package/dist/{useNarrationStage-Bk3mdW75.d.ts → useNarrationStage-B6r9Zlq-.d.ts} +11 -1
- package/package.json +16 -5
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// src/proofing/harperProvider.ts
|
|
2
|
+
import {
|
|
3
|
+
categorizeLintKind
|
|
4
|
+
} from "@bendyline/squisq/proof";
|
|
5
|
+
var SUGGESTION_KINDS = ["replace", "remove", "insertAfter"];
|
|
6
|
+
var MAX_IGNORE_ROUNDS = 5;
|
|
7
|
+
function createHarperProofingProvider(config = {}) {
|
|
8
|
+
let enginePromise = null;
|
|
9
|
+
let lastPass = null;
|
|
10
|
+
let disposed = false;
|
|
11
|
+
const words = new Set(config.initialWords ?? []);
|
|
12
|
+
const load = async () => {
|
|
13
|
+
const harper = await import("harper.js");
|
|
14
|
+
let binary = config.binary;
|
|
15
|
+
if (binary === void 0) {
|
|
16
|
+
if (config.wasmUrl) {
|
|
17
|
+
const absolute = typeof location !== "undefined" ? new URL(config.wasmUrl, location.href).toString() : config.wasmUrl;
|
|
18
|
+
binary = harper.createBinaryModuleFromUrl(absolute);
|
|
19
|
+
} else {
|
|
20
|
+
binary = (await import("harper.js/binary")).binary;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const dialect = harper.Dialect[config.dialect ?? "American"];
|
|
24
|
+
const init = { binary, dialect };
|
|
25
|
+
const linter = typeof Worker !== "undefined" ? new harper.WorkerLinter(init) : new harper.LocalLinter(init);
|
|
26
|
+
await linter.setup();
|
|
27
|
+
if (words.size > 0) await linter.importWords([...words]);
|
|
28
|
+
return { harper, linter };
|
|
29
|
+
};
|
|
30
|
+
const ensure = () => {
|
|
31
|
+
if (disposed) return Promise.reject(new Error("ProofingProvider has been disposed"));
|
|
32
|
+
if (!enginePromise) {
|
|
33
|
+
enginePromise = load().catch((err) => {
|
|
34
|
+
enginePromise = null;
|
|
35
|
+
throw err;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return enginePromise;
|
|
39
|
+
};
|
|
40
|
+
const toFinding = (lint, id, text) => {
|
|
41
|
+
const span = lint.span();
|
|
42
|
+
const kind = lint.lint_kind();
|
|
43
|
+
return {
|
|
44
|
+
id,
|
|
45
|
+
start: span.start,
|
|
46
|
+
end: span.end,
|
|
47
|
+
category: categorizeLintKind(kind),
|
|
48
|
+
kind,
|
|
49
|
+
message: lint.message(),
|
|
50
|
+
originalText: text.slice(span.start, span.end),
|
|
51
|
+
suggestions: lint.suggestions().map((suggestion) => ({
|
|
52
|
+
text: suggestion.get_replacement_text(),
|
|
53
|
+
kind: SUGGESTION_KINDS[suggestion.kind()] ?? "replace"
|
|
54
|
+
}))
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
let passCounter = 0;
|
|
58
|
+
return {
|
|
59
|
+
// App-level additions only persist if the host gave us somewhere to
|
|
60
|
+
// put them; without a callback the editor hides that menu item.
|
|
61
|
+
hasAppDictionary: config.onDictionaryWord != null,
|
|
62
|
+
async setup() {
|
|
63
|
+
await ensure();
|
|
64
|
+
},
|
|
65
|
+
async lint(text, options) {
|
|
66
|
+
const { linter } = await ensure();
|
|
67
|
+
const language = options?.language ?? "plaintext";
|
|
68
|
+
const lints = await linter.lint(text, { language });
|
|
69
|
+
passCounter += 1;
|
|
70
|
+
const byId = /* @__PURE__ */ new Map();
|
|
71
|
+
const findings = lints.map((lint, index) => {
|
|
72
|
+
const id = `${passCounter}:${index}`;
|
|
73
|
+
const finding = toFinding(lint, id, text);
|
|
74
|
+
byId.set(id, { lint, start: finding.start, end: finding.end });
|
|
75
|
+
return finding;
|
|
76
|
+
});
|
|
77
|
+
lastPass = { source: text, language, byId };
|
|
78
|
+
return findings;
|
|
79
|
+
},
|
|
80
|
+
async ignoreFinding(findingId) {
|
|
81
|
+
const { linter } = await ensure();
|
|
82
|
+
const pass = lastPass;
|
|
83
|
+
const entry = pass?.byId.get(findingId);
|
|
84
|
+
if (!pass || !entry) {
|
|
85
|
+
console.warn("squisq proofing: ignoreFinding called with a stale finding id", findingId);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
let lint = entry.lint;
|
|
89
|
+
for (let round = 0; round < MAX_IGNORE_ROUNDS && lint; round += 1) {
|
|
90
|
+
await linter.ignoreLint(pass.source, lint);
|
|
91
|
+
const relint = await linter.lint(pass.source, { language: pass.language });
|
|
92
|
+
lint = relint.find(
|
|
93
|
+
(candidate) => candidate.span().start === entry.start && candidate.span().end === entry.end
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
async addWord(word) {
|
|
98
|
+
const { linter } = await ensure();
|
|
99
|
+
words.add(word);
|
|
100
|
+
await linter.importWords([...words]);
|
|
101
|
+
config.onDictionaryWord?.(word);
|
|
102
|
+
},
|
|
103
|
+
async addWords(list) {
|
|
104
|
+
if (list.length === 0) return;
|
|
105
|
+
const { linter } = await ensure();
|
|
106
|
+
for (const word of list) words.add(word);
|
|
107
|
+
await linter.importWords([...words]);
|
|
108
|
+
},
|
|
109
|
+
async exportIgnored() {
|
|
110
|
+
const { linter } = await ensure();
|
|
111
|
+
return linter.exportIgnoredLints();
|
|
112
|
+
},
|
|
113
|
+
async clearIgnored() {
|
|
114
|
+
const { linter } = await ensure();
|
|
115
|
+
await linter.clearIgnoredLints();
|
|
116
|
+
},
|
|
117
|
+
async importIgnored(json) {
|
|
118
|
+
const { linter } = await ensure();
|
|
119
|
+
await linter.importIgnoredLints(json);
|
|
120
|
+
},
|
|
121
|
+
async setDialect(dialect) {
|
|
122
|
+
const { harper, linter } = await ensure();
|
|
123
|
+
await linter.setDialect(harper.Dialect[dialect]);
|
|
124
|
+
},
|
|
125
|
+
dispose() {
|
|
126
|
+
if (disposed) return;
|
|
127
|
+
disposed = true;
|
|
128
|
+
lastPass = null;
|
|
129
|
+
const pending = enginePromise;
|
|
130
|
+
enginePromise = null;
|
|
131
|
+
void pending?.then((handle) => handle.linter.dispose()).catch(() => {
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/proofing/index.ts
|
|
138
|
+
import { PROOF_DIALECTS, PROOF_FRONTMATTER_KEYS } from "@bendyline/squisq/proof";
|
|
139
|
+
|
|
140
|
+
export {
|
|
141
|
+
createHarperProofingProvider,
|
|
142
|
+
PROOF_DIALECTS,
|
|
143
|
+
PROOF_FRONTMATTER_KEYS
|
|
144
|
+
};
|
|
@@ -20,8 +20,9 @@ var RE_MENTION = /@\[([^\]]+?)\]\(([a-z][a-z0-9+.-]*)\\?:([^)\s]+)\)/gi;
|
|
|
20
20
|
var RE_MENTION_TAG = /<span\b[^>]*?\bdata-mention\b[^>]*?>(?:<[^>]+>)*([^<]*)<\/span>/gi;
|
|
21
21
|
var RE_ICON_MD = /\{\[([a-zA-Z0-9_:-]+)\]\}/g;
|
|
22
22
|
var RE_ICON_TAG = /<i\b[^>]*?\bdata-icon="([^"]*)"[^>]*?><\/i>/gi;
|
|
23
|
-
var RE_MARK_TAG = /<(strong|b|em|i|s|del)>(.*?)<\/\1>/gs;
|
|
23
|
+
var RE_MARK_TAG = /<(strong|b|em|i|s|del|sup|sub)>(.*?)<\/\1>/gs;
|
|
24
24
|
var RE_CODE_TAG = /<code>(.*?)<\/code>/g;
|
|
25
|
+
var RE_VERT_ALIGN_TAG = /<(sup|sub)>((?:(?!<\/?(?:sup|sub)>)[\s\S])*)<\/\1>/gi;
|
|
25
26
|
var RE_A_TAG = /<a\b([^>]*)>(.*?)<\/a>/g;
|
|
26
27
|
var RE_IMG_TAG = /<img\b([^>]*)>/g;
|
|
27
28
|
var RE_STRIP_TAGS = /<[^>]+>/g;
|
|
@@ -784,6 +785,10 @@ function inlineToHtml(text) {
|
|
|
784
785
|
RE_INLINE_CODE,
|
|
785
786
|
(_m, code) => stash(`<code>${escapeHtml(code)}</code>`)
|
|
786
787
|
);
|
|
788
|
+
staged = staged.replace(RE_VERT_ALIGN_TAG, (_m, tag, inner) => {
|
|
789
|
+
const name = tag.toLowerCase();
|
|
790
|
+
return stash(`<${name}>${inlineToHtml(inner)}</${name}>`);
|
|
791
|
+
});
|
|
787
792
|
staged = staged.replace(
|
|
788
793
|
RE_IMAGE,
|
|
789
794
|
(_m, alt, src) => stash(`<img alt="${escapeHtml(alt)}" src="${escapeHtml(src)}">`)
|
|
@@ -967,16 +972,39 @@ function markdownFromMarkTags(html) {
|
|
|
967
972
|
const trailing = convertedInner.match(/\s*$/)?.[0] ?? "";
|
|
968
973
|
const content = convertedInner.slice(leading.length, convertedInner.length - trailing.length);
|
|
969
974
|
if (!content) return convertedInner;
|
|
975
|
+
if (tag === "sup" || tag === "sub") {
|
|
976
|
+
return `${leading}<${tag}>${content}</${tag}>${trailing}`;
|
|
977
|
+
}
|
|
970
978
|
const delimiter = tag === "strong" || tag === "b" ? "**" : tag === "em" || tag === "i" ? "*" : "~~";
|
|
971
979
|
return `${leading}${delimiter}${content}${delimiter}${trailing}`;
|
|
972
980
|
});
|
|
973
981
|
}
|
|
982
|
+
var RawHtmlVault = class {
|
|
983
|
+
constructor() {
|
|
984
|
+
this.parts = [];
|
|
985
|
+
}
|
|
986
|
+
/** Replace a raw HTML string with a sentinel the tag-stripper won't match. */
|
|
987
|
+
protect(html) {
|
|
988
|
+
this.parts.push(html);
|
|
989
|
+
return `\0RAW${this.parts.length - 1}\0`;
|
|
990
|
+
}
|
|
991
|
+
/** Swap every sentinel back for its raw HTML. */
|
|
992
|
+
restore(text) {
|
|
993
|
+
let out = text;
|
|
994
|
+
for (let i = this.parts.length - 1; i >= 0; i--) {
|
|
995
|
+
out = out.split(`\0RAW${i}\0`).join(this.parts[i]);
|
|
996
|
+
}
|
|
997
|
+
return out;
|
|
998
|
+
}
|
|
999
|
+
};
|
|
974
1000
|
function htmlToInline(html) {
|
|
975
1001
|
let result = html;
|
|
1002
|
+
const vault = new RawHtmlVault();
|
|
976
1003
|
result = result.replace(/<br\s*\/?>/gi, " \n");
|
|
977
1004
|
result = escapeMarkdownTextNodes(result);
|
|
978
1005
|
result = result.replace(RE_ICON_TAG, (_m, token) => `{[${token}]}`);
|
|
979
1006
|
result = markdownFromMarkTags(result);
|
|
1007
|
+
result = result.replace(/<\/?(?:sup|sub)>/gi, (tag) => vault.protect(tag));
|
|
980
1008
|
result = result.replace(RE_CODE_TAG, "`$1`");
|
|
981
1009
|
result = result.replace(RE_MENTION_TAG, (match, _inner) => {
|
|
982
1010
|
const kind = /data-kind="([^"]*)"/i.exec(match)?.[1] ?? "";
|
|
@@ -996,9 +1024,11 @@ function htmlToInline(html) {
|
|
|
996
1024
|
const src = /\bsrc="([^"]*)"/i.exec(attrs)?.[1];
|
|
997
1025
|
if (!src) return match;
|
|
998
1026
|
const alt = /\balt="([^"]*)"/i.exec(attrs)?.[1] ?? "";
|
|
999
|
-
|
|
1027
|
+
const serialized = serializeImage(src, alt, attrs);
|
|
1028
|
+
return serialized.startsWith("<") ? vault.protect(serialized) : serialized;
|
|
1000
1029
|
});
|
|
1001
1030
|
result = result.replace(RE_STRIP_TAGS, "");
|
|
1031
|
+
result = vault.restore(result);
|
|
1002
1032
|
return restoreLeadingSpaces(unescapeHtml(result));
|
|
1003
1033
|
}
|
|
1004
1034
|
function preserveLeadingSpaces(html) {
|