@cyberyozh/text-editor 0.5.2 → 0.5.4
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/editor.d.mts +11 -0
- package/dist/editor.d.ts +11 -0
- package/dist/editor.js +93 -38
- package/dist/editor.js.map +1 -1
- package/dist/editor.mjs +93 -38
- package/dist/editor.mjs.map +1 -1
- package/dist/html.d.mts +28 -0
- package/dist/html.d.ts +28 -0
- package/dist/html.js +2803 -0
- package/dist/html.js.map +1 -0
- package/dist/html.mjs +2771 -0
- package/dist/html.mjs.map +1 -0
- package/dist/render.d.mts +5 -0
- package/dist/render.d.ts +5 -0
- package/dist/render.js +47 -40
- package/dist/render.js.map +1 -1
- package/dist/render.mjs +47 -40
- package/dist/render.mjs.map +1 -1
- package/package.json +9 -3
- package/src/editor/editor.tsx +8 -0
- package/src/extensions/base/code-block.test.ts +39 -0
- package/src/extensions/base/code-block.ts +15 -1
- package/src/extensions/base/link.test.ts +54 -1
- package/src/extensions/base/link.ts +47 -41
- package/src/extensions/editor/get-editor-extensions.ts +3 -1
- package/src/extensions/render/get-render-extensions.ts +6 -3
- package/src/html/html.test.ts +154 -0
- package/src/html/index.ts +29 -0
- package/src/utils/get-shared-extensions.ts +9 -1
- package/src/utils/html-to-tiptap-content.ts +5 -13
package/dist/editor.d.mts
CHANGED
|
@@ -50,6 +50,12 @@ interface TiptapProps {
|
|
|
50
50
|
*/
|
|
51
51
|
lang?: SupportedLanguage;
|
|
52
52
|
error?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Domains (with all their subdomains) of the site the content belongs to:
|
|
55
|
+
* such links open in the same tab and get no rel on paste / HTML parsing.
|
|
56
|
+
* Read once when the editor instance is created.
|
|
57
|
+
*/
|
|
58
|
+
ownDomains?: string[];
|
|
53
59
|
/**
|
|
54
60
|
* Domains (with all their subdomains) whose links are treated as internal:
|
|
55
61
|
* rel="noopener noreferrer nofollow" is not added on paste / HTML parsing.
|
|
@@ -64,6 +70,11 @@ interface KatexDialogContextProps {
|
|
|
64
70
|
declare const Tiptap: (props: TiptapProps) => react.JSX.Element;
|
|
65
71
|
|
|
66
72
|
interface SharedExtensionsOptions {
|
|
73
|
+
/**
|
|
74
|
+
* Domains (with all their subdomains) of the site the content belongs to —
|
|
75
|
+
* see the ownDomains option of LinkExtension.
|
|
76
|
+
*/
|
|
77
|
+
ownDomains?: string[];
|
|
67
78
|
/**
|
|
68
79
|
* Domains (with all their subdomains) whose links are treated as internal —
|
|
69
80
|
* see the trustedDomains option of LinkExtension.
|
package/dist/editor.d.ts
CHANGED
|
@@ -50,6 +50,12 @@ interface TiptapProps {
|
|
|
50
50
|
*/
|
|
51
51
|
lang?: SupportedLanguage;
|
|
52
52
|
error?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Domains (with all their subdomains) of the site the content belongs to:
|
|
55
|
+
* such links open in the same tab and get no rel on paste / HTML parsing.
|
|
56
|
+
* Read once when the editor instance is created.
|
|
57
|
+
*/
|
|
58
|
+
ownDomains?: string[];
|
|
53
59
|
/**
|
|
54
60
|
* Domains (with all their subdomains) whose links are treated as internal:
|
|
55
61
|
* rel="noopener noreferrer nofollow" is not added on paste / HTML parsing.
|
|
@@ -64,6 +70,11 @@ interface KatexDialogContextProps {
|
|
|
64
70
|
declare const Tiptap: (props: TiptapProps) => react.JSX.Element;
|
|
65
71
|
|
|
66
72
|
interface SharedExtensionsOptions {
|
|
73
|
+
/**
|
|
74
|
+
* Domains (with all their subdomains) of the site the content belongs to —
|
|
75
|
+
* see the ownDomains option of LinkExtension.
|
|
76
|
+
*/
|
|
77
|
+
ownDomains?: string[];
|
|
67
78
|
/**
|
|
68
79
|
* Domains (with all their subdomains) whose links are treated as internal —
|
|
69
80
|
* see the trustedDomains option of LinkExtension.
|
package/dist/editor.js
CHANGED
|
@@ -2997,17 +2997,27 @@ var import_xml = __toESM(require("highlight.js/lib/languages/xml"));
|
|
|
2997
2997
|
var import_lowlight = require("lowlight");
|
|
2998
2998
|
var lowlight = (0, import_lowlight.createLowlight)(import_lowlight.common);
|
|
2999
2999
|
lowlight.register("html", import_xml.default);
|
|
3000
|
+
function languageFromClass(code, prefix) {
|
|
3001
|
+
const languageClass = Array.from(code?.classList ?? []).find(
|
|
3002
|
+
(className) => className.startsWith(prefix)
|
|
3003
|
+
);
|
|
3004
|
+
return languageClass ? languageClass.slice(prefix.length) : null;
|
|
3005
|
+
}
|
|
3000
3006
|
var BaseCodeBlock = import_extension_code_block_lowlight.CodeBlockLowlight.configure({
|
|
3001
3007
|
lowlight
|
|
3002
3008
|
}).extend({
|
|
3003
3009
|
selectable: false,
|
|
3004
3010
|
draggable: true,
|
|
3005
3011
|
addAttributes() {
|
|
3012
|
+
const { languageClassPrefix } = this.options;
|
|
3006
3013
|
return {
|
|
3007
3014
|
language: {
|
|
3008
3015
|
default: null,
|
|
3016
|
+
rendered: false,
|
|
3009
3017
|
parseHTML: (element) => {
|
|
3010
|
-
|
|
3018
|
+
const code = element.querySelector("code");
|
|
3019
|
+
const fromClass = languageClassPrefix ? languageFromClass(code, languageClassPrefix) : null;
|
|
3020
|
+
return fromClass || code?.getAttribute("data-language") || "bash";
|
|
3011
3021
|
}
|
|
3012
3022
|
}
|
|
3013
3023
|
};
|
|
@@ -4326,52 +4336,53 @@ function find(str, type = null, opts = null) {
|
|
|
4326
4336
|
}
|
|
4327
4337
|
|
|
4328
4338
|
// src/extensions/base/link.ts
|
|
4329
|
-
var
|
|
4330
|
-
if (typeof window === "undefined") return false;
|
|
4339
|
+
var hostnameOf = (url) => {
|
|
4331
4340
|
try {
|
|
4332
|
-
return new URL(url).hostname
|
|
4341
|
+
return new URL(url).hostname.toLowerCase();
|
|
4333
4342
|
} catch {
|
|
4334
|
-
return
|
|
4343
|
+
return null;
|
|
4335
4344
|
}
|
|
4336
4345
|
};
|
|
4337
|
-
var
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
});
|
|
4347
|
-
}
|
|
4348
|
-
|
|
4349
|
-
|
|
4346
|
+
var isSameDomain = (url) => {
|
|
4347
|
+
if (typeof window === "undefined") return false;
|
|
4348
|
+
return hostnameOf(url) === window.location.hostname;
|
|
4349
|
+
};
|
|
4350
|
+
var matchesDomains = (url, domains) => {
|
|
4351
|
+
const hostname = hostnameOf(url);
|
|
4352
|
+
if (hostname === null) return false;
|
|
4353
|
+
return domains.some((candidate) => {
|
|
4354
|
+
const domain2 = candidate.toLowerCase();
|
|
4355
|
+
return hostname === domain2 || hostname.endsWith(`.${domain2}`);
|
|
4356
|
+
});
|
|
4357
|
+
};
|
|
4358
|
+
var isOwnDomain = (url, ownDomains) => isSameDomain(url) || matchesDomains(url, ownDomains);
|
|
4359
|
+
var isTrustedDomain = (url, trustedDomains) => isSameDomain(url) || matchesDomains(url, trustedDomains);
|
|
4360
|
+
var linkAttributes = (href, { ownDomains, trustedDomains }) => {
|
|
4361
|
+
const own = isOwnDomain(href, ownDomains);
|
|
4362
|
+
return {
|
|
4363
|
+
target: own ? "_self" : "_blank",
|
|
4364
|
+
rel: own || isTrustedDomain(href, trustedDomains) ? null : "noopener noreferrer nofollow"
|
|
4365
|
+
};
|
|
4350
4366
|
};
|
|
4351
4367
|
var LinkExtension = import_extension_link.default.extend({
|
|
4352
4368
|
addOptions() {
|
|
4353
4369
|
return {
|
|
4354
4370
|
...this.parent?.() ?? {},
|
|
4371
|
+
ownDomains: [],
|
|
4355
4372
|
trustedDomains: []
|
|
4356
4373
|
};
|
|
4357
4374
|
},
|
|
4358
4375
|
addAttributes() {
|
|
4359
|
-
const
|
|
4376
|
+
const domains = this.options;
|
|
4360
4377
|
return {
|
|
4361
4378
|
...this.parent?.(),
|
|
4362
4379
|
target: {
|
|
4363
4380
|
default: "_blank",
|
|
4364
|
-
parseHTML: (element) =>
|
|
4365
|
-
const href = element.getAttribute("href") ?? "";
|
|
4366
|
-
return isSameDomain(href) ? "_self" : "_blank";
|
|
4367
|
-
}
|
|
4381
|
+
parseHTML: (element) => linkAttributes(element.getAttribute("href") ?? "", domains).target
|
|
4368
4382
|
},
|
|
4369
4383
|
rel: {
|
|
4370
4384
|
default: null,
|
|
4371
|
-
parseHTML: (element) =>
|
|
4372
|
-
const href = element.getAttribute("href") ?? "";
|
|
4373
|
-
return isTrustedDomain(href, trustedDomains) ? null : "noopener noreferrer nofollow";
|
|
4374
|
-
}
|
|
4385
|
+
parseHTML: (element) => linkAttributes(element.getAttribute("href") ?? "", domains).rel
|
|
4375
4386
|
}
|
|
4376
4387
|
};
|
|
4377
4388
|
},
|
|
@@ -4398,11 +4409,7 @@ var LinkExtension = import_extension_link.default.extend({
|
|
|
4398
4409
|
type: this.type,
|
|
4399
4410
|
getAttributes: (match) => {
|
|
4400
4411
|
const href = match.data?.href ?? "";
|
|
4401
|
-
return {
|
|
4402
|
-
href,
|
|
4403
|
-
target: isSameDomain(href) ? "_self" : "_blank",
|
|
4404
|
-
rel: isTrustedDomain(href, this.options.trustedDomains) ? null : "noopener noreferrer nofollow"
|
|
4405
|
-
};
|
|
4412
|
+
return { href, ...linkAttributes(href, this.options) };
|
|
4406
4413
|
}
|
|
4407
4414
|
})
|
|
4408
4415
|
];
|
|
@@ -6394,7 +6401,10 @@ function getSharedExtensions(options = {}) {
|
|
|
6394
6401
|
link: false
|
|
6395
6402
|
}),
|
|
6396
6403
|
import_extension_highlight.default.configure({ multicolor: true }),
|
|
6397
|
-
LinkExtension.configure({
|
|
6404
|
+
LinkExtension.configure({
|
|
6405
|
+
ownDomains: options.ownDomains ?? [],
|
|
6406
|
+
trustedDomains: options.trustedDomains ?? []
|
|
6407
|
+
}),
|
|
6398
6408
|
import_extension_superscript.default,
|
|
6399
6409
|
import_extension_subscript.default,
|
|
6400
6410
|
import_extension_text_align.default.configure({
|
|
@@ -6636,9 +6646,10 @@ function getEditorExtensions(options) {
|
|
|
6636
6646
|
getImageById,
|
|
6637
6647
|
onKatexClick,
|
|
6638
6648
|
onFigureClick,
|
|
6649
|
+
ownDomains,
|
|
6639
6650
|
trustedDomains
|
|
6640
6651
|
} = options;
|
|
6641
|
-
const sharedExtensions = getSharedExtensions({ trustedDomains });
|
|
6652
|
+
const sharedExtensions = getSharedExtensions({ ownDomains, trustedDomains });
|
|
6642
6653
|
return [
|
|
6643
6654
|
...sharedExtensions,
|
|
6644
6655
|
Callout2,
|
|
@@ -7704,6 +7715,7 @@ function TiptapContent({
|
|
|
7704
7715
|
isDisabled = false,
|
|
7705
7716
|
lang,
|
|
7706
7717
|
error,
|
|
7718
|
+
ownDomains,
|
|
7707
7719
|
trustedDomains
|
|
7708
7720
|
}) {
|
|
7709
7721
|
const [linkDialogContext, setLinkDialogContext] = (0, import_react38.useState)(null);
|
|
@@ -7739,6 +7751,7 @@ function TiptapContent({
|
|
|
7739
7751
|
suggestion: createSuggestions(translations2, !!imageHandlers),
|
|
7740
7752
|
isEditable: isEditable && !disabled,
|
|
7741
7753
|
getImageById: imageHandlers?.getImage,
|
|
7754
|
+
ownDomains,
|
|
7742
7755
|
trustedDomains,
|
|
7743
7756
|
onKatexClick: (latex, pos) => {
|
|
7744
7757
|
setKatexDialogContext({ latex, pos });
|
|
@@ -7924,8 +7937,52 @@ var Tiptap = (props) => {
|
|
|
7924
7937
|
};
|
|
7925
7938
|
|
|
7926
7939
|
// src/utils/html-to-tiptap-content.ts
|
|
7927
|
-
var
|
|
7940
|
+
var import_html = require("@tiptap/html");
|
|
7941
|
+
|
|
7942
|
+
// src/extensions/render/get-render-extensions.ts
|
|
7943
|
+
var import_extension_mathematics2 = require("@tiptap/extension-mathematics");
|
|
7928
7944
|
var import_extension_table2 = require("@tiptap/extension-table");
|
|
7945
|
+
function getRenderExtensions(options = {}) {
|
|
7946
|
+
const sharedExtensions = getSharedExtensions(options);
|
|
7947
|
+
return [
|
|
7948
|
+
...sharedExtensions,
|
|
7949
|
+
CopyableText,
|
|
7950
|
+
BaseCallout,
|
|
7951
|
+
BaseCodeBlock,
|
|
7952
|
+
BaseCustomQuote,
|
|
7953
|
+
BaseCustomQuoteText,
|
|
7954
|
+
BaseCustomQuoteAuthor,
|
|
7955
|
+
BaseCustomQuoteSign,
|
|
7956
|
+
BasePrompt,
|
|
7957
|
+
BasePromptHeader,
|
|
7958
|
+
BasePromptContent,
|
|
7959
|
+
BaseVideo,
|
|
7960
|
+
BaseFigure,
|
|
7961
|
+
import_extension_table2.TableKit.configure({
|
|
7962
|
+
table: { resizable: false, renderWrapper: true }
|
|
7963
|
+
}),
|
|
7964
|
+
import_extension_mathematics2.Mathematics.configure({
|
|
7965
|
+
katexOptions: {
|
|
7966
|
+
throwOnError: false
|
|
7967
|
+
}
|
|
7968
|
+
}),
|
|
7969
|
+
// ========================================================================
|
|
7970
|
+
// Legacy Extensions (Deprecated - for backward compatibility only)
|
|
7971
|
+
// ========================================================================
|
|
7972
|
+
BaseLegacyBookAlert,
|
|
7973
|
+
BaseLegacyBookTip,
|
|
7974
|
+
BaseLegacySEQuote,
|
|
7975
|
+
BaseLegacyPromptSE,
|
|
7976
|
+
BaseLegacyPromptSEHeader,
|
|
7977
|
+
BaseLegacyPromptSEContent,
|
|
7978
|
+
BaseLegacyCustomBlockquote,
|
|
7979
|
+
BaseLegacyYouTube,
|
|
7980
|
+
BaseLegacyFigure
|
|
7981
|
+
// Update
|
|
7982
|
+
];
|
|
7983
|
+
}
|
|
7984
|
+
|
|
7985
|
+
// src/utils/html-to-tiptap-content.ts
|
|
7929
7986
|
function isJSONContent(value) {
|
|
7930
7987
|
return typeof value === "object" && value !== null && "type" in value && typeof value.type === "string";
|
|
7931
7988
|
}
|
|
@@ -7945,10 +8002,8 @@ function htmlToTiptapContent(content, options = {}) {
|
|
|
7945
8002
|
if (!content || content.trim() === "") {
|
|
7946
8003
|
return { type: "doc", content: [{ type: "paragraph" }] };
|
|
7947
8004
|
}
|
|
7948
|
-
const sharedExtensions = getSharedExtensions(options);
|
|
7949
|
-
const extensions = [...sharedExtensions, BaseFigure, import_extension_table2.TableKit, BaseCodeBlock];
|
|
7950
8005
|
try {
|
|
7951
|
-
return (0,
|
|
8006
|
+
return (0, import_html.generateJSON)(content, getRenderExtensions(options));
|
|
7952
8007
|
} catch (error) {
|
|
7953
8008
|
console.error("Failed to convert HTML to Tiptap content:", error);
|
|
7954
8009
|
return { type: "doc", content: [{ type: "paragraph" }] };
|