@bendyline/squisq-editor-react 2.8.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/README.md +5 -0
- package/dist/{chunk-OWOKKZAU.js → chunk-IRPOMTYK.js} +4 -0
- package/dist/{chunk-V3J5S7X6.js → chunk-JNJ7XO5L.js} +617 -99
- package/dist/{chunk-YPRX32GY.js → chunk-JYPLPGYJ.js} +1 -1
- package/dist/chunk-SAKLIEOX.js +144 -0
- package/dist/{chunk-K2WJYVS4.js → chunk-TCLNRATG.js} +48 -13
- package/dist/{chunk-SUXRSZ4Y.js → chunk-TQPZ6VVM.js} +4749 -2783
- 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 +150 -7
- 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 +477 -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
|
+
};
|
|
@@ -10,6 +10,8 @@ var RE_BOLD_UNDER = /(?<![\p{L}\p{N}_])__(?![\s_])(.+?)(?<![\s_])__(?![\p{L}\p{N
|
|
|
10
10
|
var RE_ITALIC_STAR = /\*(?![\s*])(.+?)(?<![\s*])\*/g;
|
|
11
11
|
var RE_ITALIC_UNDER = /(?<![\p{L}\p{N}_])_(?![\s_])(.+?)(?<![\s_])_(?![\p{L}\p{N}_])/gu;
|
|
12
12
|
var RE_STRIKETHROUGH = /~~(.+?)~~/g;
|
|
13
|
+
var RE_LEGACY_BOLD_STAR = /\*\*(?![\s*])(.+?)(?<![\s*])([ \t]+)\*\*(?=$|[^\s*])/g;
|
|
14
|
+
var RE_LEGACY_ITALIC_STAR = /(?<!\*)\*(?![\s*])(.+?)(?<![\s*])([ \t]+)\*(?=$|[^\s*])/g;
|
|
13
15
|
var ESCAPABLE_MD_CHARS = ["*", "_", "~", "\\"];
|
|
14
16
|
var RE_MD_ESCAPE = /\\([*_~\\])/g;
|
|
15
17
|
var RE_INLINE_CODE = /`(.+?)`/g;
|
|
@@ -18,13 +20,9 @@ var RE_MENTION = /@\[([^\]]+?)\]\(([a-z][a-z0-9+.-]*)\\?:([^)\s]+)\)/gi;
|
|
|
18
20
|
var RE_MENTION_TAG = /<span\b[^>]*?\bdata-mention\b[^>]*?>(?:<[^>]+>)*([^<]*)<\/span>/gi;
|
|
19
21
|
var RE_ICON_MD = /\{\[([a-zA-Z0-9_:-]+)\]\}/g;
|
|
20
22
|
var RE_ICON_TAG = /<i\b[^>]*?\bdata-icon="([^"]*)"[^>]*?><\/i>/gi;
|
|
21
|
-
var
|
|
22
|
-
var RE_B_TAG = /<b>(.*?)<\/b>/g;
|
|
23
|
-
var RE_EM_TAG = /<em>(.*?)<\/em>/g;
|
|
24
|
-
var RE_I_TAG = /<i>(.*?)<\/i>/g;
|
|
25
|
-
var RE_S_TAG = /<s>(.*?)<\/s>/g;
|
|
26
|
-
var RE_DEL_TAG = /<del>(.*?)<\/del>/g;
|
|
23
|
+
var RE_MARK_TAG = /<(strong|b|em|i|s|del|sup|sub)>(.*?)<\/\1>/gs;
|
|
27
24
|
var RE_CODE_TAG = /<code>(.*?)<\/code>/g;
|
|
25
|
+
var RE_VERT_ALIGN_TAG = /<(sup|sub)>((?:(?!<\/?(?:sup|sub)>)[\s\S])*)<\/\1>/gi;
|
|
28
26
|
var RE_A_TAG = /<a\b([^>]*)>(.*?)<\/a>/g;
|
|
29
27
|
var RE_IMG_TAG = /<img\b([^>]*)>/g;
|
|
30
28
|
var RE_STRIP_TAGS = /<[^>]+>/g;
|
|
@@ -787,6 +785,10 @@ function inlineToHtml(text) {
|
|
|
787
785
|
RE_INLINE_CODE,
|
|
788
786
|
(_m, code) => stash(`<code>${escapeHtml(code)}</code>`)
|
|
789
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
|
+
});
|
|
790
792
|
staged = staged.replace(
|
|
791
793
|
RE_IMAGE,
|
|
792
794
|
(_m, alt, src) => stash(`<img alt="${escapeHtml(alt)}" src="${escapeHtml(src)}">`)
|
|
@@ -814,8 +816,10 @@ function inlineToHtml(text) {
|
|
|
814
816
|
RE_MD_ESCAPE,
|
|
815
817
|
(_m, ch) => `\0ESC${ESCAPABLE_MD_CHARS.indexOf(ch)}\0`
|
|
816
818
|
);
|
|
819
|
+
result = result.replace(RE_LEGACY_BOLD_STAR, "<strong>$1</strong>$2");
|
|
817
820
|
result = result.replace(RE_BOLD_STAR, "<strong>$1</strong>");
|
|
818
821
|
result = result.replace(RE_BOLD_UNDER, "<strong>$1</strong>");
|
|
822
|
+
result = result.replace(RE_LEGACY_ITALIC_STAR, "<em>$1</em>$2");
|
|
819
823
|
result = result.replace(RE_ITALIC_STAR, "<em>$1</em>");
|
|
820
824
|
result = result.replace(RE_ITALIC_UNDER, "<em>$1</em>");
|
|
821
825
|
result = result.replace(RE_STRIKETHROUGH, "<s>$1</s>");
|
|
@@ -961,17 +965,46 @@ function escapeMarkdownTextNodes(html) {
|
|
|
961
965
|
}
|
|
962
966
|
return out + escapeMarkdownText(html.slice(cursor));
|
|
963
967
|
}
|
|
968
|
+
function markdownFromMarkTags(html) {
|
|
969
|
+
return html.replace(RE_MARK_TAG, (_match, tag, inner) => {
|
|
970
|
+
const convertedInner = markdownFromMarkTags(inner);
|
|
971
|
+
const leading = convertedInner.match(/^\s*/)?.[0] ?? "";
|
|
972
|
+
const trailing = convertedInner.match(/\s*$/)?.[0] ?? "";
|
|
973
|
+
const content = convertedInner.slice(leading.length, convertedInner.length - trailing.length);
|
|
974
|
+
if (!content) return convertedInner;
|
|
975
|
+
if (tag === "sup" || tag === "sub") {
|
|
976
|
+
return `${leading}<${tag}>${content}</${tag}>${trailing}`;
|
|
977
|
+
}
|
|
978
|
+
const delimiter = tag === "strong" || tag === "b" ? "**" : tag === "em" || tag === "i" ? "*" : "~~";
|
|
979
|
+
return `${leading}${delimiter}${content}${delimiter}${trailing}`;
|
|
980
|
+
});
|
|
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
|
+
};
|
|
964
1000
|
function htmlToInline(html) {
|
|
965
1001
|
let result = html;
|
|
1002
|
+
const vault = new RawHtmlVault();
|
|
966
1003
|
result = result.replace(/<br\s*\/?>/gi, " \n");
|
|
967
1004
|
result = escapeMarkdownTextNodes(result);
|
|
968
1005
|
result = result.replace(RE_ICON_TAG, (_m, token) => `{[${token}]}`);
|
|
969
|
-
result = result
|
|
970
|
-
result = result.replace(
|
|
971
|
-
result = result.replace(RE_EM_TAG, "*$1*");
|
|
972
|
-
result = result.replace(RE_I_TAG, "*$1*");
|
|
973
|
-
result = result.replace(RE_S_TAG, "~~$1~~");
|
|
974
|
-
result = result.replace(RE_DEL_TAG, "~~$1~~");
|
|
1006
|
+
result = markdownFromMarkTags(result);
|
|
1007
|
+
result = result.replace(/<\/?(?:sup|sub)>/gi, (tag) => vault.protect(tag));
|
|
975
1008
|
result = result.replace(RE_CODE_TAG, "`$1`");
|
|
976
1009
|
result = result.replace(RE_MENTION_TAG, (match, _inner) => {
|
|
977
1010
|
const kind = /data-kind="([^"]*)"/i.exec(match)?.[1] ?? "";
|
|
@@ -991,9 +1024,11 @@ function htmlToInline(html) {
|
|
|
991
1024
|
const src = /\bsrc="([^"]*)"/i.exec(attrs)?.[1];
|
|
992
1025
|
if (!src) return match;
|
|
993
1026
|
const alt = /\balt="([^"]*)"/i.exec(attrs)?.[1] ?? "";
|
|
994
|
-
|
|
1027
|
+
const serialized = serializeImage(src, alt, attrs);
|
|
1028
|
+
return serialized.startsWith("<") ? vault.protect(serialized) : serialized;
|
|
995
1029
|
});
|
|
996
1030
|
result = result.replace(RE_STRIP_TAGS, "");
|
|
1031
|
+
result = vault.restore(result);
|
|
997
1032
|
return restoreLeadingSpaces(unescapeHtml(result));
|
|
998
1033
|
}
|
|
999
1034
|
function preserveLeadingSpaces(html) {
|