@cyberyozh/text-editor 0.4.0 → 0.5.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/dist/editor.d.mts +15 -1
- package/dist/editor.d.ts +15 -1
- package/dist/editor.js +46 -13
- package/dist/editor.js.map +1 -1
- package/dist/editor.mjs +51 -14
- package/dist/editor.mjs.map +1 -1
- package/dist/render.d.mts +9 -1
- package/dist/render.d.ts +9 -1
- package/dist/render.js +40 -10
- package/dist/render.js.map +1 -1
- package/dist/render.mjs +45 -11
- package/dist/render.mjs.map +1 -1
- package/package.json +1 -1
- package/src/editor/editor.tsx +8 -0
- package/src/extensions/base/link.test.ts +60 -0
- package/src/extensions/base/link.ts +61 -9
- package/src/extensions/editor/get-editor-extensions.ts +3 -1
- package/src/utils/get-shared-extensions.ts +20 -4
- package/src/utils/html-to-tiptap-content.ts +13 -4
package/dist/editor.mjs
CHANGED
|
@@ -4297,8 +4297,29 @@ var isSameDomain = (url) => {
|
|
|
4297
4297
|
return false;
|
|
4298
4298
|
}
|
|
4299
4299
|
};
|
|
4300
|
+
var isTrustedDomain = (url, trustedDomains) => {
|
|
4301
|
+
try {
|
|
4302
|
+
const { hostname } = new URL(url);
|
|
4303
|
+
if (typeof window !== "undefined" && hostname === window.location.hostname) {
|
|
4304
|
+
return true;
|
|
4305
|
+
}
|
|
4306
|
+
return trustedDomains.some((trusted) => {
|
|
4307
|
+
const domain2 = trusted.toLowerCase();
|
|
4308
|
+
return hostname === domain2 || hostname.endsWith(`.${domain2}`);
|
|
4309
|
+
});
|
|
4310
|
+
} catch {
|
|
4311
|
+
return false;
|
|
4312
|
+
}
|
|
4313
|
+
};
|
|
4300
4314
|
var LinkExtension = Link.extend({
|
|
4315
|
+
addOptions() {
|
|
4316
|
+
return {
|
|
4317
|
+
...this.parent?.() ?? {},
|
|
4318
|
+
trustedDomains: []
|
|
4319
|
+
};
|
|
4320
|
+
},
|
|
4301
4321
|
addAttributes() {
|
|
4322
|
+
const { trustedDomains } = this.options;
|
|
4302
4323
|
return {
|
|
4303
4324
|
...this.parent?.(),
|
|
4304
4325
|
target: {
|
|
@@ -4312,7 +4333,7 @@ var LinkExtension = Link.extend({
|
|
|
4312
4333
|
default: null,
|
|
4313
4334
|
parseHTML: (element) => {
|
|
4314
4335
|
const href = element.getAttribute("href") ?? "";
|
|
4315
|
-
return
|
|
4336
|
+
return isTrustedDomain(href, trustedDomains) ? null : "noopener noreferrer nofollow";
|
|
4316
4337
|
}
|
|
4317
4338
|
}
|
|
4318
4339
|
};
|
|
@@ -4330,15 +4351,20 @@ var LinkExtension = Link.extend({
|
|
|
4330
4351
|
protocols,
|
|
4331
4352
|
defaultProtocol
|
|
4332
4353
|
})
|
|
4333
|
-
).filter(
|
|
4354
|
+
).filter(
|
|
4355
|
+
(link) => this.options.shouldAutoLink?.(link.value) !== false
|
|
4356
|
+
).map((link) => ({
|
|
4357
|
+
text: link.value,
|
|
4358
|
+
data: { href: link.href },
|
|
4359
|
+
index: link.start
|
|
4360
|
+
})),
|
|
4334
4361
|
type: this.type,
|
|
4335
4362
|
getAttributes: (match) => {
|
|
4336
4363
|
const href = match.data?.href ?? "";
|
|
4337
|
-
const sameDomain = isSameDomain(href);
|
|
4338
4364
|
return {
|
|
4339
4365
|
href,
|
|
4340
|
-
target:
|
|
4341
|
-
rel:
|
|
4366
|
+
target: isSameDomain(href) ? "_self" : "_blank",
|
|
4367
|
+
rel: isTrustedDomain(href, this.options.trustedDomains) ? null : "noopener noreferrer nofollow"
|
|
4342
4368
|
};
|
|
4343
4369
|
}
|
|
4344
4370
|
})
|
|
@@ -4353,7 +4379,11 @@ var LinkExtension = Link.extend({
|
|
|
4353
4379
|
if (!view.editable) return false;
|
|
4354
4380
|
const range = getMarkRange(view.state.doc.resolve(pos), this.type);
|
|
4355
4381
|
if (!range) return false;
|
|
4356
|
-
const selection = TextSelection3.create(
|
|
4382
|
+
const selection = TextSelection3.create(
|
|
4383
|
+
view.state.doc,
|
|
4384
|
+
range.from,
|
|
4385
|
+
range.to
|
|
4386
|
+
);
|
|
4357
4387
|
view.dispatch(view.state.tr.setSelection(selection));
|
|
4358
4388
|
return true;
|
|
4359
4389
|
}
|
|
@@ -6069,7 +6099,11 @@ var Commands = Extension.create({
|
|
|
6069
6099
|
|
|
6070
6100
|
// src/utils/get-shared-extensions.ts
|
|
6071
6101
|
import StarterKit from "@tiptap/starter-kit";
|
|
6072
|
-
import {
|
|
6102
|
+
import {
|
|
6103
|
+
Details,
|
|
6104
|
+
DetailsContent,
|
|
6105
|
+
DetailsSummary
|
|
6106
|
+
} from "@tiptap/extension-details";
|
|
6073
6107
|
import Highlight from "@tiptap/extension-highlight";
|
|
6074
6108
|
import Subscript from "@tiptap/extension-subscript";
|
|
6075
6109
|
import Superscript from "@tiptap/extension-superscript";
|
|
@@ -6412,14 +6446,14 @@ var TextStyleKit = Extension6.create({
|
|
|
6412
6446
|
});
|
|
6413
6447
|
|
|
6414
6448
|
// src/utils/get-shared-extensions.ts
|
|
6415
|
-
function getSharedExtensions() {
|
|
6449
|
+
function getSharedExtensions(options = {}) {
|
|
6416
6450
|
return [
|
|
6417
6451
|
StarterKit.configure({
|
|
6418
6452
|
codeBlock: false,
|
|
6419
6453
|
link: false
|
|
6420
6454
|
}),
|
|
6421
6455
|
Highlight.configure({ multicolor: true }),
|
|
6422
|
-
LinkExtension,
|
|
6456
|
+
LinkExtension.configure({ trustedDomains: options.trustedDomains ?? [] }),
|
|
6423
6457
|
Superscript,
|
|
6424
6458
|
Subscript,
|
|
6425
6459
|
TextAlign.configure({
|
|
@@ -6660,9 +6694,10 @@ function getEditorExtensions(options) {
|
|
|
6660
6694
|
isEditable = false,
|
|
6661
6695
|
getImageById,
|
|
6662
6696
|
onKatexClick,
|
|
6663
|
-
onFigureClick
|
|
6697
|
+
onFigureClick,
|
|
6698
|
+
trustedDomains
|
|
6664
6699
|
} = options;
|
|
6665
|
-
const sharedExtensions = getSharedExtensions();
|
|
6700
|
+
const sharedExtensions = getSharedExtensions({ trustedDomains });
|
|
6666
6701
|
return [
|
|
6667
6702
|
...sharedExtensions,
|
|
6668
6703
|
Callout2,
|
|
@@ -7721,7 +7756,8 @@ function TiptapContent({
|
|
|
7721
7756
|
isEditable = true,
|
|
7722
7757
|
isDisabled = false,
|
|
7723
7758
|
lang,
|
|
7724
|
-
error
|
|
7759
|
+
error,
|
|
7760
|
+
trustedDomains
|
|
7725
7761
|
}) {
|
|
7726
7762
|
const [linkDialogContext, setLinkDialogContext] = useState13(null);
|
|
7727
7763
|
const [katexDialogContext, setKatexDialogContext] = useState13(
|
|
@@ -7756,6 +7792,7 @@ function TiptapContent({
|
|
|
7756
7792
|
suggestion: createSuggestions(translations2, !!imageHandlers),
|
|
7757
7793
|
isEditable: isEditable && !disabled,
|
|
7758
7794
|
getImageById: imageHandlers?.getImage,
|
|
7795
|
+
trustedDomains,
|
|
7759
7796
|
onKatexClick: (latex, pos) => {
|
|
7760
7797
|
setKatexDialogContext({ latex, pos });
|
|
7761
7798
|
openDialogCommand("katex");
|
|
@@ -7945,7 +7982,7 @@ import { TableKit as TableKit2 } from "@tiptap/extension-table";
|
|
|
7945
7982
|
function isJSONContent(value) {
|
|
7946
7983
|
return typeof value === "object" && value !== null && "type" in value && typeof value.type === "string";
|
|
7947
7984
|
}
|
|
7948
|
-
function htmlToTiptapContent(content) {
|
|
7985
|
+
function htmlToTiptapContent(content, options = {}) {
|
|
7949
7986
|
if (isJSONContent(content)) {
|
|
7950
7987
|
return content;
|
|
7951
7988
|
}
|
|
@@ -7961,7 +7998,7 @@ function htmlToTiptapContent(content) {
|
|
|
7961
7998
|
if (!content || content.trim() === "") {
|
|
7962
7999
|
return { type: "doc", content: [{ type: "paragraph" }] };
|
|
7963
8000
|
}
|
|
7964
|
-
const sharedExtensions = getSharedExtensions();
|
|
8001
|
+
const sharedExtensions = getSharedExtensions(options);
|
|
7965
8002
|
const extensions = [...sharedExtensions, BaseFigure, TableKit2, BaseCodeBlock];
|
|
7966
8003
|
try {
|
|
7967
8004
|
return generateJSON(content, extensions);
|