@pixerate/editor 0.24.0 → 0.25.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/README.md +71 -1
- package/THIRD_PARTY_NOTICES.md +29 -0
- package/dist/agent/index.cjs +10 -9
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +1 -1
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.js +4 -3
- package/dist/agent/index.js.map +1 -1
- package/dist/canvas/index.cjs +3173 -340
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +617 -4
- package/dist/canvas/index.d.ts +617 -4
- package/dist/canvas/index.js +3105 -272
- package/dist/canvas/index.js.map +1 -1
- package/dist/chunk-4BVP64JJ.cjs +1406 -0
- package/dist/chunk-4BVP64JJ.cjs.map +1 -0
- package/dist/{chunk-XNORY7M6.cjs → chunk-7WISYZFO.cjs} +105 -50
- package/dist/chunk-7WISYZFO.cjs.map +1 -0
- package/dist/{chunk-OLZJXL4R.cjs → chunk-AL6JMGWW.cjs} +59 -25
- package/dist/chunk-AL6JMGWW.cjs.map +1 -0
- package/dist/chunk-BVP3TSLH.cjs +69 -0
- package/dist/chunk-BVP3TSLH.cjs.map +1 -0
- package/dist/{chunk-MCSJFWAO.cjs → chunk-C7P22VIP.cjs} +670 -96
- package/dist/chunk-C7P22VIP.cjs.map +1 -0
- package/dist/{chunk-PGNZKFQS.js → chunk-ECCCYKGL.js} +76 -21
- package/dist/chunk-ECCCYKGL.js.map +1 -0
- package/dist/{chunk-3CN2WD3X.js → chunk-FH6F67DN.js} +646 -72
- package/dist/chunk-FH6F67DN.js.map +1 -0
- package/dist/chunk-HRMEDT2L.js +1406 -0
- package/dist/chunk-HRMEDT2L.js.map +1 -0
- package/dist/{chunk-ITBSKI26.js → chunk-IXHSYOVY.js} +941 -9
- package/dist/chunk-IXHSYOVY.js.map +1 -0
- package/dist/{chunk-FODNLX5N.js → chunk-NAXVVS5I.js} +38 -4
- package/dist/chunk-NAXVVS5I.js.map +1 -0
- package/dist/chunk-O5RYH2PG.js +69 -0
- package/dist/chunk-O5RYH2PG.js.map +1 -0
- package/dist/{chunk-SBCZ6RN5.cjs → chunk-PO6A6QQH.cjs} +1039 -107
- package/dist/chunk-PO6A6QQH.cjs.map +1 -0
- package/dist/{chunk-3LV6RRPH.js → chunk-QGYDWPRM.js} +2 -2
- package/dist/{chunk-U5KWZU4X.js → chunk-RR7F5GUM.js} +2632 -129
- package/dist/chunk-RR7F5GUM.js.map +1 -0
- package/dist/{chunk-5S3Z4PPF.js → chunk-UAKDG62Z.js} +232 -25
- package/dist/chunk-UAKDG62Z.js.map +1 -0
- package/dist/{chunk-SML64VJG.cjs → chunk-V3CHHWOE.cjs} +4 -4
- package/dist/{chunk-SML64VJG.cjs.map → chunk-V3CHHWOE.cjs.map} +1 -1
- package/dist/chunk-WSQKHXW7.cjs +5726 -0
- package/dist/chunk-WSQKHXW7.cjs.map +1 -0
- package/dist/{chunk-D27YFC46.cjs → chunk-X4N4WUKB.cjs} +267 -60
- package/dist/chunk-X4N4WUKB.cjs.map +1 -0
- package/dist/commands/index.cjs +74 -1
- package/dist/commands/index.cjs.map +1 -1
- package/dist/commands/index.d.cts +34 -1
- package/dist/commands/index.d.ts +34 -1
- package/dist/commands/index.js +73 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/compare/index.cjs +3 -3
- package/dist/compare/index.d.cts +1 -1
- package/dist/compare/index.d.ts +1 -1
- package/dist/compare/index.js +2 -2
- package/dist/controller-BIJiNoVs.d.cts +1842 -0
- package/dist/controller-BIJiNoVs.d.ts +1842 -0
- package/dist/{documents-BQjzJNe2.d.ts → documents-CHT1U5Vs.d.ts} +10 -0
- package/dist/{documents-KRTPhvst.d.cts → documents-Gp7wb0Me.d.cts} +10 -0
- package/dist/extensions/index.cjs +53 -6
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.d.cts +12 -4
- package/dist/extensions/index.d.ts +12 -4
- package/dist/extensions/index.js +53 -6
- package/dist/generation/index.cjs +1013 -69
- package/dist/generation/index.cjs.map +1 -1
- package/dist/generation/index.d.cts +474 -13
- package/dist/generation/index.d.ts +474 -13
- package/dist/generation/index.js +976 -32
- package/dist/generation/index.js.map +1 -1
- package/dist/image-editor/index.cjs +3385 -1275
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +693 -128
- package/dist/image-editor/index.d.ts +693 -128
- package/dist/image-editor/index.js +3325 -1215
- package/dist/image-editor/index.js.map +1 -1
- package/dist/{index-fJrlkJCd.d.ts → index-7a6bHTLy.d.ts} +494 -5
- package/dist/{index-BhJBSm2d.d.cts → index-Csd5qI8u.d.cts} +494 -5
- package/dist/index.cjs +1491 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +110 -19
- package/dist/index.d.ts +110 -19
- package/dist/index.js +1464 -18
- package/dist/index.js.map +1 -1
- package/dist/mention-text-CDnCFd3c.d.cts +53 -0
- package/dist/mention-text-CDnCFd3c.d.ts +53 -0
- package/dist/model-C1zApQM8.d.cts +219 -0
- package/dist/model-C1zApQM8.d.ts +219 -0
- package/dist/persistence/index.d.cts +3 -120
- package/dist/persistence/index.d.ts +3 -120
- package/dist/{registry-GJI4gToU.d.cts → registry-CEgwXED1.d.cts} +12 -1
- package/dist/{registry-GJI4gToU.d.ts → registry-CEgwXED1.d.ts} +12 -1
- package/dist/serializers/index.cjs +12 -4
- package/dist/serializers/index.cjs.map +1 -1
- package/dist/serializers/index.d.cts +39 -12
- package/dist/serializers/index.d.ts +39 -12
- package/dist/serializers/index.js +12 -4
- package/dist/spreadsheet/index.cjs +127 -3
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +431 -11
- package/dist/spreadsheet/index.d.ts +431 -11
- package/dist/spreadsheet/index.js +127 -3
- package/dist/storage-BpFfspHm.d.cts +120 -0
- package/dist/storage-BpFfspHm.d.ts +120 -0
- package/dist/tokens/index.cjs +115 -0
- package/dist/tokens/index.cjs.map +1 -0
- package/dist/tokens/index.d.cts +212 -0
- package/dist/tokens/index.d.ts +212 -0
- package/dist/tokens/index.js +115 -0
- package/dist/tokens/index.js.map +1 -0
- package/dist/{track-changes-BK5sVf4_.d.cts → track-changes-D_VAPELi.d.cts} +95 -11
- package/dist/{track-changes-CDjCrwKe.d.ts → track-changes-Db_fGEvx.d.ts} +95 -11
- package/package.json +6 -1
- package/dist/chunk-3CN2WD3X.js.map +0 -1
- package/dist/chunk-5S3Z4PPF.js.map +0 -1
- package/dist/chunk-D27YFC46.cjs.map +0 -1
- package/dist/chunk-FODNLX5N.js.map +0 -1
- package/dist/chunk-ITBSKI26.js.map +0 -1
- package/dist/chunk-MA2F5KHF.cjs +0 -3223
- package/dist/chunk-MA2F5KHF.cjs.map +0 -1
- package/dist/chunk-MCSJFWAO.cjs.map +0 -1
- package/dist/chunk-OLZJXL4R.cjs.map +0 -1
- package/dist/chunk-PGNZKFQS.js.map +0 -1
- package/dist/chunk-SBCZ6RN5.cjs.map +0 -1
- package/dist/chunk-U5KWZU4X.js.map +0 -1
- package/dist/chunk-XNORY7M6.cjs.map +0 -1
- package/dist/controller-BhLLAoi8.d.cts +0 -1000
- package/dist/controller-BhLLAoi8.d.ts +0 -1000
- /package/dist/{chunk-3LV6RRPH.js.map → chunk-QGYDWPRM.js.map} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
compareDocuments
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-NAXVVS5I.js";
|
|
4
4
|
import {
|
|
5
5
|
INSTRUCTION_REGEX,
|
|
6
6
|
TEMPLATE_REGEX,
|
|
@@ -16,20 +16,20 @@ import {
|
|
|
16
16
|
rtfToPlainText,
|
|
17
17
|
sanitizeImportedHtml,
|
|
18
18
|
serializeRichClipboardPayload
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-QGYDWPRM.js";
|
|
20
20
|
import {
|
|
21
21
|
escapeHtml,
|
|
22
22
|
htmlToPlainText,
|
|
23
23
|
markdownToTipTapHtml,
|
|
24
24
|
plainTextToSlice
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-ECCCYKGL.js";
|
|
26
26
|
import {
|
|
27
27
|
CommentStore,
|
|
28
28
|
TRACK_CHANGES_SKIP_META,
|
|
29
29
|
TrackChanges,
|
|
30
30
|
createReviewId,
|
|
31
31
|
trackChangesPluginKey
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-UAKDG62Z.js";
|
|
33
33
|
|
|
34
34
|
// src/extensions/gradient-text.ts
|
|
35
35
|
import { Mark } from "@tiptap/core";
|
|
@@ -601,10 +601,47 @@ var Mention = BaseMention.extend({
|
|
|
601
601
|
if (!attributes.color) return {};
|
|
602
602
|
return { "data-color": attributes.color };
|
|
603
603
|
}
|
|
604
|
+
},
|
|
605
|
+
// Role of an asset mention (`reference`, `style`, `start_frame`, …). The
|
|
606
|
+
// node attribute is `assetRole` so entities that already carry a `role`
|
|
607
|
+
// (e.g. a user's job title) passed as suggestion props do not set it.
|
|
608
|
+
assetRole: {
|
|
609
|
+
default: null,
|
|
610
|
+
parseHTML: (element) => {
|
|
611
|
+
const role = element.getAttribute("data-role");
|
|
612
|
+
return role && MENTION_ROLE_PATTERN.test(role) ? role : null;
|
|
613
|
+
},
|
|
614
|
+
renderHTML: (attributes) => {
|
|
615
|
+
if (!attributes.assetRole) return {};
|
|
616
|
+
return { "data-role": attributes.assetRole };
|
|
617
|
+
}
|
|
604
618
|
}
|
|
605
619
|
};
|
|
606
620
|
}
|
|
607
621
|
});
|
|
622
|
+
var MENTION_ROLE_PATTERN = /^[A-Za-z](?:[A-Za-z0-9_-]*[A-Za-z0-9])?$/;
|
|
623
|
+
function getMentionNodes(editor) {
|
|
624
|
+
const result = [];
|
|
625
|
+
editor.state.doc.descendants((node, pos) => {
|
|
626
|
+
if (node.type?.name !== "mention") return;
|
|
627
|
+
result.push({
|
|
628
|
+
pos,
|
|
629
|
+
id: node.attrs.id ?? "",
|
|
630
|
+
label: node.attrs.label ?? "",
|
|
631
|
+
...node.attrs.type ? { type: node.attrs.type } : {},
|
|
632
|
+
...node.attrs.assetRole ? { role: node.attrs.assetRole } : {}
|
|
633
|
+
});
|
|
634
|
+
});
|
|
635
|
+
return result;
|
|
636
|
+
}
|
|
637
|
+
function setMentionRoleAt(editor, pos, role) {
|
|
638
|
+
const node = editor?.state?.doc?.nodeAt(pos);
|
|
639
|
+
if (!node || node.type.name !== "mention") return false;
|
|
640
|
+
if (role !== null && !MENTION_ROLE_PATTERN.test(role)) return false;
|
|
641
|
+
const tr = editor.state.tr.setNodeMarkup(pos, void 0, { ...node.attrs, assetRole: role });
|
|
642
|
+
editor.view.dispatch(tr);
|
|
643
|
+
return true;
|
|
644
|
+
}
|
|
608
645
|
function createMentionExtension(options = {}) {
|
|
609
646
|
const { HTMLAttributes = {}, ...rest } = options;
|
|
610
647
|
return Mention.configure({
|
|
@@ -2249,7 +2286,13 @@ var ImportAdapterRegistry = class {
|
|
|
2249
2286
|
{ fileName }
|
|
2250
2287
|
);
|
|
2251
2288
|
}
|
|
2252
|
-
const context = createImportContext(input, {
|
|
2289
|
+
const context = createImportContext(input, {
|
|
2290
|
+
fileName,
|
|
2291
|
+
mimeType,
|
|
2292
|
+
target: adapter.target,
|
|
2293
|
+
registry: this,
|
|
2294
|
+
options: options.adapterOptions?.[adapter.id]
|
|
2295
|
+
});
|
|
2253
2296
|
try {
|
|
2254
2297
|
const result = await adapter.import(input, context);
|
|
2255
2298
|
return { adapterId: adapter.id, target: adapter.target, fileName, mimeType, result };
|
|
@@ -3348,7 +3391,10 @@ async function importFilesIntoEditor(target, files, options = {}) {
|
|
|
3348
3391
|
let at = options.at;
|
|
3349
3392
|
for (const file of Array.from(files)) {
|
|
3350
3393
|
try {
|
|
3351
|
-
const outcome = await registry.importFile(file, {
|
|
3394
|
+
const outcome = await registry.importFile(file, {
|
|
3395
|
+
target: "document",
|
|
3396
|
+
adapterOptions: options.adapterOptions
|
|
3397
|
+
});
|
|
3352
3398
|
const view = toView(target);
|
|
3353
3399
|
if (view.isDestroyed) break;
|
|
3354
3400
|
at = insertImportedDocument(view, outcome.result, { at, asPlainText: options.asPlainText });
|
|
@@ -3382,6 +3428,7 @@ var FileImport = Extension8.create({
|
|
|
3382
3428
|
addOptions() {
|
|
3383
3429
|
return {
|
|
3384
3430
|
registry: void 0,
|
|
3431
|
+
adapterOptions: void 0,
|
|
3385
3432
|
asPlainText: false,
|
|
3386
3433
|
enableDrop: true,
|
|
3387
3434
|
enablePaste: true,
|
|
@@ -3397,6 +3444,7 @@ var FileImport = Extension8.create({
|
|
|
3397
3444
|
registry: registry(),
|
|
3398
3445
|
at,
|
|
3399
3446
|
asPlainText: options.asPlainText,
|
|
3447
|
+
adapterOptions: options.adapterOptions,
|
|
3400
3448
|
onImport: options.onImport,
|
|
3401
3449
|
onError: options.onImportError
|
|
3402
3450
|
});
|
|
@@ -6469,6 +6517,869 @@ function safeClipboard(get) {
|
|
|
6469
6517
|
}
|
|
6470
6518
|
}
|
|
6471
6519
|
|
|
6520
|
+
// src/extensions/paragraph-styles/extension.ts
|
|
6521
|
+
import { Extension as Extension13, Mark as Mark5, mergeAttributes as mergeAttributes7 } from "@tiptap/core";
|
|
6522
|
+
import { Plugin as Plugin15, PluginKey as PluginKey12 } from "@tiptap/pm/state";
|
|
6523
|
+
|
|
6524
|
+
// src/extensions/paragraph-styles/registry.ts
|
|
6525
|
+
var MAX_CHAIN = 32;
|
|
6526
|
+
var STYLE_ID = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/;
|
|
6527
|
+
var UNSAFE_CSS = /[;{}<>\\]|\/\*|url\s*\(|expression\s*\(|@import|javascript:/i;
|
|
6528
|
+
var NORMAL_STYLE_ID = "Normal";
|
|
6529
|
+
var PREVIEW_PROPERTIES = /* @__PURE__ */ new Set([
|
|
6530
|
+
"font-family",
|
|
6531
|
+
"font-weight",
|
|
6532
|
+
"font-style",
|
|
6533
|
+
"color",
|
|
6534
|
+
"text-decoration-line",
|
|
6535
|
+
"text-transform",
|
|
6536
|
+
"letter-spacing",
|
|
6537
|
+
"font-variant-caps"
|
|
6538
|
+
]);
|
|
6539
|
+
function isValidStyleId(id) {
|
|
6540
|
+
return typeof id === "string" && STYLE_ID.test(id);
|
|
6541
|
+
}
|
|
6542
|
+
var MUTED = "var(--pixerate-style-muted, #6b7280)";
|
|
6543
|
+
var HEADING_SIZES = ["2em", "1.5em", "1.25em", "1.1em", "1em", "0.9em"];
|
|
6544
|
+
function builtinStyles() {
|
|
6545
|
+
const styles = [
|
|
6546
|
+
{
|
|
6547
|
+
id: NORMAL_STYLE_ID,
|
|
6548
|
+
name: "Normal",
|
|
6549
|
+
kind: "paragraph",
|
|
6550
|
+
block: { type: "paragraph" },
|
|
6551
|
+
priority: 0,
|
|
6552
|
+
quick: true,
|
|
6553
|
+
builtin: true
|
|
6554
|
+
},
|
|
6555
|
+
{
|
|
6556
|
+
id: "Title",
|
|
6557
|
+
name: "Title",
|
|
6558
|
+
kind: "paragraph",
|
|
6559
|
+
basedOn: NORMAL_STYLE_ID,
|
|
6560
|
+
next: NORMAL_STYLE_ID,
|
|
6561
|
+
linked: "TitleChar",
|
|
6562
|
+
paragraph: { spaceAfter: "0.25em", lineHeight: "1.15" },
|
|
6563
|
+
character: { fontSize: "2.5em", bold: true, letterSpacing: "-0.01em" },
|
|
6564
|
+
priority: 10,
|
|
6565
|
+
quick: true,
|
|
6566
|
+
builtin: true
|
|
6567
|
+
},
|
|
6568
|
+
{
|
|
6569
|
+
id: "Subtitle",
|
|
6570
|
+
name: "Subtitle",
|
|
6571
|
+
kind: "paragraph",
|
|
6572
|
+
basedOn: NORMAL_STYLE_ID,
|
|
6573
|
+
next: NORMAL_STYLE_ID,
|
|
6574
|
+
linked: "SubtitleChar",
|
|
6575
|
+
paragraph: { spaceAfter: "0.75em" },
|
|
6576
|
+
character: { fontSize: "1.25em", color: MUTED },
|
|
6577
|
+
priority: 11,
|
|
6578
|
+
quick: true,
|
|
6579
|
+
builtin: true
|
|
6580
|
+
}
|
|
6581
|
+
];
|
|
6582
|
+
HEADING_SIZES.forEach((fontSize, i) => {
|
|
6583
|
+
const level = i + 1;
|
|
6584
|
+
styles.push({
|
|
6585
|
+
id: `Heading${level}`,
|
|
6586
|
+
name: `Heading ${level}`,
|
|
6587
|
+
kind: "paragraph",
|
|
6588
|
+
basedOn: NORMAL_STYLE_ID,
|
|
6589
|
+
next: NORMAL_STYLE_ID,
|
|
6590
|
+
linked: `Heading${level}Char`,
|
|
6591
|
+
block: { type: "heading", attrs: { level } },
|
|
6592
|
+
paragraph: { spaceBefore: level <= 2 ? "1em" : "0.75em", spaceAfter: "0.25em" },
|
|
6593
|
+
character: { fontSize, bold: true },
|
|
6594
|
+
priority: 11 + level,
|
|
6595
|
+
quick: level <= 3,
|
|
6596
|
+
builtin: true
|
|
6597
|
+
});
|
|
6598
|
+
});
|
|
6599
|
+
styles.push(
|
|
6600
|
+
{
|
|
6601
|
+
id: "Quote",
|
|
6602
|
+
name: "Quote",
|
|
6603
|
+
kind: "paragraph",
|
|
6604
|
+
basedOn: NORMAL_STYLE_ID,
|
|
6605
|
+
next: NORMAL_STYLE_ID,
|
|
6606
|
+
linked: "QuoteChar",
|
|
6607
|
+
paragraph: { indentLeft: "1em", paddingLeft: "0.75em", borderLeft: "3px solid currentColor" },
|
|
6608
|
+
character: { italic: true, color: MUTED },
|
|
6609
|
+
priority: 29,
|
|
6610
|
+
quick: true,
|
|
6611
|
+
builtin: true
|
|
6612
|
+
},
|
|
6613
|
+
{
|
|
6614
|
+
id: "Code",
|
|
6615
|
+
name: "Code",
|
|
6616
|
+
kind: "paragraph",
|
|
6617
|
+
basedOn: NORMAL_STYLE_ID,
|
|
6618
|
+
next: NORMAL_STYLE_ID,
|
|
6619
|
+
block: { type: "codeBlock" },
|
|
6620
|
+
character: {
|
|
6621
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
|
|
6622
|
+
fontSize: "0.9em"
|
|
6623
|
+
},
|
|
6624
|
+
priority: 30,
|
|
6625
|
+
quick: true,
|
|
6626
|
+
builtin: true
|
|
6627
|
+
},
|
|
6628
|
+
{
|
|
6629
|
+
id: "ListParagraph",
|
|
6630
|
+
name: "List Paragraph",
|
|
6631
|
+
kind: "paragraph",
|
|
6632
|
+
basedOn: NORMAL_STYLE_ID,
|
|
6633
|
+
paragraph: { indentLeft: "2em" },
|
|
6634
|
+
priority: 34,
|
|
6635
|
+
quick: true,
|
|
6636
|
+
builtin: true
|
|
6637
|
+
}
|
|
6638
|
+
);
|
|
6639
|
+
const linked = ["Title", "Subtitle", "Quote", ...HEADING_SIZES.map((_, i) => `Heading${i + 1}`)];
|
|
6640
|
+
linked.forEach((paragraphId) => {
|
|
6641
|
+
const name = styles.find((s) => s.id === paragraphId).name;
|
|
6642
|
+
styles.push({
|
|
6643
|
+
id: `${paragraphId}Char`,
|
|
6644
|
+
name: `${name} Char`,
|
|
6645
|
+
kind: "character",
|
|
6646
|
+
linked: paragraphId,
|
|
6647
|
+
priority: 99,
|
|
6648
|
+
hidden: true,
|
|
6649
|
+
builtin: true
|
|
6650
|
+
});
|
|
6651
|
+
});
|
|
6652
|
+
styles.push(
|
|
6653
|
+
{
|
|
6654
|
+
id: "Emphasis",
|
|
6655
|
+
name: "Emphasis",
|
|
6656
|
+
kind: "character",
|
|
6657
|
+
character: { italic: true },
|
|
6658
|
+
priority: 20,
|
|
6659
|
+
quick: true,
|
|
6660
|
+
builtin: true
|
|
6661
|
+
},
|
|
6662
|
+
{
|
|
6663
|
+
id: "Strong",
|
|
6664
|
+
name: "Strong",
|
|
6665
|
+
kind: "character",
|
|
6666
|
+
character: { bold: true },
|
|
6667
|
+
priority: 22,
|
|
6668
|
+
quick: true,
|
|
6669
|
+
builtin: true
|
|
6670
|
+
}
|
|
6671
|
+
);
|
|
6672
|
+
return styles;
|
|
6673
|
+
}
|
|
6674
|
+
var DEFAULT_STYLES = Object.freeze(builtinStyles());
|
|
6675
|
+
var clone = (value) => value === void 0 ? value : JSON.parse(JSON.stringify(value));
|
|
6676
|
+
function overlay(base, patch) {
|
|
6677
|
+
if (!patch) return base;
|
|
6678
|
+
const out = { ...base };
|
|
6679
|
+
Object.entries(patch).forEach(([key, value]) => {
|
|
6680
|
+
if (value !== void 0 && value !== null) out[key] = value;
|
|
6681
|
+
});
|
|
6682
|
+
return out;
|
|
6683
|
+
}
|
|
6684
|
+
function sameBlock(a, type, attrs) {
|
|
6685
|
+
if (a.type !== type) return false;
|
|
6686
|
+
return Object.entries(a.attrs ?? {}).every(([key, value]) => attrs[key] === value);
|
|
6687
|
+
}
|
|
6688
|
+
var StyleRegistry = class {
|
|
6689
|
+
styles = /* @__PURE__ */ new Map();
|
|
6690
|
+
defaults;
|
|
6691
|
+
version = 0;
|
|
6692
|
+
snapshot = null;
|
|
6693
|
+
listeners = /* @__PURE__ */ new Set();
|
|
6694
|
+
constructor(options = {}) {
|
|
6695
|
+
this.defaults = clone(options.defaults ?? {});
|
|
6696
|
+
if (options.builtins !== false) DEFAULT_STYLES.forEach((style) => this.styles.set(style.id, clone(style)));
|
|
6697
|
+
(options.styles ?? []).forEach((style) => this.put(style));
|
|
6698
|
+
}
|
|
6699
|
+
// -- Reading --------------------------------------------------------------
|
|
6700
|
+
get(id) {
|
|
6701
|
+
return id ? this.styles.get(id) : void 0;
|
|
6702
|
+
}
|
|
6703
|
+
/** Finds a style by id or display name (case-insensitive). */
|
|
6704
|
+
find(nameOrId) {
|
|
6705
|
+
const direct = this.styles.get(nameOrId);
|
|
6706
|
+
if (direct) return direct;
|
|
6707
|
+
const lower = nameOrId.toLowerCase();
|
|
6708
|
+
return this.list().find((style) => style.name.toLowerCase() === lower);
|
|
6709
|
+
}
|
|
6710
|
+
/** All styles (optionally of one kind) in gallery order. */
|
|
6711
|
+
list(kind) {
|
|
6712
|
+
return Array.from(this.styles.values()).filter((style) => !kind || style.kind === kind).sort((a, b) => (a.priority ?? 99) - (b.priority ?? 99) || a.name.localeCompare(b.name));
|
|
6713
|
+
}
|
|
6714
|
+
/** Styles shown in the gallery (`quick`, not hidden), paragraph styles by default. */
|
|
6715
|
+
gallery(kind = "paragraph") {
|
|
6716
|
+
return this.list(kind).filter((style) => style.quick && !style.hidden);
|
|
6717
|
+
}
|
|
6718
|
+
/** The `basedOn` chain from the root style down to `id` (cycle-safe, bounded). */
|
|
6719
|
+
chain(id) {
|
|
6720
|
+
const out = [];
|
|
6721
|
+
let current = this.styles.get(id);
|
|
6722
|
+
while (current && out.length < MAX_CHAIN && !out.includes(current)) {
|
|
6723
|
+
out.push(current);
|
|
6724
|
+
current = current.basedOn ? this.styles.get(current.basedOn) : void 0;
|
|
6725
|
+
}
|
|
6726
|
+
return out.reverse();
|
|
6727
|
+
}
|
|
6728
|
+
/**
|
|
6729
|
+
* Resolves a paragraph style: defaults, then each style of the chain (base
|
|
6730
|
+
* first). Unknown ids resolve to the defaults in a `paragraph` block.
|
|
6731
|
+
*/
|
|
6732
|
+
resolve(id) {
|
|
6733
|
+
let paragraph = overlay({}, this.defaults.paragraph);
|
|
6734
|
+
let character = overlay({}, this.defaults.character);
|
|
6735
|
+
let block = { type: "paragraph" };
|
|
6736
|
+
this.chain(id).forEach((style) => {
|
|
6737
|
+
if (style.kind !== "paragraph") return;
|
|
6738
|
+
paragraph = overlay(paragraph, style.paragraph);
|
|
6739
|
+
character = overlay(character, style.character);
|
|
6740
|
+
if (style.block) block = clone(style.block);
|
|
6741
|
+
});
|
|
6742
|
+
return { id, paragraph, character, block, next: this.nextStyleId(id) };
|
|
6743
|
+
}
|
|
6744
|
+
/** Character formatting a paragraph style's chain sets (without defaults). */
|
|
6745
|
+
paragraphCharacter(id) {
|
|
6746
|
+
let character = {};
|
|
6747
|
+
this.chain(id).forEach((style) => {
|
|
6748
|
+
if (style.kind === "paragraph") character = overlay(character, style.character);
|
|
6749
|
+
});
|
|
6750
|
+
return character;
|
|
6751
|
+
}
|
|
6752
|
+
/**
|
|
6753
|
+
* Character formatting of a character style's chain. A style linked to a
|
|
6754
|
+
* paragraph style takes that style's character formatting first.
|
|
6755
|
+
*/
|
|
6756
|
+
resolveCharacterStyle(id) {
|
|
6757
|
+
let character = {};
|
|
6758
|
+
this.chain(id).forEach((style) => {
|
|
6759
|
+
if (style.kind === "character" && style.linked && this.get(style.linked)?.kind === "paragraph") {
|
|
6760
|
+
character = overlay(character, this.paragraphCharacter(style.linked));
|
|
6761
|
+
}
|
|
6762
|
+
character = overlay(character, style.character);
|
|
6763
|
+
});
|
|
6764
|
+
return character;
|
|
6765
|
+
}
|
|
6766
|
+
/**
|
|
6767
|
+
* Character formatting of text: defaults → paragraph style chain →
|
|
6768
|
+
* character style chain → direct formatting.
|
|
6769
|
+
*/
|
|
6770
|
+
resolveText(input) {
|
|
6771
|
+
let character = this.resolve(input.paragraphStyle || NORMAL_STYLE_ID).character;
|
|
6772
|
+
if (input.characterStyle) character = overlay(character, this.resolveCharacterStyle(input.characterStyle));
|
|
6773
|
+
return overlay(character, input.direct);
|
|
6774
|
+
}
|
|
6775
|
+
/** The style after Enter at the end of a paragraph of `id` (itself when unset or unknown). */
|
|
6776
|
+
nextStyleId(id) {
|
|
6777
|
+
const next = this.styles.get(id)?.next;
|
|
6778
|
+
return next && this.styles.get(next)?.kind === "paragraph" ? next : id;
|
|
6779
|
+
}
|
|
6780
|
+
/** The linked character style of a paragraph style, if any. */
|
|
6781
|
+
linkedCharacterStyle(id) {
|
|
6782
|
+
const style = this.styles.get(id);
|
|
6783
|
+
const linked = style?.linked ? this.styles.get(style.linked) : void 0;
|
|
6784
|
+
return style?.kind === "paragraph" && linked?.kind === "character" ? linked : void 0;
|
|
6785
|
+
}
|
|
6786
|
+
/**
|
|
6787
|
+
* The style a block uses when it names none: Normal for paragraphs,
|
|
6788
|
+
* Heading N for headings of level N, Code for code blocks (the built-in
|
|
6789
|
+
* style whose own `block` matches).
|
|
6790
|
+
*/
|
|
6791
|
+
defaultStyleFor(type, attrs = {}) {
|
|
6792
|
+
if (type === "paragraph" && this.styles.get(NORMAL_STYLE_ID)) return NORMAL_STYLE_ID;
|
|
6793
|
+
const candidates = this.list("paragraph").filter(
|
|
6794
|
+
(style) => style.block && sameBlock(style.block, type, attrs)
|
|
6795
|
+
);
|
|
6796
|
+
return (candidates.find((s) => s.builtin) ?? candidates[0])?.id ?? null;
|
|
6797
|
+
}
|
|
6798
|
+
/** The style of a block: its `styleId` when known, otherwise the block's default style. */
|
|
6799
|
+
styleOfBlock(type, attrs = {}) {
|
|
6800
|
+
const id = attrs.styleId;
|
|
6801
|
+
if (id && this.styles.get(id)?.kind === "paragraph") return id;
|
|
6802
|
+
return this.defaultStyleFor(type, attrs);
|
|
6803
|
+
}
|
|
6804
|
+
getSnapshot = () => {
|
|
6805
|
+
if (!this.snapshot) {
|
|
6806
|
+
this.snapshot = Object.freeze({
|
|
6807
|
+
styles: Object.freeze(this.list()),
|
|
6808
|
+
defaults: this.defaults,
|
|
6809
|
+
version: this.version
|
|
6810
|
+
});
|
|
6811
|
+
}
|
|
6812
|
+
return this.snapshot;
|
|
6813
|
+
};
|
|
6814
|
+
subscribe = (listener) => {
|
|
6815
|
+
this.listeners.add(listener);
|
|
6816
|
+
listener(this.getSnapshot());
|
|
6817
|
+
return () => {
|
|
6818
|
+
this.listeners.delete(listener);
|
|
6819
|
+
};
|
|
6820
|
+
};
|
|
6821
|
+
toJSON() {
|
|
6822
|
+
return { styles: clone(Array.from(this.styles.values())), defaults: clone(this.defaults) };
|
|
6823
|
+
}
|
|
6824
|
+
// -- Writing --------------------------------------------------------------
|
|
6825
|
+
/** Adds or replaces a style. Throws on an invalid id. */
|
|
6826
|
+
upsert(style) {
|
|
6827
|
+
const stored = this.put(style);
|
|
6828
|
+
this.changed();
|
|
6829
|
+
return stored;
|
|
6830
|
+
}
|
|
6831
|
+
/** Merges `patch` into a style (formats are merged key by key). Returns `undefined` for unknown ids. */
|
|
6832
|
+
update(id, patch) {
|
|
6833
|
+
const current = this.styles.get(id);
|
|
6834
|
+
if (!current) return void 0;
|
|
6835
|
+
const next = {
|
|
6836
|
+
...current,
|
|
6837
|
+
...patch,
|
|
6838
|
+
id,
|
|
6839
|
+
paragraph: patch.paragraph ? { ...current.paragraph, ...patch.paragraph } : current.paragraph,
|
|
6840
|
+
character: patch.character ? { ...current.character, ...patch.character } : current.character
|
|
6841
|
+
};
|
|
6842
|
+
return this.upsert(next);
|
|
6843
|
+
}
|
|
6844
|
+
/**
|
|
6845
|
+
* Removes a style and returns it. Built-in styles cannot be removed. Styles
|
|
6846
|
+
* based on it are rebased onto its own base, and `next`/`linked`
|
|
6847
|
+
* references to it are dropped.
|
|
6848
|
+
*/
|
|
6849
|
+
remove(id) {
|
|
6850
|
+
const gone = this.styles.get(id);
|
|
6851
|
+
if (!gone || gone.builtin) return void 0;
|
|
6852
|
+
this.styles.delete(id);
|
|
6853
|
+
this.styles.forEach((style, key) => {
|
|
6854
|
+
let changed = style;
|
|
6855
|
+
if (style.basedOn === id) {
|
|
6856
|
+
changed = { ...changed, basedOn: gone.basedOn && gone.basedOn !== key ? gone.basedOn : null };
|
|
6857
|
+
}
|
|
6858
|
+
if (style.next === id) changed = { ...changed, next: null };
|
|
6859
|
+
if (style.linked === id) changed = { ...changed, linked: null };
|
|
6860
|
+
if (changed !== style) this.styles.set(key, changed);
|
|
6861
|
+
});
|
|
6862
|
+
this.changed();
|
|
6863
|
+
return gone;
|
|
6864
|
+
}
|
|
6865
|
+
/** Replaces the document defaults. */
|
|
6866
|
+
setDefaults(defaults) {
|
|
6867
|
+
this.defaults = clone(defaults);
|
|
6868
|
+
this.changed();
|
|
6869
|
+
}
|
|
6870
|
+
/** An unused id derived from a display name (`My Style` → `MyStyle`, then `MyStyle1`, …). */
|
|
6871
|
+
newId(name) {
|
|
6872
|
+
let base = name.replace(/[^A-Za-z0-9_-]+/g, "").replace(/^[^A-Za-z]+/, "").slice(0, 56);
|
|
6873
|
+
if (!base) base = "Style";
|
|
6874
|
+
if (!this.styles.has(base)) return base;
|
|
6875
|
+
for (let i = 1; i < 1e5; i++) {
|
|
6876
|
+
const id = `${base}${i}`;
|
|
6877
|
+
if (!this.styles.has(id)) return id;
|
|
6878
|
+
}
|
|
6879
|
+
return `${base}${Date.now()}`;
|
|
6880
|
+
}
|
|
6881
|
+
// -- CSS --------------------------------------------------------------------
|
|
6882
|
+
/** CSS declarations (`property: value`) of a resolved paragraph or character style. */
|
|
6883
|
+
cssDeclarations(id) {
|
|
6884
|
+
const style = this.styles.get(id);
|
|
6885
|
+
if (style?.kind === "character") return characterCSS(this.resolveCharacterStyle(id));
|
|
6886
|
+
const resolved = this.resolve(id);
|
|
6887
|
+
return { ...paragraphCSS(resolved.paragraph), ...characterCSS(resolved.character) };
|
|
6888
|
+
}
|
|
6889
|
+
/**
|
|
6890
|
+
* Declarations for previewing a style in a menu or gallery: font family,
|
|
6891
|
+
* weight, style, color, decoration, case and letter spacing (no sizes,
|
|
6892
|
+
* margins or borders).
|
|
6893
|
+
*/
|
|
6894
|
+
previewDeclarations(id) {
|
|
6895
|
+
return Object.fromEntries(
|
|
6896
|
+
Object.entries(this.cssDeclarations(id)).filter(([property]) => PREVIEW_PROPERTIES.has(property))
|
|
6897
|
+
);
|
|
6898
|
+
}
|
|
6899
|
+
/**
|
|
6900
|
+
* A stylesheet for the styles: `[data-style="Id"]` rules for paragraph
|
|
6901
|
+
* styles (plus the plain element of blocks that use their default style,
|
|
6902
|
+
* e.g. `h2:not([data-style])`), `[data-char-style="Id"]` for character
|
|
6903
|
+
* styles and the defaults on the scope element.
|
|
6904
|
+
*/
|
|
6905
|
+
toCSS(options = {}) {
|
|
6906
|
+
const scope = options.scope ?? ".ProseMirror";
|
|
6907
|
+
const tagFor = options.tagFor ?? defaultTagFor;
|
|
6908
|
+
const rules = [];
|
|
6909
|
+
const rule = (selectors, declarations) => {
|
|
6910
|
+
const body = Object.entries(declarations).map(([property, value]) => `${property}: ${value};`).join(" ");
|
|
6911
|
+
if (body) rules.push(`${selectors.join(", ")} { ${body} }`);
|
|
6912
|
+
};
|
|
6913
|
+
rule([scope], {
|
|
6914
|
+
...paragraphCSS(this.defaults.paragraph ?? {}),
|
|
6915
|
+
...characterCSS(this.defaults.character ?? {})
|
|
6916
|
+
});
|
|
6917
|
+
this.list().forEach((style) => {
|
|
6918
|
+
if (style.kind === "character") {
|
|
6919
|
+
rule([`${scope} [data-char-style="${style.id}"]`], this.cssDeclarations(style.id));
|
|
6920
|
+
return;
|
|
6921
|
+
}
|
|
6922
|
+
const selectors = [`${scope} [data-style="${style.id}"]`];
|
|
6923
|
+
const block = this.resolve(style.id).block;
|
|
6924
|
+
if (this.defaultStyleFor(block.type, block.attrs ?? {}) === style.id) {
|
|
6925
|
+
const tag = tagFor(block);
|
|
6926
|
+
if (tag) selectors.push(`${scope} ${tag}:not([data-style])`);
|
|
6927
|
+
}
|
|
6928
|
+
const resolved = this.resolve(style.id);
|
|
6929
|
+
const own = {
|
|
6930
|
+
...paragraphCSS(withoutDefaults(resolved.paragraph, this.defaults.paragraph)),
|
|
6931
|
+
...characterCSS(withoutDefaults(resolved.character, this.defaults.character))
|
|
6932
|
+
};
|
|
6933
|
+
rule(selectors, own);
|
|
6934
|
+
});
|
|
6935
|
+
return rules.join("\n");
|
|
6936
|
+
}
|
|
6937
|
+
// -- Internals --------------------------------------------------------------
|
|
6938
|
+
put(style) {
|
|
6939
|
+
if (!isValidStyleId(style.id)) throw new Error(`Invalid style id: ${String(style.id)}`);
|
|
6940
|
+
if (style.kind !== "paragraph" && style.kind !== "character") {
|
|
6941
|
+
throw new Error(`Invalid style kind: ${String(style.kind)}`);
|
|
6942
|
+
}
|
|
6943
|
+
const stored = clone({ ...style, name: style.name || style.id });
|
|
6944
|
+
this.styles.set(style.id, stored);
|
|
6945
|
+
return stored;
|
|
6946
|
+
}
|
|
6947
|
+
changed() {
|
|
6948
|
+
this.version++;
|
|
6949
|
+
this.snapshot = null;
|
|
6950
|
+
const snapshot = this.getSnapshot();
|
|
6951
|
+
this.listeners.forEach((listener) => {
|
|
6952
|
+
try {
|
|
6953
|
+
listener(snapshot);
|
|
6954
|
+
} catch (err) {
|
|
6955
|
+
console.error("[StyleRegistry] Error in listener:", err);
|
|
6956
|
+
}
|
|
6957
|
+
});
|
|
6958
|
+
}
|
|
6959
|
+
};
|
|
6960
|
+
function withoutDefaults(format, defaults) {
|
|
6961
|
+
if (!defaults) return format;
|
|
6962
|
+
const out = {};
|
|
6963
|
+
Object.entries(format).forEach(([key, value]) => {
|
|
6964
|
+
if (defaults[key] !== value) out[key] = value;
|
|
6965
|
+
});
|
|
6966
|
+
return out;
|
|
6967
|
+
}
|
|
6968
|
+
function defaultTagFor(block) {
|
|
6969
|
+
if (block.type === "paragraph") return "p";
|
|
6970
|
+
if (block.type === "heading") {
|
|
6971
|
+
const level = Number(block.attrs?.level);
|
|
6972
|
+
return level >= 1 && level <= 6 ? `h${level}` : null;
|
|
6973
|
+
}
|
|
6974
|
+
if (block.type === "codeBlock") return "pre";
|
|
6975
|
+
return null;
|
|
6976
|
+
}
|
|
6977
|
+
function safeCSSValue(value) {
|
|
6978
|
+
if (typeof value !== "string") return void 0;
|
|
6979
|
+
const trimmed = value.trim();
|
|
6980
|
+
if (!trimmed || trimmed.length > 200 || UNSAFE_CSS.test(trimmed)) return void 0;
|
|
6981
|
+
return trimmed;
|
|
6982
|
+
}
|
|
6983
|
+
function paragraphCSS(format) {
|
|
6984
|
+
const out = {};
|
|
6985
|
+
const set = (property, value) => {
|
|
6986
|
+
const safe = safeCSSValue(value);
|
|
6987
|
+
if (safe) out[property] = safe;
|
|
6988
|
+
};
|
|
6989
|
+
set("text-align", format.textAlign);
|
|
6990
|
+
set("line-height", format.lineHeight);
|
|
6991
|
+
set("margin-top", format.spaceBefore);
|
|
6992
|
+
set("margin-bottom", format.spaceAfter);
|
|
6993
|
+
set("margin-left", format.indentLeft);
|
|
6994
|
+
set("margin-right", format.indentRight);
|
|
6995
|
+
set("text-indent", format.indentFirstLine);
|
|
6996
|
+
set("border-left", format.borderLeft);
|
|
6997
|
+
set("padding-left", format.paddingLeft);
|
|
6998
|
+
set("background-color", format.backgroundColor);
|
|
6999
|
+
return out;
|
|
7000
|
+
}
|
|
7001
|
+
function characterCSS(format) {
|
|
7002
|
+
const out = {};
|
|
7003
|
+
const set = (property, value) => {
|
|
7004
|
+
const safe = safeCSSValue(value);
|
|
7005
|
+
if (safe) out[property] = safe;
|
|
7006
|
+
};
|
|
7007
|
+
set("font-family", format.fontFamily);
|
|
7008
|
+
set("font-size", format.fontSize);
|
|
7009
|
+
if (format.bold !== void 0) out["font-weight"] = format.bold ? "700" : "400";
|
|
7010
|
+
if (format.italic !== void 0) out["font-style"] = format.italic ? "italic" : "normal";
|
|
7011
|
+
const lines = [format.underline && "underline", format.strike && "line-through"].filter(Boolean);
|
|
7012
|
+
if (format.underline !== void 0 || format.strike !== void 0) {
|
|
7013
|
+
out["text-decoration-line"] = lines.length ? lines.join(" ") : "none";
|
|
7014
|
+
}
|
|
7015
|
+
set("color", format.color);
|
|
7016
|
+
set("background-color", format.backgroundColor);
|
|
7017
|
+
set("letter-spacing", format.letterSpacing);
|
|
7018
|
+
set("text-transform", format.textTransform);
|
|
7019
|
+
if (format.smallCaps !== void 0) out["font-variant-caps"] = format.smallCaps ? "small-caps" : "normal";
|
|
7020
|
+
return out;
|
|
7021
|
+
}
|
|
7022
|
+
function createStyleRegistry(options = {}) {
|
|
7023
|
+
return new StyleRegistry(options);
|
|
7024
|
+
}
|
|
7025
|
+
|
|
7026
|
+
// src/extensions/paragraph-styles/extension.ts
|
|
7027
|
+
var STYLE_ID_ATTRIBUTE = "styleId";
|
|
7028
|
+
var CHARACTER_STYLE_MARK_NAME = "characterStyle";
|
|
7029
|
+
var paragraphStylesPluginKey = new PluginKey12("paragraphStyles");
|
|
7030
|
+
function getStyleRegistry(editor) {
|
|
7031
|
+
return editor?.storage?.paragraphStyles?.registry ?? null;
|
|
7032
|
+
}
|
|
7033
|
+
function headingLevels(editor) {
|
|
7034
|
+
const heading = editor?.extensionManager?.extensions.find((e) => e.name === "heading");
|
|
7035
|
+
const levels = heading?.options?.levels;
|
|
7036
|
+
return Array.isArray(levels) ? levels : null;
|
|
7037
|
+
}
|
|
7038
|
+
function isParagraphStyleAvailable(editor, registry, id) {
|
|
7039
|
+
const style = registry.get(id);
|
|
7040
|
+
if (!style || style.kind !== "paragraph") return false;
|
|
7041
|
+
const block = registry.resolve(id).block;
|
|
7042
|
+
if (!editor.schema.nodes[block.type]) return false;
|
|
7043
|
+
if (block.type === "heading") {
|
|
7044
|
+
const levels = headingLevels(editor);
|
|
7045
|
+
if (levels && !levels.includes(Number(block.attrs?.level))) return false;
|
|
7046
|
+
}
|
|
7047
|
+
return true;
|
|
7048
|
+
}
|
|
7049
|
+
function getParagraphStyleAt(state, registry, pos = state.selection.from) {
|
|
7050
|
+
const $pos = state.doc.resolve(Math.max(0, Math.min(pos, state.doc.content.size)));
|
|
7051
|
+
const block = $pos.parent;
|
|
7052
|
+
if (!block.isTextblock) return null;
|
|
7053
|
+
return registry.styleOfBlock(block.type.name, block.attrs);
|
|
7054
|
+
}
|
|
7055
|
+
var MARK_FORMAT = {
|
|
7056
|
+
bold: "bold",
|
|
7057
|
+
italic: "italic",
|
|
7058
|
+
underline: "underline",
|
|
7059
|
+
strike: "strike"
|
|
7060
|
+
};
|
|
7061
|
+
function selectionMarks(state) {
|
|
7062
|
+
const { from, to, empty, $from } = state.selection;
|
|
7063
|
+
if (empty) return state.storedMarks ?? $from.marks();
|
|
7064
|
+
let common = null;
|
|
7065
|
+
state.doc.nodesBetween(from, to, (node) => {
|
|
7066
|
+
if (!node.isText) return true;
|
|
7067
|
+
common = common === null ? node.marks : common.filter((m) => m.isInSet(node.marks));
|
|
7068
|
+
return false;
|
|
7069
|
+
});
|
|
7070
|
+
return common ?? $from.marks();
|
|
7071
|
+
}
|
|
7072
|
+
function captureSelectionFormat(state) {
|
|
7073
|
+
const character = {};
|
|
7074
|
+
selectionMarks(state).forEach((mark) => {
|
|
7075
|
+
const name = mark.type.name;
|
|
7076
|
+
if (MARK_FORMAT[name]) character[MARK_FORMAT[name]] = true;
|
|
7077
|
+
if (name === "textStyle") {
|
|
7078
|
+
if (mark.attrs.fontFamily) character.fontFamily = mark.attrs.fontFamily;
|
|
7079
|
+
if (mark.attrs.fontSize) character.fontSize = mark.attrs.fontSize;
|
|
7080
|
+
if (mark.attrs.color) character.color = mark.attrs.color;
|
|
7081
|
+
}
|
|
7082
|
+
if (name === "highlight") character.backgroundColor = mark.attrs.color || "#fef08a";
|
|
7083
|
+
});
|
|
7084
|
+
const paragraph = {};
|
|
7085
|
+
const align = state.selection.$from.parent.attrs?.textAlign;
|
|
7086
|
+
if (align && align !== "left") paragraph.textAlign = align;
|
|
7087
|
+
return { paragraph, character };
|
|
7088
|
+
}
|
|
7089
|
+
function carriedAttributes(node, type) {
|
|
7090
|
+
const spec = type.spec.attrs ?? {};
|
|
7091
|
+
return Object.fromEntries(Object.entries(node.attrs).filter(([key]) => key in spec));
|
|
7092
|
+
}
|
|
7093
|
+
function applyStyleToBlock(tr, pos, id, registry) {
|
|
7094
|
+
const node = tr.doc.nodeAt(pos);
|
|
7095
|
+
if (!node || !node.isTextblock) return false;
|
|
7096
|
+
const resolved = registry.resolve(id);
|
|
7097
|
+
const type = tr.doc.type.schema.nodes[resolved.block.type];
|
|
7098
|
+
if (!type) return false;
|
|
7099
|
+
const blockAttrs = resolved.block.attrs ?? {};
|
|
7100
|
+
const isDefault = registry.defaultStyleFor(resolved.block.type, blockAttrs) === id;
|
|
7101
|
+
const attrs = { ...carriedAttributes(node, type), ...blockAttrs };
|
|
7102
|
+
if (STYLE_ID_ATTRIBUTE in (type.spec.attrs ?? {})) attrs[STYLE_ID_ATTRIBUTE] = isDefault ? null : id;
|
|
7103
|
+
if ("textAlign" in (type.spec.attrs ?? {})) {
|
|
7104
|
+
const fallback = type.spec.attrs.textAlign.default ?? null;
|
|
7105
|
+
attrs.textAlign = fallback === null ? null : resolved.paragraph.textAlign ?? fallback;
|
|
7106
|
+
}
|
|
7107
|
+
if (node.type === type && Object.entries(attrs).every(([k, v]) => node.attrs[k] === v)) return false;
|
|
7108
|
+
try {
|
|
7109
|
+
tr.setNodeMarkup(pos, type, attrs);
|
|
7110
|
+
} catch {
|
|
7111
|
+
try {
|
|
7112
|
+
tr.setBlockType(pos + 1, pos + 1, type, attrs);
|
|
7113
|
+
} catch {
|
|
7114
|
+
return false;
|
|
7115
|
+
}
|
|
7116
|
+
}
|
|
7117
|
+
return true;
|
|
7118
|
+
}
|
|
7119
|
+
function selectedBlocks(state) {
|
|
7120
|
+
const { from, to } = state.selection;
|
|
7121
|
+
const positions = [];
|
|
7122
|
+
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
7123
|
+
if (node.isTextblock) {
|
|
7124
|
+
positions.push(pos);
|
|
7125
|
+
return false;
|
|
7126
|
+
}
|
|
7127
|
+
return true;
|
|
7128
|
+
});
|
|
7129
|
+
if (positions.length === 0 && state.selection.$from.parent.isTextblock) {
|
|
7130
|
+
positions.push(state.selection.$from.before());
|
|
7131
|
+
}
|
|
7132
|
+
return positions;
|
|
7133
|
+
}
|
|
7134
|
+
function setParagraphStyle(tr, state, id, registry) {
|
|
7135
|
+
const start2 = tr.steps.length;
|
|
7136
|
+
selectedBlocks(state).forEach((pos) => {
|
|
7137
|
+
applyStyleToBlock(tr, tr.mapping.slice(start2).map(pos), id, registry);
|
|
7138
|
+
});
|
|
7139
|
+
}
|
|
7140
|
+
function nextStyleTransaction(transactions, oldState, newState, registry) {
|
|
7141
|
+
if (transactions.length !== 1) return null;
|
|
7142
|
+
const [tr] = transactions;
|
|
7143
|
+
if (!tr.docChanged || tr.getMeta("uiEvent") || tr.getMeta("history$") || tr.getMeta("y-sync$")) {
|
|
7144
|
+
return null;
|
|
7145
|
+
}
|
|
7146
|
+
const old = oldState.selection;
|
|
7147
|
+
const $old = old.$from;
|
|
7148
|
+
if (!old.empty || !$old.parent.isTextblock || $old.parent.type.spec.code) return null;
|
|
7149
|
+
if ($old.parentOffset !== $old.parent.content.size) return null;
|
|
7150
|
+
if (newState.doc.content.size !== oldState.doc.content.size + 2) return null;
|
|
7151
|
+
const $new = newState.selection.$from;
|
|
7152
|
+
if (!newState.selection.empty || !$new.parent.isTextblock || $new.parent.content.size !== 0) return null;
|
|
7153
|
+
const depth = $new.depth;
|
|
7154
|
+
const index = $new.index(depth - 1);
|
|
7155
|
+
if (index === 0 || $new.depth !== $old.depth) return null;
|
|
7156
|
+
const previous = $new.node(depth - 1).child(index - 1);
|
|
7157
|
+
if (!previous.isTextblock || !previous.eq($old.parent)) return null;
|
|
7158
|
+
const style = registry.styleOfBlock($old.parent.type.name, $old.parent.attrs);
|
|
7159
|
+
if (!style) return null;
|
|
7160
|
+
const next = registry.nextStyleId(style);
|
|
7161
|
+
const current = registry.styleOfBlock($new.parent.type.name, $new.parent.attrs);
|
|
7162
|
+
const target = registry.resolve(next).block;
|
|
7163
|
+
const typeMatches = $new.parent.type.name === target.type && Object.entries(target.attrs ?? {}).every(([k, v]) => $new.parent.attrs[k] === v);
|
|
7164
|
+
if (current === next && typeMatches) return null;
|
|
7165
|
+
const out = newState.tr;
|
|
7166
|
+
if (!applyStyleToBlock(out, $new.before(), next, registry)) return null;
|
|
7167
|
+
return out;
|
|
7168
|
+
}
|
|
7169
|
+
var CharacterStyle = Mark5.create({
|
|
7170
|
+
name: CHARACTER_STYLE_MARK_NAME,
|
|
7171
|
+
addAttributes() {
|
|
7172
|
+
return {
|
|
7173
|
+
[STYLE_ID_ATTRIBUTE]: {
|
|
7174
|
+
default: null,
|
|
7175
|
+
parseHTML: (el) => {
|
|
7176
|
+
const id = el.getAttribute("data-char-style");
|
|
7177
|
+
return isValidStyleId(id) ? id : null;
|
|
7178
|
+
},
|
|
7179
|
+
renderHTML: (attrs) => attrs[STYLE_ID_ATTRIBUTE] ? { "data-char-style": attrs[STYLE_ID_ATTRIBUTE] } : {}
|
|
7180
|
+
}
|
|
7181
|
+
};
|
|
7182
|
+
},
|
|
7183
|
+
parseHTML() {
|
|
7184
|
+
return [{ tag: "span[data-char-style]" }];
|
|
7185
|
+
},
|
|
7186
|
+
renderHTML({ HTMLAttributes }) {
|
|
7187
|
+
return ["span", mergeAttributes7(HTMLAttributes), 0];
|
|
7188
|
+
}
|
|
7189
|
+
});
|
|
7190
|
+
var ParagraphStyles = Extension13.create({
|
|
7191
|
+
name: "paragraphStyles",
|
|
7192
|
+
addOptions() {
|
|
7193
|
+
return {
|
|
7194
|
+
registry: null,
|
|
7195
|
+
types: ["paragraph", "heading", "codeBlock"],
|
|
7196
|
+
injectCSS: true,
|
|
7197
|
+
cssScope: ".ProseMirror",
|
|
7198
|
+
cssNonce: void 0,
|
|
7199
|
+
linkedCharacterStyles: true
|
|
7200
|
+
};
|
|
7201
|
+
},
|
|
7202
|
+
addStorage() {
|
|
7203
|
+
return { registry: this.options.registry ?? createStyleRegistry() };
|
|
7204
|
+
},
|
|
7205
|
+
addExtensions() {
|
|
7206
|
+
return [CharacterStyle];
|
|
7207
|
+
},
|
|
7208
|
+
addGlobalAttributes() {
|
|
7209
|
+
return [
|
|
7210
|
+
{
|
|
7211
|
+
types: this.options.types,
|
|
7212
|
+
attributes: {
|
|
7213
|
+
[STYLE_ID_ATTRIBUTE]: {
|
|
7214
|
+
default: null,
|
|
7215
|
+
keepOnSplit: true,
|
|
7216
|
+
parseHTML: (el) => {
|
|
7217
|
+
const id = el.getAttribute("data-style");
|
|
7218
|
+
return isValidStyleId(id) ? id : null;
|
|
7219
|
+
},
|
|
7220
|
+
renderHTML: (attrs) => {
|
|
7221
|
+
const id = attrs[STYLE_ID_ATTRIBUTE];
|
|
7222
|
+
return isValidStyleId(id) ? { "data-style": id, class: `pixerate-style-${id}` } : {};
|
|
7223
|
+
}
|
|
7224
|
+
}
|
|
7225
|
+
}
|
|
7226
|
+
}
|
|
7227
|
+
];
|
|
7228
|
+
},
|
|
7229
|
+
addCommands() {
|
|
7230
|
+
const registry = () => this.storage.registry;
|
|
7231
|
+
const editor = () => this.editor;
|
|
7232
|
+
return {
|
|
7233
|
+
setParagraphStyle: (id) => ({ state, tr, dispatch }) => {
|
|
7234
|
+
const reg = registry();
|
|
7235
|
+
if (!isParagraphStyleAvailable(editor(), reg, id)) return false;
|
|
7236
|
+
const { $from, $to, empty } = state.selection;
|
|
7237
|
+
const linked = this.options.linkedCharacterStyles ? reg.linkedCharacterStyle(id) : void 0;
|
|
7238
|
+
const partial = !empty && $from.sameParent($to) && $from.parent.isTextblock && ($from.parentOffset > 0 || $to.parentOffset < $from.parent.content.size);
|
|
7239
|
+
const markType = state.schema.marks[CHARACTER_STYLE_MARK_NAME];
|
|
7240
|
+
if (partial && linked && markType) {
|
|
7241
|
+
if (dispatch) {
|
|
7242
|
+
tr.addMark($from.pos, $to.pos, markType.create({ [STYLE_ID_ATTRIBUTE]: linked.id }));
|
|
7243
|
+
}
|
|
7244
|
+
return true;
|
|
7245
|
+
}
|
|
7246
|
+
if (dispatch) setParagraphStyle(tr, state, id, reg);
|
|
7247
|
+
return true;
|
|
7248
|
+
},
|
|
7249
|
+
clearParagraphStyle: () => ({ commands }) => commands.setParagraphStyle(NORMAL_STYLE_ID),
|
|
7250
|
+
setCharacterStyle: (id) => ({ commands }) => {
|
|
7251
|
+
if (registry().get(id)?.kind !== "character") return false;
|
|
7252
|
+
return commands.setMark(CHARACTER_STYLE_MARK_NAME, { [STYLE_ID_ATTRIBUTE]: id });
|
|
7253
|
+
},
|
|
7254
|
+
unsetCharacterStyle: () => ({ commands }) => commands.unsetMark(CHARACTER_STYLE_MARK_NAME),
|
|
7255
|
+
updateParagraphStyleFromSelection: (id) => ({ state, dispatch }) => {
|
|
7256
|
+
const reg = registry();
|
|
7257
|
+
const target = id ?? getParagraphStyleAt(state, reg);
|
|
7258
|
+
const style = target ? reg.get(target) : void 0;
|
|
7259
|
+
if (!style || style.kind !== "paragraph") return false;
|
|
7260
|
+
if (dispatch) {
|
|
7261
|
+
const captured = captureSelectionFormat(state);
|
|
7262
|
+
reg.update(style.id, captured);
|
|
7263
|
+
}
|
|
7264
|
+
return true;
|
|
7265
|
+
},
|
|
7266
|
+
createParagraphStyleFromSelection: (name, options = {}) => ({ state, tr, dispatch }) => {
|
|
7267
|
+
const reg = registry();
|
|
7268
|
+
const trimmed = name.trim();
|
|
7269
|
+
if (!trimmed) return false;
|
|
7270
|
+
const id = options.id ?? reg.newId(trimmed);
|
|
7271
|
+
if (!isValidStyleId(id) || reg.get(id)) return false;
|
|
7272
|
+
const basedOn = options.basedOn === void 0 ? getParagraphStyleAt(state, reg) : options.basedOn;
|
|
7273
|
+
if (dispatch) {
|
|
7274
|
+
const captured = captureSelectionFormat(state);
|
|
7275
|
+
const definition = {
|
|
7276
|
+
id,
|
|
7277
|
+
name: trimmed,
|
|
7278
|
+
kind: "paragraph",
|
|
7279
|
+
basedOn: basedOn ?? NORMAL_STYLE_ID,
|
|
7280
|
+
paragraph: captured.paragraph,
|
|
7281
|
+
character: captured.character,
|
|
7282
|
+
priority: 50,
|
|
7283
|
+
quick: true
|
|
7284
|
+
};
|
|
7285
|
+
reg.upsert(definition);
|
|
7286
|
+
if (options.apply !== false) setParagraphStyle(tr, state, id, reg);
|
|
7287
|
+
}
|
|
7288
|
+
return true;
|
|
7289
|
+
}
|
|
7290
|
+
};
|
|
7291
|
+
},
|
|
7292
|
+
addProseMirrorPlugins() {
|
|
7293
|
+
const registry = this.storage.registry;
|
|
7294
|
+
return [
|
|
7295
|
+
new Plugin15({
|
|
7296
|
+
key: paragraphStylesPluginKey,
|
|
7297
|
+
appendTransaction: (transactions, oldState, newState) => nextStyleTransaction(transactions, oldState, newState, registry)
|
|
7298
|
+
})
|
|
7299
|
+
];
|
|
7300
|
+
},
|
|
7301
|
+
onBeforeCreate() {
|
|
7302
|
+
if (!this.options.injectCSS || typeof document === "undefined") return;
|
|
7303
|
+
const element = document.createElement("style");
|
|
7304
|
+
element.setAttribute("data-pixerate-paragraph-styles", "");
|
|
7305
|
+
if (this.options.cssNonce) element.nonce = this.options.cssNonce;
|
|
7306
|
+
document.head.appendChild(element);
|
|
7307
|
+
const scope = this.options.cssScope;
|
|
7308
|
+
const unsubscribe = this.storage.registry.subscribe(() => {
|
|
7309
|
+
element.textContent = this.storage.registry.toCSS({ scope });
|
|
7310
|
+
});
|
|
7311
|
+
this.storage.cleanup = () => {
|
|
7312
|
+
unsubscribe();
|
|
7313
|
+
element.remove();
|
|
7314
|
+
};
|
|
7315
|
+
},
|
|
7316
|
+
onDestroy() {
|
|
7317
|
+
this.storage.cleanup?.();
|
|
7318
|
+
}
|
|
7319
|
+
});
|
|
7320
|
+
var EMPTY_STYLES = Object.freeze({
|
|
7321
|
+
gallery: [],
|
|
7322
|
+
styles: [],
|
|
7323
|
+
characterStyles: [],
|
|
7324
|
+
currentStyleId: null,
|
|
7325
|
+
version: -1
|
|
7326
|
+
});
|
|
7327
|
+
function createParagraphStylesStore(editor) {
|
|
7328
|
+
const registry = getStyleRegistry(editor);
|
|
7329
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
7330
|
+
let snapshot = EMPTY_STYLES;
|
|
7331
|
+
let unsubscribeRegistry = null;
|
|
7332
|
+
const compute = () => {
|
|
7333
|
+
if (!editor || editor.isDestroyed || !registry) return EMPTY_STYLES;
|
|
7334
|
+
const { version } = registry.getSnapshot();
|
|
7335
|
+
const currentStyleId = getParagraphStyleAt(editor.state, registry);
|
|
7336
|
+
if (snapshot.version === version && snapshot.currentStyleId === currentStyleId) return snapshot;
|
|
7337
|
+
if (snapshot.version === version) return { ...snapshot, currentStyleId };
|
|
7338
|
+
const styles = registry.list("paragraph").filter((style) => !style.hidden && isParagraphStyleAvailable(editor, registry, style.id));
|
|
7339
|
+
return {
|
|
7340
|
+
gallery: styles.filter((style) => style.quick),
|
|
7341
|
+
styles,
|
|
7342
|
+
characterStyles: registry.list("character").filter((style) => !style.hidden),
|
|
7343
|
+
currentStyleId,
|
|
7344
|
+
version
|
|
7345
|
+
};
|
|
7346
|
+
};
|
|
7347
|
+
const update = () => {
|
|
7348
|
+
const next = compute();
|
|
7349
|
+
if (next !== snapshot) {
|
|
7350
|
+
snapshot = next;
|
|
7351
|
+
listeners.forEach((listener) => listener());
|
|
7352
|
+
}
|
|
7353
|
+
};
|
|
7354
|
+
const detach = () => {
|
|
7355
|
+
editor?.off("transaction", update);
|
|
7356
|
+
unsubscribeRegistry?.();
|
|
7357
|
+
unsubscribeRegistry = null;
|
|
7358
|
+
};
|
|
7359
|
+
return {
|
|
7360
|
+
getSnapshot: () => {
|
|
7361
|
+
if (!listeners.size) snapshot = compute();
|
|
7362
|
+
return snapshot;
|
|
7363
|
+
},
|
|
7364
|
+
subscribe(listener) {
|
|
7365
|
+
if (!listeners.size) {
|
|
7366
|
+
snapshot = compute();
|
|
7367
|
+
editor?.on("transaction", update);
|
|
7368
|
+
unsubscribeRegistry = registry ? registry.subscribe(update) : null;
|
|
7369
|
+
}
|
|
7370
|
+
listeners.add(listener);
|
|
7371
|
+
return () => {
|
|
7372
|
+
listeners.delete(listener);
|
|
7373
|
+
if (!listeners.size) detach();
|
|
7374
|
+
};
|
|
7375
|
+
},
|
|
7376
|
+
destroy() {
|
|
7377
|
+
detach();
|
|
7378
|
+
listeners.clear();
|
|
7379
|
+
}
|
|
7380
|
+
};
|
|
7381
|
+
}
|
|
7382
|
+
|
|
6472
7383
|
// src/extensions/rich-text-preset.ts
|
|
6473
7384
|
var resolveExt3 = (mod, name) => mod?.[name] || mod?.default?.[name] || mod?.default?.default || mod?.default || mod;
|
|
6474
7385
|
var StarterKit = resolveExt3(_StarterKit, "StarterKit");
|
|
@@ -6491,7 +7402,7 @@ function createRichTextPreset(options = {}) {
|
|
|
6491
7402
|
openLinksOnClick = false,
|
|
6492
7403
|
enableSmilies = true,
|
|
6493
7404
|
enableColorHighlighter = true,
|
|
6494
|
-
headingLevels = [1, 2, 3, 4]
|
|
7405
|
+
headingLevels: headingLevels2 = [1, 2, 3, 4]
|
|
6495
7406
|
} = options;
|
|
6496
7407
|
const extensions2 = [
|
|
6497
7408
|
StarterKit.configure({
|
|
@@ -6506,7 +7417,7 @@ function createRichTextPreset(options = {}) {
|
|
|
6506
7417
|
}
|
|
6507
7418
|
},
|
|
6508
7419
|
heading: {
|
|
6509
|
-
levels:
|
|
7420
|
+
levels: headingLevels2,
|
|
6510
7421
|
HTMLAttributes: {
|
|
6511
7422
|
class: "font-bold tracking-tight"
|
|
6512
7423
|
}
|
|
@@ -6668,6 +7579,9 @@ function createRichTextPreset(options = {}) {
|
|
|
6668
7579
|
if (options.findReplace) {
|
|
6669
7580
|
extensions2.push(FindReplace.configure(optionObject(options.findReplace)));
|
|
6670
7581
|
}
|
|
7582
|
+
if (options.paragraphStyles) {
|
|
7583
|
+
extensions2.push(ParagraphStyles.configure(optionObject(options.paragraphStyles)));
|
|
7584
|
+
}
|
|
6671
7585
|
return extensions2;
|
|
6672
7586
|
}
|
|
6673
7587
|
|
|
@@ -6820,6 +7734,8 @@ export {
|
|
|
6820
7734
|
ColorHighlighter,
|
|
6821
7735
|
FontSize,
|
|
6822
7736
|
Mention,
|
|
7737
|
+
getMentionNodes,
|
|
7738
|
+
setMentionRoleAt,
|
|
6823
7739
|
createMentionExtension,
|
|
6824
7740
|
Markdown2 as Markdown,
|
|
6825
7741
|
imagePastePluginKey,
|
|
@@ -6929,8 +7845,24 @@ export {
|
|
|
6929
7845
|
FIND_OPTION_TOGGLES,
|
|
6930
7846
|
formatFindStatus,
|
|
6931
7847
|
FindReplace,
|
|
7848
|
+
NORMAL_STYLE_ID,
|
|
7849
|
+
isValidStyleId,
|
|
7850
|
+
DEFAULT_STYLES,
|
|
7851
|
+
StyleRegistry,
|
|
7852
|
+
safeCSSValue,
|
|
7853
|
+
createStyleRegistry,
|
|
7854
|
+
STYLE_ID_ATTRIBUTE,
|
|
7855
|
+
CHARACTER_STYLE_MARK_NAME,
|
|
7856
|
+
paragraphStylesPluginKey,
|
|
7857
|
+
getStyleRegistry,
|
|
7858
|
+
isParagraphStyleAvailable,
|
|
7859
|
+
getParagraphStyleAt,
|
|
7860
|
+
captureSelectionFormat,
|
|
7861
|
+
CharacterStyle,
|
|
7862
|
+
ParagraphStyles,
|
|
7863
|
+
createParagraphStylesStore,
|
|
6932
7864
|
createRichTextPreset,
|
|
6933
7865
|
createFindReplaceCommands,
|
|
6934
7866
|
validateFindPattern
|
|
6935
7867
|
};
|
|
6936
|
-
//# sourceMappingURL=chunk-
|
|
7868
|
+
//# sourceMappingURL=chunk-IXHSYOVY.js.map
|