@notum-cz/strapi-plugin-tiptap-editor 1.0.1 → 1.0.2
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 +85 -55
- package/dist/_chunks/{RichTextInput-BZQ2iVqa.mjs → RichTextInput-COGVRWOW.mjs} +786 -596
- package/dist/_chunks/RichTextInput-COGVRWOW.mjs.map +1 -0
- package/dist/_chunks/{RichTextInput-BlxoJMa2.js → RichTextInput-Wc2q__HY.js} +785 -595
- package/dist/_chunks/RichTextInput-Wc2q__HY.js.map +1 -0
- package/dist/admin/index.js +23 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +23 -1
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/src/components/BaseTiptapInput.d.ts +1 -0
- package/dist/admin/src/components/EditorErrorBoundary.d.ts +23 -0
- package/dist/admin/src/components/FeatureGuard.d.ts +15 -0
- package/dist/admin/src/components/PresetSelect.d.ts +7 -0
- package/dist/admin/src/extensions/Heading.d.ts +1 -0
- package/dist/admin/src/fields/richTextField.d.ts +18 -0
- package/dist/admin/src/hooks/usePresetConfig.d.ts +6 -0
- package/dist/admin/src/utils/buildExtensions.d.ts +3 -0
- package/dist/server/index.js +154 -6
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +153 -6
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/config/index.d.ts +7 -4
- package/dist/server/src/controllers/index.d.ts +8 -1
- package/dist/server/src/controllers/preset.d.ts +8 -0
- package/dist/server/src/index.d.ts +43 -5
- package/dist/server/src/routes/index.d.ts +15 -1
- package/dist/server/src/services/index.d.ts +9 -1
- package/dist/server/src/services/preset.d.ts +10 -0
- package/dist/shared/types.d.ts +54 -0
- package/package.json +11 -3
- package/dist/_chunks/AccentCursive-CpAPpH9C.mjs +0 -3383
- package/dist/_chunks/AccentCursive-CpAPpH9C.mjs.map +0 -1
- package/dist/_chunks/AccentCursive-D6sTlhub.js +0 -3384
- package/dist/_chunks/AccentCursive-D6sTlhub.js.map +0 -1
- package/dist/_chunks/FormattedHeadingInput-DycgfIze.mjs +0 -101
- package/dist/_chunks/FormattedHeadingInput-DycgfIze.mjs.map +0 -1
- package/dist/_chunks/FormattedHeadingInput-FFjiRSEJ.js +0 -101
- package/dist/_chunks/FormattedHeadingInput-FFjiRSEJ.js.map +0 -1
- package/dist/_chunks/RichTextInput-BZQ2iVqa.mjs.map +0 -1
- package/dist/_chunks/RichTextInput-BbbQxPc-.js +0 -4414
- package/dist/_chunks/RichTextInput-BbbQxPc-.js.map +0 -1
- package/dist/_chunks/RichTextInput-BjLR2pi0.js +0 -4416
- package/dist/_chunks/RichTextInput-BjLR2pi0.js.map +0 -1
- package/dist/_chunks/RichTextInput-BlxoJMa2.js.map +0 -1
- package/dist/_chunks/RichTextInput-Bm3X8fR2.mjs +0 -4400
- package/dist/_chunks/RichTextInput-Bm3X8fR2.mjs.map +0 -1
- package/dist/_chunks/RichTextInput-Bms-gSvK.js +0 -4407
- package/dist/_chunks/RichTextInput-Bms-gSvK.js.map +0 -1
- package/dist/_chunks/RichTextInput-BtNjPJRN.mjs +0 -4400
- package/dist/_chunks/RichTextInput-BtNjPJRN.mjs.map +0 -1
- package/dist/_chunks/RichTextInput-Bw3tcXfp.js +0 -4407
- package/dist/_chunks/RichTextInput-Bw3tcXfp.js.map +0 -1
- package/dist/_chunks/RichTextInput-CsgNpoxq.mjs +0 -4409
- package/dist/_chunks/RichTextInput-CsgNpoxq.mjs.map +0 -1
- package/dist/_chunks/RichTextInput-CwTvEMda.js +0 -4407
- package/dist/_chunks/RichTextInput-CwTvEMda.js.map +0 -1
- package/dist/_chunks/RichTextInput-DG-36krM.js +0 -1181
- package/dist/_chunks/RichTextInput-DG-36krM.js.map +0 -1
- package/dist/_chunks/RichTextInput-DLac-zNQ.mjs +0 -4400
- package/dist/_chunks/RichTextInput-DLac-zNQ.mjs.map +0 -1
- package/dist/_chunks/RichTextInput-DSXttrvi.js +0 -4407
- package/dist/_chunks/RichTextInput-DSXttrvi.js.map +0 -1
- package/dist/_chunks/RichTextInput-DeJ6Exto.mjs +0 -4400
- package/dist/_chunks/RichTextInput-DeJ6Exto.mjs.map +0 -1
- package/dist/_chunks/RichTextInput-DgT88AkO.mjs +0 -1175
- package/dist/_chunks/RichTextInput-DgT88AkO.mjs.map +0 -1
- package/dist/_chunks/RichTextInput-DlMaDJQF.mjs +0 -4400
- package/dist/_chunks/RichTextInput-DlMaDJQF.mjs.map +0 -1
- package/dist/_chunks/RichTextInput-DtaYdjCs.mjs +0 -4400
- package/dist/_chunks/RichTextInput-DtaYdjCs.mjs.map +0 -1
- package/dist/_chunks/RichTextInput-YTKXo5oq.js +0 -4407
- package/dist/_chunks/RichTextInput-YTKXo5oq.js.map +0 -1
- package/dist/_chunks/RichTextInput-tmg-oMJk.mjs +0 -4407
- package/dist/_chunks/RichTextInput-tmg-oMJk.mjs.map +0 -1
- package/dist/_chunks/RichTextInput-umhMsI5o.js +0 -4407
- package/dist/_chunks/RichTextInput-umhMsI5o.js.map +0 -1
- package/dist/admin/src/components/FormattedHeadingInput.d.ts +0 -4
- package/dist/admin/src/extensions/AccentCursive.d.ts +0 -18
- package/dist/admin/src/fields/formattedHeadingField.d.ts +0 -20
- package/dist/admin/src/pluginId.d.ts +0 -1
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment as Fragment$1 } from "react/jsx-runtime";
|
|
2
|
-
import
|
|
2
|
+
import React, { forwardRef, Component, useState, useRef, useEffect, useMemo } from "react";
|
|
3
|
+
import { Field, Box, Status, Typography, Flex, Button, Tooltip, Dialog, TextInput, SingleSelect, SingleSelectOption } from "@strapi/design-system";
|
|
3
4
|
import { EditorContent, useEditor, useEditorState } from "@tiptap/react";
|
|
4
5
|
import styled from "styled-components";
|
|
5
|
-
import
|
|
6
|
-
import { useField } from "@strapi/strapi/admin";
|
|
7
|
-
import StarterKit from "@tiptap/starter-kit";
|
|
6
|
+
import { useField, useFetchClient } from "@strapi/strapi/admin";
|
|
8
7
|
import { Quotes, Code, NumberList, BulletList, StrikeThrough, Underline, Italic, Bold, Link, GridNine } from "@strapi/icons";
|
|
9
8
|
import { RemoveMarkStep, Transform, liftTarget, joinPoint, canSplit, ReplaceStep, ReplaceAroundStep, canJoin } from "@tiptap/pm/transform";
|
|
10
9
|
import { createParagraphNear as createParagraphNear$1, deleteSelection as deleteSelection$1, exitCode as exitCode$1, joinUp as joinUp$1, joinDown as joinDown$1, joinBackward as joinBackward$1, joinForward as joinForward$1, joinTextblockBackward as joinTextblockBackward$1, joinTextblockForward as joinTextblockForward$1, lift as lift$1, liftEmptyBlock as liftEmptyBlock$1, newlineInCode as newlineInCode$1, selectNodeBackward as selectNodeBackward$1, selectNodeForward as selectNodeForward$1, selectParentNode as selectParentNode$1, selectTextblockEnd as selectTextblockEnd$1, selectTextblockStart as selectTextblockStart$1, setBlockType, wrapIn as wrapIn$1 } from "@tiptap/pm/commands";
|
|
@@ -13,13 +12,14 @@ import { Fragment, Slice, Node, Schema, DOMParser } from "@tiptap/pm/model";
|
|
|
13
12
|
import { liftListItem as liftListItem$1, sinkListItem as sinkListItem$1, wrapInList as wrapInList$1 } from "@tiptap/pm/schema-list";
|
|
14
13
|
import { DecorationSet, Decoration } from "@tiptap/pm/view";
|
|
15
14
|
import "@tiptap/pm/keymap";
|
|
15
|
+
import StarterKit from "@tiptap/starter-kit";
|
|
16
16
|
import Superscript from "@tiptap/extension-superscript";
|
|
17
17
|
import Subscript from "@tiptap/extension-subscript";
|
|
18
18
|
import { TableKit } from "@tiptap/extension-table";
|
|
19
|
+
import TextAlign from "@tiptap/extension-text-align";
|
|
19
20
|
import { dropCursor } from "@tiptap/pm/dropcursor";
|
|
20
21
|
import { gapCursor } from "@tiptap/pm/gapcursor";
|
|
21
22
|
import { history, redo, undo } from "@tiptap/pm/history";
|
|
22
|
-
import TextAlign from "@tiptap/extension-text-align";
|
|
23
23
|
const TiptapInputStyles = styled.div`
|
|
24
24
|
.editor-toolbar {
|
|
25
25
|
margin-bottom: 0.25rem;
|
|
@@ -207,7 +207,7 @@ const TiptapInputStyles = styled.div`
|
|
|
207
207
|
}
|
|
208
208
|
`;
|
|
209
209
|
const BaseTiptapInput = forwardRef(
|
|
210
|
-
({ hint, disabled = false, labelAction, label, name, required = false, editor, field, children }, forwardedRef) => {
|
|
210
|
+
({ hint, disabled = false, labelAction, label, name, required = false, editor, field, children, noPresetConfigured }, forwardedRef) => {
|
|
211
211
|
const borderColor = field.error ? "danger600" : "neutral200";
|
|
212
212
|
const background = disabled ? "neutral200" : "neutral100";
|
|
213
213
|
return /* @__PURE__ */ jsxs(Field.Root, { name, id: name, hint, error: field.error, required, children: [
|
|
@@ -224,6 +224,7 @@ const BaseTiptapInput = forwardRef(
|
|
|
224
224
|
paddingLeft: 0,
|
|
225
225
|
paddingRight: 0,
|
|
226
226
|
children: [
|
|
227
|
+
noPresetConfigured && /* @__PURE__ */ jsx(Box, { paddingLeft: 2, paddingRight: 2, paddingTop: 2, children: /* @__PURE__ */ jsx(Status, { variant: "secondary", showBullet: false, children: /* @__PURE__ */ jsx(Typography, { variant: "pi", children: "No editor preset configured — showing minimal editor" }) }) }),
|
|
227
228
|
/* @__PURE__ */ jsx(Box, { className: "editor-toolbar", paddingLeft: 2, paddingRight: 2, paddingBottom: 2, children: /* @__PURE__ */ jsx(Flex, { gap: 1, wrap: "wrap", children }) }),
|
|
228
229
|
/* @__PURE__ */ jsx(
|
|
229
230
|
Box,
|
|
@@ -245,6 +246,71 @@ const BaseTiptapInput = forwardRef(
|
|
|
245
246
|
] });
|
|
246
247
|
}
|
|
247
248
|
);
|
|
249
|
+
class EditorErrorBoundary extends Component {
|
|
250
|
+
state = { hasError: false, error: null };
|
|
251
|
+
static getDerivedStateFromError(error) {
|
|
252
|
+
return { hasError: true, error };
|
|
253
|
+
}
|
|
254
|
+
componentDidCatch(error, errorInfo) {
|
|
255
|
+
console.error("[TiptapEditor] Editor crashed:", error, errorInfo);
|
|
256
|
+
}
|
|
257
|
+
handleRetry = () => {
|
|
258
|
+
this.setState({ hasError: false, error: null });
|
|
259
|
+
};
|
|
260
|
+
render() {
|
|
261
|
+
if (this.state.hasError) {
|
|
262
|
+
return /* @__PURE__ */ jsxs(Box, { padding: 4, background: "danger100", hasRadius: true, children: [
|
|
263
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "danger700", children: "The editor encountered an error and could not render." }),
|
|
264
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "S", onClick: this.handleRetry, children: "Retry" }) })
|
|
265
|
+
] });
|
|
266
|
+
}
|
|
267
|
+
return this.props.children;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
const MINIMAL_PRESET_CONFIG = {
|
|
271
|
+
bold: true,
|
|
272
|
+
italic: true
|
|
273
|
+
};
|
|
274
|
+
const isPlainObject$1 = (value) => {
|
|
275
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
276
|
+
const prototype = Object.getPrototypeOf(value);
|
|
277
|
+
return prototype === Object.prototype || prototype === null;
|
|
278
|
+
};
|
|
279
|
+
const isFeatureEnabled = (value) => {
|
|
280
|
+
if (value === void 0) {
|
|
281
|
+
return true;
|
|
282
|
+
}
|
|
283
|
+
if (typeof value === "boolean") {
|
|
284
|
+
return value;
|
|
285
|
+
}
|
|
286
|
+
if (!isPlainObject$1(value)) {
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
const obj = value;
|
|
290
|
+
if (typeof obj.enabled === "boolean") {
|
|
291
|
+
return obj.enabled;
|
|
292
|
+
}
|
|
293
|
+
if (typeof obj.disabled === "boolean") {
|
|
294
|
+
return !obj.disabled;
|
|
295
|
+
}
|
|
296
|
+
return true;
|
|
297
|
+
};
|
|
298
|
+
const getFeatureOptions = (value, defaults) => {
|
|
299
|
+
if (value === false) {
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
if (!isPlainObject$1(value)) {
|
|
303
|
+
return defaults;
|
|
304
|
+
}
|
|
305
|
+
const { enabled: _e, disabled: _d, ...rest } = value;
|
|
306
|
+
return { ...defaults, ...rest };
|
|
307
|
+
};
|
|
308
|
+
function FeatureGuard({ featureValue, children }) {
|
|
309
|
+
if (!isFeatureEnabled(featureValue)) {
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
return children;
|
|
313
|
+
}
|
|
248
314
|
function tiptapContent(text) {
|
|
249
315
|
return {
|
|
250
316
|
type: "doc",
|
|
@@ -275,10 +341,10 @@ function parseJSONContent(value, defaultValue) {
|
|
|
275
341
|
`);
|
|
276
342
|
}
|
|
277
343
|
}
|
|
278
|
-
function useTiptapEditor(name, defaultValue = "",
|
|
344
|
+
function useTiptapEditor(name, defaultValue = "", extensions = []) {
|
|
279
345
|
const field = useField(name);
|
|
280
346
|
const editor = useEditor({
|
|
281
|
-
extensions
|
|
347
|
+
extensions,
|
|
282
348
|
content: parseJSONContent(field.value, defaultValue),
|
|
283
349
|
onUpdate: ({ editor: editor2 }) => {
|
|
284
350
|
const json = editor2.getJSON();
|
|
@@ -1670,10 +1736,10 @@ function callOrReturn(value, context = void 0, ...props) {
|
|
|
1670
1736
|
}
|
|
1671
1737
|
return value;
|
|
1672
1738
|
}
|
|
1673
|
-
function splitExtensions(
|
|
1674
|
-
const baseExtensions =
|
|
1675
|
-
const nodeExtensions =
|
|
1676
|
-
const markExtensions =
|
|
1739
|
+
function splitExtensions(extensions) {
|
|
1740
|
+
const baseExtensions = extensions.filter((extension) => extension.type === "extension");
|
|
1741
|
+
const nodeExtensions = extensions.filter((extension) => extension.type === "node");
|
|
1742
|
+
const markExtensions = extensions.filter((extension) => extension.type === "mark");
|
|
1677
1743
|
return {
|
|
1678
1744
|
baseExtensions,
|
|
1679
1745
|
nodeExtensions,
|
|
@@ -1862,8 +1928,8 @@ function isMarkActive(state, typeOrName, attributes = {}) {
|
|
|
1862
1928
|
const range = matchedRange > 0 ? matchedRange + excludedRange : matchedRange;
|
|
1863
1929
|
return range >= selectionRange;
|
|
1864
1930
|
}
|
|
1865
|
-
function isList(name,
|
|
1866
|
-
const { nodeExtensions } = splitExtensions(
|
|
1931
|
+
function isList(name, extensions) {
|
|
1932
|
+
const { nodeExtensions } = splitExtensions(extensions);
|
|
1867
1933
|
const extension = nodeExtensions.find((item) => item.name === name);
|
|
1868
1934
|
if (!extension) {
|
|
1869
1935
|
return false;
|
|
@@ -2249,7 +2315,7 @@ var joinListForwards = (tr, listType) => {
|
|
|
2249
2315
|
return true;
|
|
2250
2316
|
};
|
|
2251
2317
|
var toggleList = (listTypeOrName, itemTypeOrName, keepMarks, attributes = {}) => ({ editor, tr, state, dispatch, chain, commands, can }) => {
|
|
2252
|
-
const { extensions
|
|
2318
|
+
const { extensions, splittableMarks } = editor.extensionManager;
|
|
2253
2319
|
const listType = getNodeType(listTypeOrName, state.schema);
|
|
2254
2320
|
const itemType = getNodeType(itemTypeOrName, state.schema);
|
|
2255
2321
|
const { selection, storedMarks } = state;
|
|
@@ -2259,12 +2325,12 @@ var toggleList = (listTypeOrName, itemTypeOrName, keepMarks, attributes = {}) =>
|
|
|
2259
2325
|
if (!range) {
|
|
2260
2326
|
return false;
|
|
2261
2327
|
}
|
|
2262
|
-
const parentList = findParentNode((node) => isList(node.type.name,
|
|
2328
|
+
const parentList = findParentNode((node) => isList(node.type.name, extensions))(selection);
|
|
2263
2329
|
if (range.depth >= 1 && parentList && range.depth - parentList.depth <= 1) {
|
|
2264
2330
|
if (parentList.node.type === listType) {
|
|
2265
2331
|
return commands.liftListItem(itemType);
|
|
2266
2332
|
}
|
|
2267
|
-
if (isList(parentList.node.type.name,
|
|
2333
|
+
if (isList(parentList.node.type.name, extensions) && listType.validContent(parentList.node.content) && dispatch) {
|
|
2268
2334
|
return chain().command(() => {
|
|
2269
2335
|
tr.setNodeMarkup(parentList.pos, listType);
|
|
2270
2336
|
return true;
|
|
@@ -3599,7 +3665,7 @@ var Heading = Node3.create({
|
|
|
3599
3665
|
}
|
|
3600
3666
|
});
|
|
3601
3667
|
var index_default = Heading;
|
|
3602
|
-
const
|
|
3668
|
+
const BaseHeadingWithSEOTag = index_default.extend({
|
|
3603
3669
|
addAttributes() {
|
|
3604
3670
|
return {
|
|
3605
3671
|
...this.parent?.(),
|
|
@@ -3607,7 +3673,8 @@ const HeadingWithSEOTag = index_default.extend({
|
|
|
3607
3673
|
tag: { default: null }
|
|
3608
3674
|
};
|
|
3609
3675
|
}
|
|
3610
|
-
})
|
|
3676
|
+
});
|
|
3677
|
+
BaseHeadingWithSEOTag.configure({ levels: [1, 2, 3, 4] });
|
|
3611
3678
|
function useHeading(editor, props = { disabled: false }) {
|
|
3612
3679
|
const editorState = useEditorState({
|
|
3613
3680
|
editor,
|
|
@@ -3726,425 +3793,72 @@ function useScript(editor, props = { disabled: false }) {
|
|
|
3726
3793
|
)
|
|
3727
3794
|
};
|
|
3728
3795
|
}
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
if (initialContentSize > limit) {
|
|
3777
|
-
const over = initialContentSize - limit;
|
|
3778
|
-
const from = 0;
|
|
3779
|
-
const to = over;
|
|
3780
|
-
console.warn(
|
|
3781
|
-
`[CharacterCount] Initial content exceeded limit of ${limit} characters. Content was automatically trimmed.`
|
|
3782
|
-
);
|
|
3783
|
-
const tr = newState.tr.deleteRange(from, to);
|
|
3784
|
-
initialEvaluationDone = true;
|
|
3785
|
-
return tr;
|
|
3786
|
-
}
|
|
3787
|
-
initialEvaluationDone = true;
|
|
3788
|
-
},
|
|
3789
|
-
filterTransaction: (transaction, state) => {
|
|
3790
|
-
const limit = this.options.limit;
|
|
3791
|
-
if (!transaction.docChanged || limit === 0 || limit === null || limit === void 0) {
|
|
3792
|
-
return true;
|
|
3793
|
-
}
|
|
3794
|
-
const oldSize = this.storage.characters({ node: state.doc });
|
|
3795
|
-
const newSize = this.storage.characters({ node: transaction.doc });
|
|
3796
|
-
if (newSize <= limit) {
|
|
3797
|
-
return true;
|
|
3798
|
-
}
|
|
3799
|
-
if (oldSize > limit && newSize > limit && newSize <= oldSize) {
|
|
3800
|
-
return true;
|
|
3801
|
-
}
|
|
3802
|
-
if (oldSize > limit && newSize > limit && newSize > oldSize) {
|
|
3803
|
-
return false;
|
|
3804
|
-
}
|
|
3805
|
-
const isPaste = transaction.getMeta("paste");
|
|
3806
|
-
if (!isPaste) {
|
|
3807
|
-
return false;
|
|
3808
|
-
}
|
|
3809
|
-
const pos = transaction.selection.$head.pos;
|
|
3810
|
-
const over = newSize - limit;
|
|
3811
|
-
const from = pos - over;
|
|
3812
|
-
const to = pos;
|
|
3813
|
-
transaction.deleteRange(from, to);
|
|
3814
|
-
const updatedSize = this.storage.characters({ node: transaction.doc });
|
|
3815
|
-
if (updatedSize > limit) {
|
|
3816
|
-
return false;
|
|
3817
|
-
}
|
|
3818
|
-
return true;
|
|
3819
|
-
}
|
|
3820
|
-
})
|
|
3821
|
-
];
|
|
3822
|
-
}
|
|
3823
|
-
});
|
|
3824
|
-
Extension.create({
|
|
3825
|
-
name: "dropCursor",
|
|
3826
|
-
addOptions() {
|
|
3827
|
-
return {
|
|
3828
|
-
color: "currentColor",
|
|
3829
|
-
width: 1,
|
|
3830
|
-
class: void 0
|
|
3831
|
-
};
|
|
3832
|
-
},
|
|
3833
|
-
addProseMirrorPlugins() {
|
|
3834
|
-
return [dropCursor(this.options)];
|
|
3835
|
-
}
|
|
3836
|
-
});
|
|
3837
|
-
Extension.create({
|
|
3838
|
-
name: "focus",
|
|
3839
|
-
addOptions() {
|
|
3840
|
-
return {
|
|
3841
|
-
className: "has-focus",
|
|
3842
|
-
mode: "all"
|
|
3843
|
-
};
|
|
3844
|
-
},
|
|
3845
|
-
addProseMirrorPlugins() {
|
|
3846
|
-
return [
|
|
3847
|
-
new Plugin({
|
|
3848
|
-
key: new PluginKey("focus"),
|
|
3849
|
-
props: {
|
|
3850
|
-
decorations: ({ doc, selection }) => {
|
|
3851
|
-
const { isEditable, isFocused } = this.editor;
|
|
3852
|
-
const { anchor } = selection;
|
|
3853
|
-
const decorations = [];
|
|
3854
|
-
if (!isEditable || !isFocused) {
|
|
3855
|
-
return DecorationSet.create(doc, []);
|
|
3856
|
-
}
|
|
3857
|
-
let maxLevels = 0;
|
|
3858
|
-
if (this.options.mode === "deepest") {
|
|
3859
|
-
doc.descendants((node, pos) => {
|
|
3860
|
-
if (node.isText) {
|
|
3861
|
-
return;
|
|
3862
|
-
}
|
|
3863
|
-
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
|
|
3864
|
-
if (!isCurrent) {
|
|
3865
|
-
return false;
|
|
3866
|
-
}
|
|
3867
|
-
maxLevels += 1;
|
|
3868
|
-
});
|
|
3869
|
-
}
|
|
3870
|
-
let currentLevel = 0;
|
|
3871
|
-
doc.descendants((node, pos) => {
|
|
3872
|
-
if (node.isText) {
|
|
3873
|
-
return false;
|
|
3874
|
-
}
|
|
3875
|
-
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
|
|
3876
|
-
if (!isCurrent) {
|
|
3877
|
-
return false;
|
|
3796
|
+
const clamp = (val, min, max) => Math.max(min, Math.min(max, val));
|
|
3797
|
+
const parseNum = (value, fallback) => {
|
|
3798
|
+
const n = Number(value);
|
|
3799
|
+
return Number.isFinite(n) ? n : fallback;
|
|
3800
|
+
};
|
|
3801
|
+
const TableSizeDialog = ({
|
|
3802
|
+
open,
|
|
3803
|
+
defaultRows = 3,
|
|
3804
|
+
defaultCols = 3,
|
|
3805
|
+
onClose,
|
|
3806
|
+
onSave
|
|
3807
|
+
}) => {
|
|
3808
|
+
const [rows, setRows] = useState(defaultRows);
|
|
3809
|
+
const [cols, setCols] = useState(defaultCols);
|
|
3810
|
+
useEffect(() => {
|
|
3811
|
+
if (open) {
|
|
3812
|
+
setRows(defaultRows);
|
|
3813
|
+
setCols(defaultCols);
|
|
3814
|
+
}
|
|
3815
|
+
}, [open, defaultRows, defaultCols]);
|
|
3816
|
+
const min = 1;
|
|
3817
|
+
const max = 10;
|
|
3818
|
+
const isValid = rows >= min && rows <= max && cols >= min && cols <= max;
|
|
3819
|
+
const handleSave = () => {
|
|
3820
|
+
if (!isValid) return;
|
|
3821
|
+
onSave(clamp(rows, min, max), clamp(cols, min, max));
|
|
3822
|
+
};
|
|
3823
|
+
return /* @__PURE__ */ jsx(
|
|
3824
|
+
Dialog.Root,
|
|
3825
|
+
{
|
|
3826
|
+
open,
|
|
3827
|
+
onOpenChange: (v) => {
|
|
3828
|
+
if (!v) onClose();
|
|
3829
|
+
},
|
|
3830
|
+
children: open && /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
|
3831
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: "Insert table" }),
|
|
3832
|
+
/* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { gap: 4, alignItems: "flex-end", children: [
|
|
3833
|
+
/* @__PURE__ */ jsxs(Field.Root, { width: "100%", children: [
|
|
3834
|
+
/* @__PURE__ */ jsx(Field.Label, { children: "Rows" }),
|
|
3835
|
+
/* @__PURE__ */ jsx(
|
|
3836
|
+
TextInput,
|
|
3837
|
+
{
|
|
3838
|
+
name: "table-rows",
|
|
3839
|
+
type: "number",
|
|
3840
|
+
value: String(rows),
|
|
3841
|
+
onChange: (e) => setRows(clamp(parseNum(e.target.value, rows), min, max)),
|
|
3842
|
+
placeholder: String(defaultRows)
|
|
3878
3843
|
}
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
var Gapcursor = Extension.create({
|
|
3898
|
-
name: "gapCursor",
|
|
3899
|
-
addProseMirrorPlugins() {
|
|
3900
|
-
return [gapCursor()];
|
|
3901
|
-
},
|
|
3902
|
-
extendNodeSchema(extension) {
|
|
3903
|
-
var _a;
|
|
3904
|
-
const context = {
|
|
3905
|
-
name: extension.name,
|
|
3906
|
-
options: extension.options,
|
|
3907
|
-
storage: extension.storage
|
|
3908
|
-
};
|
|
3909
|
-
return {
|
|
3910
|
-
allowGapCursor: (_a = callOrReturn(getExtensionField(extension, "allowGapCursor", context))) != null ? _a : null
|
|
3911
|
-
};
|
|
3912
|
-
}
|
|
3913
|
-
});
|
|
3914
|
-
var DEFAULT_DATA_ATTRIBUTE = "placeholder";
|
|
3915
|
-
function preparePlaceholderAttribute(attr) {
|
|
3916
|
-
return attr.replace(/\s+/g, "-").replace(/[^a-zA-Z0-9-]/g, "").replace(/^[0-9-]+/, "").replace(/^-+/, "").toLowerCase();
|
|
3917
|
-
}
|
|
3918
|
-
Extension.create({
|
|
3919
|
-
name: "placeholder",
|
|
3920
|
-
addOptions() {
|
|
3921
|
-
return {
|
|
3922
|
-
emptyEditorClass: "is-editor-empty",
|
|
3923
|
-
emptyNodeClass: "is-empty",
|
|
3924
|
-
dataAttribute: DEFAULT_DATA_ATTRIBUTE,
|
|
3925
|
-
placeholder: "Write something …",
|
|
3926
|
-
showOnlyWhenEditable: true,
|
|
3927
|
-
showOnlyCurrent: true,
|
|
3928
|
-
includeChildren: false
|
|
3929
|
-
};
|
|
3930
|
-
},
|
|
3931
|
-
addProseMirrorPlugins() {
|
|
3932
|
-
const dataAttribute = this.options.dataAttribute ? `data-${preparePlaceholderAttribute(this.options.dataAttribute)}` : `data-${DEFAULT_DATA_ATTRIBUTE}`;
|
|
3933
|
-
return [
|
|
3934
|
-
new Plugin({
|
|
3935
|
-
key: new PluginKey("placeholder"),
|
|
3936
|
-
props: {
|
|
3937
|
-
decorations: ({ doc, selection }) => {
|
|
3938
|
-
const active = this.editor.isEditable || !this.options.showOnlyWhenEditable;
|
|
3939
|
-
const { anchor } = selection;
|
|
3940
|
-
const decorations = [];
|
|
3941
|
-
if (!active) {
|
|
3942
|
-
return null;
|
|
3943
|
-
}
|
|
3944
|
-
const isEmptyDoc = this.editor.isEmpty;
|
|
3945
|
-
doc.descendants((node, pos) => {
|
|
3946
|
-
const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
|
|
3947
|
-
const isEmpty = !node.isLeaf && isNodeEmpty(node);
|
|
3948
|
-
if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
|
|
3949
|
-
const classes = [this.options.emptyNodeClass];
|
|
3950
|
-
if (isEmptyDoc) {
|
|
3951
|
-
classes.push(this.options.emptyEditorClass);
|
|
3952
|
-
}
|
|
3953
|
-
const decoration = Decoration.node(pos, pos + node.nodeSize, {
|
|
3954
|
-
class: classes.join(" "),
|
|
3955
|
-
[dataAttribute]: typeof this.options.placeholder === "function" ? this.options.placeholder({
|
|
3956
|
-
editor: this.editor,
|
|
3957
|
-
node,
|
|
3958
|
-
pos,
|
|
3959
|
-
hasAnchor
|
|
3960
|
-
}) : this.options.placeholder
|
|
3961
|
-
});
|
|
3962
|
-
decorations.push(decoration);
|
|
3963
|
-
}
|
|
3964
|
-
return this.options.includeChildren;
|
|
3965
|
-
});
|
|
3966
|
-
return DecorationSet.create(doc, decorations);
|
|
3967
|
-
}
|
|
3968
|
-
}
|
|
3969
|
-
})
|
|
3970
|
-
];
|
|
3971
|
-
}
|
|
3972
|
-
});
|
|
3973
|
-
Extension.create({
|
|
3974
|
-
name: "selection",
|
|
3975
|
-
addOptions() {
|
|
3976
|
-
return {
|
|
3977
|
-
className: "selection"
|
|
3978
|
-
};
|
|
3979
|
-
},
|
|
3980
|
-
addProseMirrorPlugins() {
|
|
3981
|
-
const { editor, options } = this;
|
|
3982
|
-
return [
|
|
3983
|
-
new Plugin({
|
|
3984
|
-
key: new PluginKey("selection"),
|
|
3985
|
-
props: {
|
|
3986
|
-
decorations(state) {
|
|
3987
|
-
if (state.selection.empty || editor.isFocused || !editor.isEditable || isNodeSelection(state.selection) || editor.view.dragging) {
|
|
3988
|
-
return null;
|
|
3989
|
-
}
|
|
3990
|
-
return DecorationSet.create(state.doc, [
|
|
3991
|
-
Decoration.inline(state.selection.from, state.selection.to, {
|
|
3992
|
-
class: options.className
|
|
3993
|
-
})
|
|
3994
|
-
]);
|
|
3995
|
-
}
|
|
3996
|
-
}
|
|
3997
|
-
})
|
|
3998
|
-
];
|
|
3999
|
-
}
|
|
4000
|
-
});
|
|
4001
|
-
function nodeEqualsType({ types, node }) {
|
|
4002
|
-
return node && Array.isArray(types) && types.includes(node.type) || (node == null ? void 0 : node.type) === types;
|
|
4003
|
-
}
|
|
4004
|
-
Extension.create({
|
|
4005
|
-
name: "trailingNode",
|
|
4006
|
-
addOptions() {
|
|
4007
|
-
return {
|
|
4008
|
-
node: void 0,
|
|
4009
|
-
notAfter: []
|
|
4010
|
-
};
|
|
4011
|
-
},
|
|
4012
|
-
addProseMirrorPlugins() {
|
|
4013
|
-
var _a;
|
|
4014
|
-
const plugin = new PluginKey(this.name);
|
|
4015
|
-
const defaultNode = this.options.node || ((_a = this.editor.schema.topNodeType.contentMatch.defaultType) == null ? void 0 : _a.name) || "paragraph";
|
|
4016
|
-
const disabledNodes = Object.entries(this.editor.schema.nodes).map(([, value]) => value).filter((node) => (this.options.notAfter || []).concat(defaultNode).includes(node.name));
|
|
4017
|
-
return [
|
|
4018
|
-
new Plugin({
|
|
4019
|
-
key: plugin,
|
|
4020
|
-
appendTransaction: (_, __, state) => {
|
|
4021
|
-
const { doc, tr, schema } = state;
|
|
4022
|
-
const shouldInsertNodeAtEnd = plugin.getState(state);
|
|
4023
|
-
const endPosition = doc.content.size;
|
|
4024
|
-
const type = schema.nodes[defaultNode];
|
|
4025
|
-
if (!shouldInsertNodeAtEnd) {
|
|
4026
|
-
return;
|
|
4027
|
-
}
|
|
4028
|
-
return tr.insert(endPosition, type.create());
|
|
4029
|
-
},
|
|
4030
|
-
state: {
|
|
4031
|
-
init: (_, state) => {
|
|
4032
|
-
const lastNode = state.tr.doc.lastChild;
|
|
4033
|
-
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
|
|
4034
|
-
},
|
|
4035
|
-
apply: (tr, value) => {
|
|
4036
|
-
if (!tr.docChanged) {
|
|
4037
|
-
return value;
|
|
4038
|
-
}
|
|
4039
|
-
if (tr.getMeta("__uniqueIDTransaction")) {
|
|
4040
|
-
return value;
|
|
4041
|
-
}
|
|
4042
|
-
const lastNode = tr.doc.lastChild;
|
|
4043
|
-
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
|
|
4044
|
-
}
|
|
4045
|
-
}
|
|
4046
|
-
})
|
|
4047
|
-
];
|
|
4048
|
-
}
|
|
4049
|
-
});
|
|
4050
|
-
Extension.create({
|
|
4051
|
-
name: "undoRedo",
|
|
4052
|
-
addOptions() {
|
|
4053
|
-
return {
|
|
4054
|
-
depth: 100,
|
|
4055
|
-
newGroupDelay: 500
|
|
4056
|
-
};
|
|
4057
|
-
},
|
|
4058
|
-
addCommands() {
|
|
4059
|
-
return {
|
|
4060
|
-
undo: () => ({ state, dispatch }) => {
|
|
4061
|
-
return undo(state, dispatch);
|
|
4062
|
-
},
|
|
4063
|
-
redo: () => ({ state, dispatch }) => {
|
|
4064
|
-
return redo(state, dispatch);
|
|
4065
|
-
}
|
|
4066
|
-
};
|
|
4067
|
-
},
|
|
4068
|
-
addProseMirrorPlugins() {
|
|
4069
|
-
return [history(this.options)];
|
|
4070
|
-
},
|
|
4071
|
-
addKeyboardShortcuts() {
|
|
4072
|
-
return {
|
|
4073
|
-
"Mod-z": () => this.editor.commands.undo(),
|
|
4074
|
-
"Shift-Mod-z": () => this.editor.commands.redo(),
|
|
4075
|
-
"Mod-y": () => this.editor.commands.redo(),
|
|
4076
|
-
// Russian keyboard layouts
|
|
4077
|
-
"Mod-я": () => this.editor.commands.undo(),
|
|
4078
|
-
"Shift-Mod-я": () => this.editor.commands.redo()
|
|
4079
|
-
};
|
|
4080
|
-
}
|
|
4081
|
-
});
|
|
4082
|
-
const clamp = (val, min, max) => Math.max(min, Math.min(max, val));
|
|
4083
|
-
const parseNum = (value, fallback) => {
|
|
4084
|
-
const n = Number(value);
|
|
4085
|
-
return Number.isFinite(n) ? n : fallback;
|
|
4086
|
-
};
|
|
4087
|
-
const TableSizeDialog = ({
|
|
4088
|
-
open,
|
|
4089
|
-
defaultRows = 3,
|
|
4090
|
-
defaultCols = 3,
|
|
4091
|
-
onClose,
|
|
4092
|
-
onSave
|
|
4093
|
-
}) => {
|
|
4094
|
-
const [rows, setRows] = useState(defaultRows);
|
|
4095
|
-
const [cols, setCols] = useState(defaultCols);
|
|
4096
|
-
useEffect(() => {
|
|
4097
|
-
if (open) {
|
|
4098
|
-
setRows(defaultRows);
|
|
4099
|
-
setCols(defaultCols);
|
|
4100
|
-
}
|
|
4101
|
-
}, [open, defaultRows, defaultCols]);
|
|
4102
|
-
const min = 1;
|
|
4103
|
-
const max = 10;
|
|
4104
|
-
const isValid = rows >= min && rows <= max && cols >= min && cols <= max;
|
|
4105
|
-
const handleSave = () => {
|
|
4106
|
-
if (!isValid) return;
|
|
4107
|
-
onSave(clamp(rows, min, max), clamp(cols, min, max));
|
|
4108
|
-
};
|
|
4109
|
-
return /* @__PURE__ */ jsx(
|
|
4110
|
-
Dialog.Root,
|
|
4111
|
-
{
|
|
4112
|
-
open,
|
|
4113
|
-
onOpenChange: (v) => {
|
|
4114
|
-
if (!v) onClose();
|
|
4115
|
-
},
|
|
4116
|
-
children: open && /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
|
4117
|
-
/* @__PURE__ */ jsx(Dialog.Header, { children: "Insert table" }),
|
|
4118
|
-
/* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { gap: 4, alignItems: "flex-end", children: [
|
|
4119
|
-
/* @__PURE__ */ jsxs(Field.Root, { width: "100%", children: [
|
|
4120
|
-
/* @__PURE__ */ jsx(Field.Label, { children: "Rows" }),
|
|
4121
|
-
/* @__PURE__ */ jsx(
|
|
4122
|
-
TextInput,
|
|
4123
|
-
{
|
|
4124
|
-
name: "table-rows",
|
|
4125
|
-
type: "number",
|
|
4126
|
-
value: String(rows),
|
|
4127
|
-
onChange: (e) => setRows(clamp(parseNum(e.target.value, rows), min, max)),
|
|
4128
|
-
placeholder: String(defaultRows)
|
|
4129
|
-
}
|
|
4130
|
-
),
|
|
4131
|
-
/* @__PURE__ */ jsxs(Field.Hint, { children: [
|
|
4132
|
-
"Min ",
|
|
4133
|
-
min,
|
|
4134
|
-
", max ",
|
|
4135
|
-
max
|
|
4136
|
-
] })
|
|
4137
|
-
] }),
|
|
4138
|
-
/* @__PURE__ */ jsxs(Field.Root, { width: "100%", children: [
|
|
4139
|
-
/* @__PURE__ */ jsx(Field.Label, { children: "Columns" }),
|
|
4140
|
-
/* @__PURE__ */ jsx(
|
|
4141
|
-
TextInput,
|
|
4142
|
-
{
|
|
4143
|
-
name: "table-cols",
|
|
4144
|
-
type: "number",
|
|
4145
|
-
value: String(cols),
|
|
4146
|
-
onChange: (e) => setCols(clamp(parseNum(e.target.value, cols), min, max)),
|
|
4147
|
-
placeholder: String(defaultCols)
|
|
3844
|
+
),
|
|
3845
|
+
/* @__PURE__ */ jsxs(Field.Hint, { children: [
|
|
3846
|
+
"Min ",
|
|
3847
|
+
min,
|
|
3848
|
+
", max ",
|
|
3849
|
+
max
|
|
3850
|
+
] })
|
|
3851
|
+
] }),
|
|
3852
|
+
/* @__PURE__ */ jsxs(Field.Root, { width: "100%", children: [
|
|
3853
|
+
/* @__PURE__ */ jsx(Field.Label, { children: "Columns" }),
|
|
3854
|
+
/* @__PURE__ */ jsx(
|
|
3855
|
+
TextInput,
|
|
3856
|
+
{
|
|
3857
|
+
name: "table-cols",
|
|
3858
|
+
type: "number",
|
|
3859
|
+
value: String(cols),
|
|
3860
|
+
onChange: (e) => setCols(clamp(parseNum(e.target.value, cols), min, max)),
|
|
3861
|
+
placeholder: String(defaultCols)
|
|
4148
3862
|
}
|
|
4149
3863
|
),
|
|
4150
3864
|
/* @__PURE__ */ jsxs(Field.Hint, { children: [
|
|
@@ -4302,140 +4016,597 @@ function TextAlignJustify(props) {
|
|
|
4302
4016
|
"stroke-linecap": "round",
|
|
4303
4017
|
"stroke-linejoin": "round"
|
|
4304
4018
|
}
|
|
4305
|
-
)
|
|
4306
|
-
}
|
|
4307
|
-
);
|
|
4308
|
-
}
|
|
4309
|
-
function TextAlignRight(props) {
|
|
4310
|
-
return /* @__PURE__ */ jsx(
|
|
4311
|
-
"svg",
|
|
4312
|
-
{
|
|
4313
|
-
width: "16",
|
|
4314
|
-
height: "16",
|
|
4315
|
-
viewBox: "0 0 24 24",
|
|
4316
|
-
fill: "currentColor",
|
|
4317
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
4318
|
-
...props,
|
|
4319
|
-
children: /* @__PURE__ */ jsx(
|
|
4320
|
-
"path",
|
|
4321
|
-
{
|
|
4322
|
-
d: "M8 10H21M3 14H21M8 18H21M3 6H21",
|
|
4323
|
-
stroke: "currentColor",
|
|
4324
|
-
"stroke-width": "2",
|
|
4325
|
-
"stroke-linecap": "round",
|
|
4326
|
-
"stroke-linejoin": "round"
|
|
4019
|
+
)
|
|
4020
|
+
}
|
|
4021
|
+
);
|
|
4022
|
+
}
|
|
4023
|
+
function TextAlignRight(props) {
|
|
4024
|
+
return /* @__PURE__ */ jsx(
|
|
4025
|
+
"svg",
|
|
4026
|
+
{
|
|
4027
|
+
width: "16",
|
|
4028
|
+
height: "16",
|
|
4029
|
+
viewBox: "0 0 24 24",
|
|
4030
|
+
fill: "currentColor",
|
|
4031
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4032
|
+
...props,
|
|
4033
|
+
children: /* @__PURE__ */ jsx(
|
|
4034
|
+
"path",
|
|
4035
|
+
{
|
|
4036
|
+
d: "M8 10H21M3 14H21M8 18H21M3 6H21",
|
|
4037
|
+
stroke: "currentColor",
|
|
4038
|
+
"stroke-width": "2",
|
|
4039
|
+
"stroke-linecap": "round",
|
|
4040
|
+
"stroke-linejoin": "round"
|
|
4041
|
+
}
|
|
4042
|
+
)
|
|
4043
|
+
}
|
|
4044
|
+
);
|
|
4045
|
+
}
|
|
4046
|
+
function TextAlignCenter(props) {
|
|
4047
|
+
return /* @__PURE__ */ jsx(
|
|
4048
|
+
"svg",
|
|
4049
|
+
{
|
|
4050
|
+
width: "16",
|
|
4051
|
+
height: "16",
|
|
4052
|
+
viewBox: "0 0 24 24",
|
|
4053
|
+
fill: "currentColor",
|
|
4054
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4055
|
+
...props,
|
|
4056
|
+
children: /* @__PURE__ */ jsx(
|
|
4057
|
+
"path",
|
|
4058
|
+
{
|
|
4059
|
+
d: "M3 6H21M3 14H21M17 10H7M17 18H7",
|
|
4060
|
+
stroke: "currentColor",
|
|
4061
|
+
"stroke-width": "2",
|
|
4062
|
+
"stroke-linecap": "round",
|
|
4063
|
+
"stroke-linejoin": "round"
|
|
4064
|
+
}
|
|
4065
|
+
)
|
|
4066
|
+
}
|
|
4067
|
+
);
|
|
4068
|
+
}
|
|
4069
|
+
function useTextAlign(editor, props = { disabled: false }) {
|
|
4070
|
+
const editorState = useEditorState({
|
|
4071
|
+
editor,
|
|
4072
|
+
selector: (ctx) => {
|
|
4073
|
+
return {
|
|
4074
|
+
isTextAlignLeft: ctx.editor.isActive({ textAlign: "left" }) ?? false,
|
|
4075
|
+
isTextAlignRight: ctx.editor.isActive({ textAlign: "right" }) ?? false,
|
|
4076
|
+
isTextAlignCenter: ctx.editor.isActive({ textAlign: "center" }) ?? false,
|
|
4077
|
+
isTextAlignJustify: ctx.editor.isActive({ textAlign: "justify" }) ?? false,
|
|
4078
|
+
canToggleAlign: ctx.editor.can().chain().setTextAlign("left").run() ?? false
|
|
4079
|
+
};
|
|
4080
|
+
}
|
|
4081
|
+
});
|
|
4082
|
+
const setTextAlign = (alignment) => {
|
|
4083
|
+
editor.chain().focus().setTextAlign(alignment).run();
|
|
4084
|
+
};
|
|
4085
|
+
return {
|
|
4086
|
+
textAlignLeftButton: /* @__PURE__ */ jsx(
|
|
4087
|
+
ToolbarButton,
|
|
4088
|
+
{
|
|
4089
|
+
onClick: () => setTextAlign("left"),
|
|
4090
|
+
icon: /* @__PURE__ */ jsx(TextAlignLeft, {}),
|
|
4091
|
+
active: editorState.isTextAlignLeft,
|
|
4092
|
+
disabled: props.disabled || !editor || !editorState.canToggleAlign,
|
|
4093
|
+
tooltip: "Text Align Left"
|
|
4094
|
+
},
|
|
4095
|
+
"text-align-left"
|
|
4096
|
+
),
|
|
4097
|
+
textAlignCenterButton: /* @__PURE__ */ jsx(
|
|
4098
|
+
ToolbarButton,
|
|
4099
|
+
{
|
|
4100
|
+
onClick: () => setTextAlign("center"),
|
|
4101
|
+
icon: /* @__PURE__ */ jsx(TextAlignCenter, {}),
|
|
4102
|
+
active: editorState.isTextAlignCenter,
|
|
4103
|
+
disabled: props.disabled || !editor || !editorState.canToggleAlign,
|
|
4104
|
+
tooltip: "Text Align Center"
|
|
4105
|
+
},
|
|
4106
|
+
"text-align-center"
|
|
4107
|
+
),
|
|
4108
|
+
textAlignRightButton: /* @__PURE__ */ jsx(
|
|
4109
|
+
ToolbarButton,
|
|
4110
|
+
{
|
|
4111
|
+
onClick: () => setTextAlign("right"),
|
|
4112
|
+
icon: /* @__PURE__ */ jsx(TextAlignRight, {}),
|
|
4113
|
+
active: editorState.isTextAlignRight,
|
|
4114
|
+
disabled: props.disabled || !editor || !editorState.canToggleAlign,
|
|
4115
|
+
tooltip: "Text Align Right"
|
|
4116
|
+
},
|
|
4117
|
+
"text-align-right"
|
|
4118
|
+
),
|
|
4119
|
+
textAlignJustifyButton: /* @__PURE__ */ jsx(
|
|
4120
|
+
ToolbarButton,
|
|
4121
|
+
{
|
|
4122
|
+
onClick: () => setTextAlign("justify"),
|
|
4123
|
+
icon: /* @__PURE__ */ jsx(TextAlignJustify, {}),
|
|
4124
|
+
active: editorState.isTextAlignJustify,
|
|
4125
|
+
disabled: props.disabled || !editor || !editorState.canToggleAlign,
|
|
4126
|
+
tooltip: "Text Align Justify"
|
|
4127
|
+
},
|
|
4128
|
+
"text-align-justify"
|
|
4129
|
+
)
|
|
4130
|
+
};
|
|
4131
|
+
}
|
|
4132
|
+
function usePresetConfig(presetName) {
|
|
4133
|
+
const { get } = useFetchClient();
|
|
4134
|
+
const normalizedPresetName = useMemo(
|
|
4135
|
+
() => presetName?.trim() || void 0,
|
|
4136
|
+
[presetName]
|
|
4137
|
+
);
|
|
4138
|
+
const [config, setConfig] = useState(
|
|
4139
|
+
normalizedPresetName ? null : MINIMAL_PRESET_CONFIG
|
|
4140
|
+
);
|
|
4141
|
+
const [isLoading, setIsLoading] = useState(Boolean(normalizedPresetName));
|
|
4142
|
+
useEffect(() => {
|
|
4143
|
+
let mounted = true;
|
|
4144
|
+
if (!normalizedPresetName) {
|
|
4145
|
+
setConfig(MINIMAL_PRESET_CONFIG);
|
|
4146
|
+
setIsLoading(false);
|
|
4147
|
+
return;
|
|
4148
|
+
}
|
|
4149
|
+
const fetchPreset = async () => {
|
|
4150
|
+
setIsLoading(true);
|
|
4151
|
+
try {
|
|
4152
|
+
const response = await get(
|
|
4153
|
+
`/api/tiptap-editor/presets/${normalizedPresetName}`
|
|
4154
|
+
);
|
|
4155
|
+
if (!mounted) return;
|
|
4156
|
+
setConfig(response.data || MINIMAL_PRESET_CONFIG);
|
|
4157
|
+
} catch (error) {
|
|
4158
|
+
console.warn(
|
|
4159
|
+
"[TiptapEditor] Failed to fetch preset config:",
|
|
4160
|
+
error
|
|
4161
|
+
);
|
|
4162
|
+
if (!mounted) return;
|
|
4163
|
+
setConfig(MINIMAL_PRESET_CONFIG);
|
|
4164
|
+
} finally {
|
|
4165
|
+
if (mounted) {
|
|
4166
|
+
setIsLoading(false);
|
|
4167
|
+
}
|
|
4168
|
+
}
|
|
4169
|
+
};
|
|
4170
|
+
fetchPreset();
|
|
4171
|
+
return () => {
|
|
4172
|
+
mounted = false;
|
|
4173
|
+
};
|
|
4174
|
+
}, [get, normalizedPresetName]);
|
|
4175
|
+
return { config, isLoading };
|
|
4176
|
+
}
|
|
4177
|
+
Extension.create({
|
|
4178
|
+
name: "characterCount",
|
|
4179
|
+
addOptions() {
|
|
4180
|
+
return {
|
|
4181
|
+
limit: null,
|
|
4182
|
+
mode: "textSize",
|
|
4183
|
+
textCounter: (text) => text.length,
|
|
4184
|
+
wordCounter: (text) => text.split(" ").filter((word) => word !== "").length
|
|
4185
|
+
};
|
|
4186
|
+
},
|
|
4187
|
+
addStorage() {
|
|
4188
|
+
return {
|
|
4189
|
+
characters: () => 0,
|
|
4190
|
+
words: () => 0
|
|
4191
|
+
};
|
|
4192
|
+
},
|
|
4193
|
+
onBeforeCreate() {
|
|
4194
|
+
this.storage.characters = (options) => {
|
|
4195
|
+
const node = (options == null ? void 0 : options.node) || this.editor.state.doc;
|
|
4196
|
+
const mode = (options == null ? void 0 : options.mode) || this.options.mode;
|
|
4197
|
+
if (mode === "textSize") {
|
|
4198
|
+
const text = node.textBetween(0, node.content.size, void 0, " ");
|
|
4199
|
+
return this.options.textCounter(text);
|
|
4200
|
+
}
|
|
4201
|
+
return node.nodeSize;
|
|
4202
|
+
};
|
|
4203
|
+
this.storage.words = (options) => {
|
|
4204
|
+
const node = (options == null ? void 0 : options.node) || this.editor.state.doc;
|
|
4205
|
+
const text = node.textBetween(0, node.content.size, " ", " ");
|
|
4206
|
+
return this.options.wordCounter(text);
|
|
4207
|
+
};
|
|
4208
|
+
},
|
|
4209
|
+
addProseMirrorPlugins() {
|
|
4210
|
+
let initialEvaluationDone = false;
|
|
4211
|
+
return [
|
|
4212
|
+
new Plugin({
|
|
4213
|
+
key: new PluginKey("characterCount"),
|
|
4214
|
+
appendTransaction: (transactions, oldState, newState) => {
|
|
4215
|
+
if (initialEvaluationDone) {
|
|
4216
|
+
return;
|
|
4217
|
+
}
|
|
4218
|
+
const limit = this.options.limit;
|
|
4219
|
+
if (limit === null || limit === void 0 || limit === 0) {
|
|
4220
|
+
initialEvaluationDone = true;
|
|
4221
|
+
return;
|
|
4222
|
+
}
|
|
4223
|
+
const initialContentSize = this.storage.characters({ node: newState.doc });
|
|
4224
|
+
if (initialContentSize > limit) {
|
|
4225
|
+
const over = initialContentSize - limit;
|
|
4226
|
+
const from = 0;
|
|
4227
|
+
const to = over;
|
|
4228
|
+
console.warn(
|
|
4229
|
+
`[CharacterCount] Initial content exceeded limit of ${limit} characters. Content was automatically trimmed.`
|
|
4230
|
+
);
|
|
4231
|
+
const tr = newState.tr.deleteRange(from, to);
|
|
4232
|
+
initialEvaluationDone = true;
|
|
4233
|
+
return tr;
|
|
4234
|
+
}
|
|
4235
|
+
initialEvaluationDone = true;
|
|
4236
|
+
},
|
|
4237
|
+
filterTransaction: (transaction, state) => {
|
|
4238
|
+
const limit = this.options.limit;
|
|
4239
|
+
if (!transaction.docChanged || limit === 0 || limit === null || limit === void 0) {
|
|
4240
|
+
return true;
|
|
4241
|
+
}
|
|
4242
|
+
const oldSize = this.storage.characters({ node: state.doc });
|
|
4243
|
+
const newSize = this.storage.characters({ node: transaction.doc });
|
|
4244
|
+
if (newSize <= limit) {
|
|
4245
|
+
return true;
|
|
4246
|
+
}
|
|
4247
|
+
if (oldSize > limit && newSize > limit && newSize <= oldSize) {
|
|
4248
|
+
return true;
|
|
4249
|
+
}
|
|
4250
|
+
if (oldSize > limit && newSize > limit && newSize > oldSize) {
|
|
4251
|
+
return false;
|
|
4252
|
+
}
|
|
4253
|
+
const isPaste = transaction.getMeta("paste");
|
|
4254
|
+
if (!isPaste) {
|
|
4255
|
+
return false;
|
|
4256
|
+
}
|
|
4257
|
+
const pos = transaction.selection.$head.pos;
|
|
4258
|
+
const over = newSize - limit;
|
|
4259
|
+
const from = pos - over;
|
|
4260
|
+
const to = pos;
|
|
4261
|
+
transaction.deleteRange(from, to);
|
|
4262
|
+
const updatedSize = this.storage.characters({ node: transaction.doc });
|
|
4263
|
+
if (updatedSize > limit) {
|
|
4264
|
+
return false;
|
|
4265
|
+
}
|
|
4266
|
+
return true;
|
|
4267
|
+
}
|
|
4268
|
+
})
|
|
4269
|
+
];
|
|
4270
|
+
}
|
|
4271
|
+
});
|
|
4272
|
+
Extension.create({
|
|
4273
|
+
name: "dropCursor",
|
|
4274
|
+
addOptions() {
|
|
4275
|
+
return {
|
|
4276
|
+
color: "currentColor",
|
|
4277
|
+
width: 1,
|
|
4278
|
+
class: void 0
|
|
4279
|
+
};
|
|
4280
|
+
},
|
|
4281
|
+
addProseMirrorPlugins() {
|
|
4282
|
+
return [dropCursor(this.options)];
|
|
4283
|
+
}
|
|
4284
|
+
});
|
|
4285
|
+
Extension.create({
|
|
4286
|
+
name: "focus",
|
|
4287
|
+
addOptions() {
|
|
4288
|
+
return {
|
|
4289
|
+
className: "has-focus",
|
|
4290
|
+
mode: "all"
|
|
4291
|
+
};
|
|
4292
|
+
},
|
|
4293
|
+
addProseMirrorPlugins() {
|
|
4294
|
+
return [
|
|
4295
|
+
new Plugin({
|
|
4296
|
+
key: new PluginKey("focus"),
|
|
4297
|
+
props: {
|
|
4298
|
+
decorations: ({ doc, selection }) => {
|
|
4299
|
+
const { isEditable, isFocused } = this.editor;
|
|
4300
|
+
const { anchor } = selection;
|
|
4301
|
+
const decorations = [];
|
|
4302
|
+
if (!isEditable || !isFocused) {
|
|
4303
|
+
return DecorationSet.create(doc, []);
|
|
4304
|
+
}
|
|
4305
|
+
let maxLevels = 0;
|
|
4306
|
+
if (this.options.mode === "deepest") {
|
|
4307
|
+
doc.descendants((node, pos) => {
|
|
4308
|
+
if (node.isText) {
|
|
4309
|
+
return;
|
|
4310
|
+
}
|
|
4311
|
+
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
|
|
4312
|
+
if (!isCurrent) {
|
|
4313
|
+
return false;
|
|
4314
|
+
}
|
|
4315
|
+
maxLevels += 1;
|
|
4316
|
+
});
|
|
4317
|
+
}
|
|
4318
|
+
let currentLevel = 0;
|
|
4319
|
+
doc.descendants((node, pos) => {
|
|
4320
|
+
if (node.isText) {
|
|
4321
|
+
return false;
|
|
4322
|
+
}
|
|
4323
|
+
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
|
|
4324
|
+
if (!isCurrent) {
|
|
4325
|
+
return false;
|
|
4326
|
+
}
|
|
4327
|
+
currentLevel += 1;
|
|
4328
|
+
const outOfScope = this.options.mode === "deepest" && maxLevels - currentLevel > 0 || this.options.mode === "shallowest" && currentLevel > 1;
|
|
4329
|
+
if (outOfScope) {
|
|
4330
|
+
return this.options.mode === "deepest";
|
|
4331
|
+
}
|
|
4332
|
+
decorations.push(
|
|
4333
|
+
Decoration.node(pos, pos + node.nodeSize, {
|
|
4334
|
+
class: this.options.className
|
|
4335
|
+
})
|
|
4336
|
+
);
|
|
4337
|
+
});
|
|
4338
|
+
return DecorationSet.create(doc, decorations);
|
|
4339
|
+
}
|
|
4340
|
+
}
|
|
4341
|
+
})
|
|
4342
|
+
];
|
|
4343
|
+
}
|
|
4344
|
+
});
|
|
4345
|
+
var Gapcursor = Extension.create({
|
|
4346
|
+
name: "gapCursor",
|
|
4347
|
+
addProseMirrorPlugins() {
|
|
4348
|
+
return [gapCursor()];
|
|
4349
|
+
},
|
|
4350
|
+
extendNodeSchema(extension) {
|
|
4351
|
+
var _a;
|
|
4352
|
+
const context = {
|
|
4353
|
+
name: extension.name,
|
|
4354
|
+
options: extension.options,
|
|
4355
|
+
storage: extension.storage
|
|
4356
|
+
};
|
|
4357
|
+
return {
|
|
4358
|
+
allowGapCursor: (_a = callOrReturn(getExtensionField(extension, "allowGapCursor", context))) != null ? _a : null
|
|
4359
|
+
};
|
|
4360
|
+
}
|
|
4361
|
+
});
|
|
4362
|
+
var DEFAULT_DATA_ATTRIBUTE = "placeholder";
|
|
4363
|
+
function preparePlaceholderAttribute(attr) {
|
|
4364
|
+
return attr.replace(/\s+/g, "-").replace(/[^a-zA-Z0-9-]/g, "").replace(/^[0-9-]+/, "").replace(/^-+/, "").toLowerCase();
|
|
4365
|
+
}
|
|
4366
|
+
Extension.create({
|
|
4367
|
+
name: "placeholder",
|
|
4368
|
+
addOptions() {
|
|
4369
|
+
return {
|
|
4370
|
+
emptyEditorClass: "is-editor-empty",
|
|
4371
|
+
emptyNodeClass: "is-empty",
|
|
4372
|
+
dataAttribute: DEFAULT_DATA_ATTRIBUTE,
|
|
4373
|
+
placeholder: "Write something …",
|
|
4374
|
+
showOnlyWhenEditable: true,
|
|
4375
|
+
showOnlyCurrent: true,
|
|
4376
|
+
includeChildren: false
|
|
4377
|
+
};
|
|
4378
|
+
},
|
|
4379
|
+
addProseMirrorPlugins() {
|
|
4380
|
+
const dataAttribute = this.options.dataAttribute ? `data-${preparePlaceholderAttribute(this.options.dataAttribute)}` : `data-${DEFAULT_DATA_ATTRIBUTE}`;
|
|
4381
|
+
return [
|
|
4382
|
+
new Plugin({
|
|
4383
|
+
key: new PluginKey("placeholder"),
|
|
4384
|
+
props: {
|
|
4385
|
+
decorations: ({ doc, selection }) => {
|
|
4386
|
+
const active = this.editor.isEditable || !this.options.showOnlyWhenEditable;
|
|
4387
|
+
const { anchor } = selection;
|
|
4388
|
+
const decorations = [];
|
|
4389
|
+
if (!active) {
|
|
4390
|
+
return null;
|
|
4391
|
+
}
|
|
4392
|
+
const isEmptyDoc = this.editor.isEmpty;
|
|
4393
|
+
doc.descendants((node, pos) => {
|
|
4394
|
+
const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
|
|
4395
|
+
const isEmpty = !node.isLeaf && isNodeEmpty(node);
|
|
4396
|
+
if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
|
|
4397
|
+
const classes = [this.options.emptyNodeClass];
|
|
4398
|
+
if (isEmptyDoc) {
|
|
4399
|
+
classes.push(this.options.emptyEditorClass);
|
|
4400
|
+
}
|
|
4401
|
+
const decoration = Decoration.node(pos, pos + node.nodeSize, {
|
|
4402
|
+
class: classes.join(" "),
|
|
4403
|
+
[dataAttribute]: typeof this.options.placeholder === "function" ? this.options.placeholder({
|
|
4404
|
+
editor: this.editor,
|
|
4405
|
+
node,
|
|
4406
|
+
pos,
|
|
4407
|
+
hasAnchor
|
|
4408
|
+
}) : this.options.placeholder
|
|
4409
|
+
});
|
|
4410
|
+
decorations.push(decoration);
|
|
4411
|
+
}
|
|
4412
|
+
return this.options.includeChildren;
|
|
4413
|
+
});
|
|
4414
|
+
return DecorationSet.create(doc, decorations);
|
|
4415
|
+
}
|
|
4416
|
+
}
|
|
4417
|
+
})
|
|
4418
|
+
];
|
|
4419
|
+
}
|
|
4420
|
+
});
|
|
4421
|
+
Extension.create({
|
|
4422
|
+
name: "selection",
|
|
4423
|
+
addOptions() {
|
|
4424
|
+
return {
|
|
4425
|
+
className: "selection"
|
|
4426
|
+
};
|
|
4427
|
+
},
|
|
4428
|
+
addProseMirrorPlugins() {
|
|
4429
|
+
const { editor, options } = this;
|
|
4430
|
+
return [
|
|
4431
|
+
new Plugin({
|
|
4432
|
+
key: new PluginKey("selection"),
|
|
4433
|
+
props: {
|
|
4434
|
+
decorations(state) {
|
|
4435
|
+
if (state.selection.empty || editor.isFocused || !editor.isEditable || isNodeSelection(state.selection) || editor.view.dragging) {
|
|
4436
|
+
return null;
|
|
4437
|
+
}
|
|
4438
|
+
return DecorationSet.create(state.doc, [
|
|
4439
|
+
Decoration.inline(state.selection.from, state.selection.to, {
|
|
4440
|
+
class: options.className
|
|
4441
|
+
})
|
|
4442
|
+
]);
|
|
4443
|
+
}
|
|
4327
4444
|
}
|
|
4328
|
-
)
|
|
4329
|
-
|
|
4330
|
-
|
|
4445
|
+
})
|
|
4446
|
+
];
|
|
4447
|
+
}
|
|
4448
|
+
});
|
|
4449
|
+
function nodeEqualsType({ types, node }) {
|
|
4450
|
+
return node && Array.isArray(types) && types.includes(node.type) || (node == null ? void 0 : node.type) === types;
|
|
4331
4451
|
}
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
{
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4452
|
+
Extension.create({
|
|
4453
|
+
name: "trailingNode",
|
|
4454
|
+
addOptions() {
|
|
4455
|
+
return {
|
|
4456
|
+
node: void 0,
|
|
4457
|
+
notAfter: []
|
|
4458
|
+
};
|
|
4459
|
+
},
|
|
4460
|
+
addProseMirrorPlugins() {
|
|
4461
|
+
var _a;
|
|
4462
|
+
const plugin = new PluginKey(this.name);
|
|
4463
|
+
const defaultNode = this.options.node || ((_a = this.editor.schema.topNodeType.contentMatch.defaultType) == null ? void 0 : _a.name) || "paragraph";
|
|
4464
|
+
const disabledNodes = Object.entries(this.editor.schema.nodes).map(([, value]) => value).filter((node) => (this.options.notAfter || []).concat(defaultNode).includes(node.name));
|
|
4465
|
+
return [
|
|
4466
|
+
new Plugin({
|
|
4467
|
+
key: plugin,
|
|
4468
|
+
appendTransaction: (_, __, state) => {
|
|
4469
|
+
const { doc, tr, schema } = state;
|
|
4470
|
+
const shouldInsertNodeAtEnd = plugin.getState(state);
|
|
4471
|
+
const endPosition = doc.content.size;
|
|
4472
|
+
const type = schema.nodes[defaultNode];
|
|
4473
|
+
if (!shouldInsertNodeAtEnd) {
|
|
4474
|
+
return;
|
|
4475
|
+
}
|
|
4476
|
+
return tr.insert(endPosition, type.create());
|
|
4477
|
+
},
|
|
4478
|
+
state: {
|
|
4479
|
+
init: (_, state) => {
|
|
4480
|
+
const lastNode = state.tr.doc.lastChild;
|
|
4481
|
+
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
|
|
4482
|
+
},
|
|
4483
|
+
apply: (tr, value) => {
|
|
4484
|
+
if (!tr.docChanged) {
|
|
4485
|
+
return value;
|
|
4486
|
+
}
|
|
4487
|
+
if (tr.getMeta("__uniqueIDTransaction")) {
|
|
4488
|
+
return value;
|
|
4489
|
+
}
|
|
4490
|
+
const lastNode = tr.doc.lastChild;
|
|
4491
|
+
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
|
|
4492
|
+
}
|
|
4350
4493
|
}
|
|
4351
|
-
)
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
}
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
}
|
|
4366
|
-
|
|
4367
|
-
});
|
|
4368
|
-
const setTextAlign = (alignment) => {
|
|
4369
|
-
editor.chain().focus().setTextAlign(alignment).run();
|
|
4370
|
-
};
|
|
4371
|
-
return {
|
|
4372
|
-
textAlignLeftButton: /* @__PURE__ */ jsx(
|
|
4373
|
-
ToolbarButton,
|
|
4374
|
-
{
|
|
4375
|
-
onClick: () => setTextAlign("left"),
|
|
4376
|
-
icon: /* @__PURE__ */ jsx(TextAlignLeft, {}),
|
|
4377
|
-
active: editorState.isTextAlignLeft,
|
|
4378
|
-
disabled: props.disabled || !editor || !editorState.canToggleAlign,
|
|
4379
|
-
tooltip: "Text Align Left"
|
|
4380
|
-
},
|
|
4381
|
-
"text-align-left"
|
|
4382
|
-
),
|
|
4383
|
-
textAlignCenterButton: /* @__PURE__ */ jsx(
|
|
4384
|
-
ToolbarButton,
|
|
4385
|
-
{
|
|
4386
|
-
onClick: () => setTextAlign("center"),
|
|
4387
|
-
icon: /* @__PURE__ */ jsx(TextAlignCenter, {}),
|
|
4388
|
-
active: editorState.isTextAlignCenter,
|
|
4389
|
-
disabled: props.disabled || !editor || !editorState.canToggleAlign,
|
|
4390
|
-
tooltip: "Text Align Center"
|
|
4391
|
-
},
|
|
4392
|
-
"text-align-center"
|
|
4393
|
-
),
|
|
4394
|
-
textAlignRightButton: /* @__PURE__ */ jsx(
|
|
4395
|
-
ToolbarButton,
|
|
4396
|
-
{
|
|
4397
|
-
onClick: () => setTextAlign("right"),
|
|
4398
|
-
icon: /* @__PURE__ */ jsx(TextAlignRight, {}),
|
|
4399
|
-
active: editorState.isTextAlignRight,
|
|
4400
|
-
disabled: props.disabled || !editor || !editorState.canToggleAlign,
|
|
4401
|
-
tooltip: "Text Align Right"
|
|
4402
|
-
},
|
|
4403
|
-
"text-align-right"
|
|
4404
|
-
),
|
|
4405
|
-
textAlignJustifyButton: /* @__PURE__ */ jsx(
|
|
4406
|
-
ToolbarButton,
|
|
4407
|
-
{
|
|
4408
|
-
onClick: () => setTextAlign("justify"),
|
|
4409
|
-
icon: /* @__PURE__ */ jsx(TextAlignJustify, {}),
|
|
4410
|
-
active: editorState.isTextAlignJustify,
|
|
4411
|
-
disabled: props.disabled || !editor || !editorState.canToggleAlign,
|
|
4412
|
-
tooltip: "Text Align Justify"
|
|
4494
|
+
})
|
|
4495
|
+
];
|
|
4496
|
+
}
|
|
4497
|
+
});
|
|
4498
|
+
Extension.create({
|
|
4499
|
+
name: "undoRedo",
|
|
4500
|
+
addOptions() {
|
|
4501
|
+
return {
|
|
4502
|
+
depth: 100,
|
|
4503
|
+
newGroupDelay: 500
|
|
4504
|
+
};
|
|
4505
|
+
},
|
|
4506
|
+
addCommands() {
|
|
4507
|
+
return {
|
|
4508
|
+
undo: () => ({ state, dispatch }) => {
|
|
4509
|
+
return undo(state, dispatch);
|
|
4413
4510
|
},
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
}
|
|
4418
|
-
|
|
4419
|
-
|
|
4511
|
+
redo: () => ({ state, dispatch }) => {
|
|
4512
|
+
return redo(state, dispatch);
|
|
4513
|
+
}
|
|
4514
|
+
};
|
|
4515
|
+
},
|
|
4516
|
+
addProseMirrorPlugins() {
|
|
4517
|
+
return [history(this.options)];
|
|
4518
|
+
},
|
|
4519
|
+
addKeyboardShortcuts() {
|
|
4520
|
+
return {
|
|
4521
|
+
"Mod-z": () => this.editor.commands.undo(),
|
|
4522
|
+
"Shift-Mod-z": () => this.editor.commands.redo(),
|
|
4523
|
+
"Mod-y": () => this.editor.commands.redo(),
|
|
4524
|
+
// Russian keyboard layouts
|
|
4525
|
+
"Mod-я": () => this.editor.commands.undo(),
|
|
4526
|
+
"Shift-Mod-я": () => this.editor.commands.redo()
|
|
4527
|
+
};
|
|
4528
|
+
}
|
|
4529
|
+
});
|
|
4530
|
+
const starterKitFeatureValue = (value) => {
|
|
4531
|
+
if (!isFeatureEnabled(value)) {
|
|
4532
|
+
return false;
|
|
4533
|
+
}
|
|
4534
|
+
return getFeatureOptions(value, {}) ?? {};
|
|
4535
|
+
};
|
|
4536
|
+
function buildExtensions(config) {
|
|
4537
|
+
const starterKitConfig = {
|
|
4420
4538
|
heading: false,
|
|
4421
|
-
//
|
|
4422
|
-
|
|
4423
|
-
|
|
4539
|
+
// ALWAYS false — heading handled separately via BaseHeadingWithSEOTag
|
|
4540
|
+
bold: starterKitFeatureValue(config.bold),
|
|
4541
|
+
italic: starterKitFeatureValue(config.italic),
|
|
4542
|
+
strike: starterKitFeatureValue(config.strike),
|
|
4543
|
+
code: starterKitFeatureValue(config.code),
|
|
4544
|
+
codeBlock: starterKitFeatureValue(config.codeBlock),
|
|
4545
|
+
blockquote: starterKitFeatureValue(config.blockquote),
|
|
4546
|
+
bulletList: starterKitFeatureValue(config.bulletList),
|
|
4547
|
+
orderedList: starterKitFeatureValue(config.orderedList),
|
|
4548
|
+
hardBreak: starterKitFeatureValue(config.hardBreak),
|
|
4549
|
+
horizontalRule: starterKitFeatureValue(config.horizontalRule),
|
|
4550
|
+
history: starterKitFeatureValue(config.history),
|
|
4551
|
+
link: !isFeatureEnabled(config.link) ? false : {
|
|
4552
|
+
openOnClick: false,
|
|
4553
|
+
...getFeatureOptions(config.link, {})
|
|
4424
4554
|
}
|
|
4425
|
-
}
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4555
|
+
};
|
|
4556
|
+
const extensions = [
|
|
4557
|
+
StarterKit.configure(starterKitConfig)
|
|
4558
|
+
];
|
|
4559
|
+
if (isFeatureEnabled(config.heading)) {
|
|
4560
|
+
const headingConfig = getFeatureOptions(config.heading, {
|
|
4561
|
+
levels: [1, 2, 3, 4]
|
|
4562
|
+
});
|
|
4563
|
+
const levels = headingConfig?.levels || [1, 2, 3, 4];
|
|
4564
|
+
extensions.push(BaseHeadingWithSEOTag.configure({ levels }));
|
|
4565
|
+
}
|
|
4566
|
+
if (isFeatureEnabled(config.superscript)) {
|
|
4567
|
+
extensions.push(Superscript);
|
|
4568
|
+
}
|
|
4569
|
+
if (isFeatureEnabled(config.subscript)) {
|
|
4570
|
+
extensions.push(Subscript);
|
|
4571
|
+
}
|
|
4572
|
+
if (isFeatureEnabled(config.table)) {
|
|
4573
|
+
extensions.push(
|
|
4574
|
+
TableKit.configure({
|
|
4575
|
+
table: {
|
|
4576
|
+
resizable: true,
|
|
4577
|
+
...getFeatureOptions(config.table, {})
|
|
4578
|
+
}
|
|
4579
|
+
})
|
|
4580
|
+
);
|
|
4581
|
+
}
|
|
4582
|
+
if (isFeatureEnabled(config.textAlign)) {
|
|
4583
|
+
const textAlignConfig = getFeatureOptions(config.textAlign, {
|
|
4584
|
+
types: ["heading", "paragraph"],
|
|
4585
|
+
alignments: ["left", "center", "right", "justify"]
|
|
4586
|
+
});
|
|
4587
|
+
extensions.push(
|
|
4588
|
+
TextAlign.configure({
|
|
4589
|
+
types: textAlignConfig?.types || ["heading", "paragraph"],
|
|
4590
|
+
alignments: textAlignConfig?.alignments || [
|
|
4591
|
+
"left",
|
|
4592
|
+
"center",
|
|
4593
|
+
"right",
|
|
4594
|
+
"justify"
|
|
4595
|
+
]
|
|
4596
|
+
})
|
|
4597
|
+
);
|
|
4598
|
+
}
|
|
4599
|
+
extensions.push(Gapcursor);
|
|
4600
|
+
return extensions;
|
|
4601
|
+
}
|
|
4438
4602
|
const RichTextInput = forwardRef((props, forwardedRef) => {
|
|
4603
|
+
const attribute = props.attribute;
|
|
4604
|
+
const presetName = attribute?.options?.preset;
|
|
4605
|
+
const { config, isLoading } = usePresetConfig(presetName);
|
|
4606
|
+
const extensions = useMemo(() => {
|
|
4607
|
+
if (!config) return [];
|
|
4608
|
+
return buildExtensions(config);
|
|
4609
|
+
}, [presetName]);
|
|
4439
4610
|
const { editor, field } = useTiptapEditor(props.name, "", extensions);
|
|
4440
4611
|
const starterKit = useStarterKit(editor, { disabled: props.disabled });
|
|
4441
4612
|
const heading = useHeading(editor, { disabled: props.disabled });
|
|
@@ -4443,39 +4614,58 @@ const RichTextInput = forwardRef((props, forwardedRef) => {
|
|
|
4443
4614
|
const script = useScript(editor, { disabled: props.disabled });
|
|
4444
4615
|
const table = useTable(editor, { disabled: props.disabled });
|
|
4445
4616
|
const textAlign = useTextAlign(editor, { disabled: props.disabled });
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4617
|
+
if (isLoading) {
|
|
4618
|
+
return /* @__PURE__ */ jsx(Box, { padding: 4, children: "Loading editor..." });
|
|
4619
|
+
}
|
|
4620
|
+
return /* @__PURE__ */ jsx(EditorErrorBoundary, { children: /* @__PURE__ */ jsxs(
|
|
4621
|
+
BaseTiptapInput,
|
|
4622
|
+
{
|
|
4623
|
+
editor,
|
|
4624
|
+
field,
|
|
4625
|
+
...props,
|
|
4626
|
+
ref: forwardedRef,
|
|
4627
|
+
noPresetConfigured: !presetName,
|
|
4628
|
+
children: [
|
|
4629
|
+
/* @__PURE__ */ jsxs(FeatureGuard, { featureValue: config?.heading, children: [
|
|
4630
|
+
heading.headingSelect,
|
|
4631
|
+
heading.headingTagSelect,
|
|
4632
|
+
/* @__PURE__ */ jsx(Spacer, { width: 8 })
|
|
4633
|
+
] }),
|
|
4634
|
+
starterKit.boldButton,
|
|
4635
|
+
starterKit.italicButton,
|
|
4636
|
+
starterKit.underlineButton,
|
|
4637
|
+
starterKit.strikeButton,
|
|
4638
|
+
script.superscriptButton,
|
|
4639
|
+
script.subscriptButton,
|
|
4640
|
+
/* @__PURE__ */ jsx(Spacer, { width: 8 }),
|
|
4641
|
+
/* @__PURE__ */ jsxs(FeatureGuard, { featureValue: config?.textAlign, children: [
|
|
4642
|
+
textAlign.textAlignLeftButton,
|
|
4643
|
+
textAlign.textAlignCenterButton,
|
|
4644
|
+
textAlign.textAlignRightButton,
|
|
4645
|
+
textAlign.textAlignJustifyButton,
|
|
4646
|
+
/* @__PURE__ */ jsx(Spacer, { width: 8 })
|
|
4647
|
+
] }),
|
|
4648
|
+
starterKit.bulletButton,
|
|
4649
|
+
starterKit.orderedButton,
|
|
4650
|
+
/* @__PURE__ */ jsx(Spacer, { width: 8 }),
|
|
4651
|
+
starterKit.codeButton,
|
|
4652
|
+
starterKit.blockquoteButton,
|
|
4653
|
+
link.linkButton,
|
|
4654
|
+
link.linkDialog,
|
|
4655
|
+
/* @__PURE__ */ jsxs(FeatureGuard, { featureValue: config?.table, children: [
|
|
4656
|
+
/* @__PURE__ */ jsx(Spacer, { width: 8 }),
|
|
4657
|
+
table.tableButton,
|
|
4658
|
+
table.addColumnButton,
|
|
4659
|
+
table.removeColumnButton,
|
|
4660
|
+
table.addRowButton,
|
|
4661
|
+
table.removeRowButton,
|
|
4662
|
+
table.tableDialog
|
|
4663
|
+
] })
|
|
4664
|
+
]
|
|
4665
|
+
}
|
|
4666
|
+
) });
|
|
4477
4667
|
});
|
|
4478
4668
|
export {
|
|
4479
4669
|
RichTextInput as default
|
|
4480
4670
|
};
|
|
4481
|
-
//# sourceMappingURL=RichTextInput-
|
|
4671
|
+
//# sourceMappingURL=RichTextInput-COGVRWOW.mjs.map
|