@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,12 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const React = require("react");
|
|
4
5
|
const designSystem = require("@strapi/design-system");
|
|
5
6
|
const react = require("@tiptap/react");
|
|
6
7
|
const styled = require("styled-components");
|
|
7
|
-
const React = require("react");
|
|
8
8
|
const admin = require("@strapi/strapi/admin");
|
|
9
|
-
const StarterKit = require("@tiptap/starter-kit");
|
|
10
9
|
const icons = require("@strapi/icons");
|
|
11
10
|
const transform = require("@tiptap/pm/transform");
|
|
12
11
|
const commands = require("@tiptap/pm/commands");
|
|
@@ -15,16 +14,17 @@ const model = require("@tiptap/pm/model");
|
|
|
15
14
|
const schemaList = require("@tiptap/pm/schema-list");
|
|
16
15
|
const view = require("@tiptap/pm/view");
|
|
17
16
|
require("@tiptap/pm/keymap");
|
|
17
|
+
const StarterKit = require("@tiptap/starter-kit");
|
|
18
18
|
const Superscript = require("@tiptap/extension-superscript");
|
|
19
19
|
const Subscript = require("@tiptap/extension-subscript");
|
|
20
20
|
const extensionTable = require("@tiptap/extension-table");
|
|
21
|
+
const TextAlign = require("@tiptap/extension-text-align");
|
|
21
22
|
const dropcursor = require("@tiptap/pm/dropcursor");
|
|
22
23
|
const gapcursor = require("@tiptap/pm/gapcursor");
|
|
23
24
|
const history = require("@tiptap/pm/history");
|
|
24
|
-
const TextAlign = require("@tiptap/extension-text-align");
|
|
25
25
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
26
|
-
const styled__default = /* @__PURE__ */ _interopDefault(styled);
|
|
27
26
|
const React__default = /* @__PURE__ */ _interopDefault(React);
|
|
27
|
+
const styled__default = /* @__PURE__ */ _interopDefault(styled);
|
|
28
28
|
const StarterKit__default = /* @__PURE__ */ _interopDefault(StarterKit);
|
|
29
29
|
const Superscript__default = /* @__PURE__ */ _interopDefault(Superscript);
|
|
30
30
|
const Subscript__default = /* @__PURE__ */ _interopDefault(Subscript);
|
|
@@ -216,7 +216,7 @@ const TiptapInputStyles = styled__default.default.div`
|
|
|
216
216
|
}
|
|
217
217
|
`;
|
|
218
218
|
const BaseTiptapInput = React.forwardRef(
|
|
219
|
-
({ hint, disabled = false, labelAction, label, name, required = false, editor, field, children }, forwardedRef) => {
|
|
219
|
+
({ hint, disabled = false, labelAction, label, name, required = false, editor, field, children, noPresetConfigured }, forwardedRef) => {
|
|
220
220
|
const borderColor = field.error ? "danger600" : "neutral200";
|
|
221
221
|
const background = disabled ? "neutral200" : "neutral100";
|
|
222
222
|
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name, id: name, hint, error: field.error, required, children: [
|
|
@@ -233,6 +233,7 @@ const BaseTiptapInput = React.forwardRef(
|
|
|
233
233
|
paddingLeft: 0,
|
|
234
234
|
paddingRight: 0,
|
|
235
235
|
children: [
|
|
236
|
+
noPresetConfigured && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingLeft: 2, paddingRight: 2, paddingTop: 2, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Status, { variant: "secondary", showBullet: false, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: "No editor preset configured — showing minimal editor" }) }) }),
|
|
236
237
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { className: "editor-toolbar", paddingLeft: 2, paddingRight: 2, paddingBottom: 2, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 1, wrap: "wrap", children }) }),
|
|
237
238
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
238
239
|
designSystem.Box,
|
|
@@ -254,6 +255,71 @@ const BaseTiptapInput = React.forwardRef(
|
|
|
254
255
|
] });
|
|
255
256
|
}
|
|
256
257
|
);
|
|
258
|
+
class EditorErrorBoundary extends React.Component {
|
|
259
|
+
state = { hasError: false, error: null };
|
|
260
|
+
static getDerivedStateFromError(error) {
|
|
261
|
+
return { hasError: true, error };
|
|
262
|
+
}
|
|
263
|
+
componentDidCatch(error, errorInfo) {
|
|
264
|
+
console.error("[TiptapEditor] Editor crashed:", error, errorInfo);
|
|
265
|
+
}
|
|
266
|
+
handleRetry = () => {
|
|
267
|
+
this.setState({ hasError: false, error: null });
|
|
268
|
+
};
|
|
269
|
+
render() {
|
|
270
|
+
if (this.state.hasError) {
|
|
271
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 4, background: "danger100", hasRadius: true, children: [
|
|
272
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "danger700", children: "The editor encountered an error and could not render." }),
|
|
273
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 2, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "secondary", size: "S", onClick: this.handleRetry, children: "Retry" }) })
|
|
274
|
+
] });
|
|
275
|
+
}
|
|
276
|
+
return this.props.children;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const MINIMAL_PRESET_CONFIG = {
|
|
280
|
+
bold: true,
|
|
281
|
+
italic: true
|
|
282
|
+
};
|
|
283
|
+
const isPlainObject$1 = (value) => {
|
|
284
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
285
|
+
const prototype = Object.getPrototypeOf(value);
|
|
286
|
+
return prototype === Object.prototype || prototype === null;
|
|
287
|
+
};
|
|
288
|
+
const isFeatureEnabled = (value) => {
|
|
289
|
+
if (value === void 0) {
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
if (typeof value === "boolean") {
|
|
293
|
+
return value;
|
|
294
|
+
}
|
|
295
|
+
if (!isPlainObject$1(value)) {
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
const obj = value;
|
|
299
|
+
if (typeof obj.enabled === "boolean") {
|
|
300
|
+
return obj.enabled;
|
|
301
|
+
}
|
|
302
|
+
if (typeof obj.disabled === "boolean") {
|
|
303
|
+
return !obj.disabled;
|
|
304
|
+
}
|
|
305
|
+
return true;
|
|
306
|
+
};
|
|
307
|
+
const getFeatureOptions = (value, defaults) => {
|
|
308
|
+
if (value === false) {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
if (!isPlainObject$1(value)) {
|
|
312
|
+
return defaults;
|
|
313
|
+
}
|
|
314
|
+
const { enabled: _e, disabled: _d, ...rest } = value;
|
|
315
|
+
return { ...defaults, ...rest };
|
|
316
|
+
};
|
|
317
|
+
function FeatureGuard({ featureValue, children }) {
|
|
318
|
+
if (!isFeatureEnabled(featureValue)) {
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
return children;
|
|
322
|
+
}
|
|
257
323
|
function tiptapContent(text) {
|
|
258
324
|
return {
|
|
259
325
|
type: "doc",
|
|
@@ -284,10 +350,10 @@ function parseJSONContent(value, defaultValue) {
|
|
|
284
350
|
`);
|
|
285
351
|
}
|
|
286
352
|
}
|
|
287
|
-
function useTiptapEditor(name, defaultValue = "",
|
|
353
|
+
function useTiptapEditor(name, defaultValue = "", extensions = []) {
|
|
288
354
|
const field = admin.useField(name);
|
|
289
355
|
const editor = react.useEditor({
|
|
290
|
-
extensions
|
|
356
|
+
extensions,
|
|
291
357
|
content: parseJSONContent(field.value, defaultValue),
|
|
292
358
|
onUpdate: ({ editor: editor2 }) => {
|
|
293
359
|
const json = editor2.getJSON();
|
|
@@ -1679,10 +1745,10 @@ function callOrReturn(value, context = void 0, ...props) {
|
|
|
1679
1745
|
}
|
|
1680
1746
|
return value;
|
|
1681
1747
|
}
|
|
1682
|
-
function splitExtensions(
|
|
1683
|
-
const baseExtensions =
|
|
1684
|
-
const nodeExtensions =
|
|
1685
|
-
const markExtensions =
|
|
1748
|
+
function splitExtensions(extensions) {
|
|
1749
|
+
const baseExtensions = extensions.filter((extension) => extension.type === "extension");
|
|
1750
|
+
const nodeExtensions = extensions.filter((extension) => extension.type === "node");
|
|
1751
|
+
const markExtensions = extensions.filter((extension) => extension.type === "mark");
|
|
1686
1752
|
return {
|
|
1687
1753
|
baseExtensions,
|
|
1688
1754
|
nodeExtensions,
|
|
@@ -1871,8 +1937,8 @@ function isMarkActive(state2, typeOrName, attributes = {}) {
|
|
|
1871
1937
|
const range = matchedRange > 0 ? matchedRange + excludedRange : matchedRange;
|
|
1872
1938
|
return range >= selectionRange;
|
|
1873
1939
|
}
|
|
1874
|
-
function isList(name,
|
|
1875
|
-
const { nodeExtensions } = splitExtensions(
|
|
1940
|
+
function isList(name, extensions) {
|
|
1941
|
+
const { nodeExtensions } = splitExtensions(extensions);
|
|
1876
1942
|
const extension = nodeExtensions.find((item) => item.name === name);
|
|
1877
1943
|
if (!extension) {
|
|
1878
1944
|
return false;
|
|
@@ -2258,7 +2324,7 @@ var joinListForwards = (tr, listType) => {
|
|
|
2258
2324
|
return true;
|
|
2259
2325
|
};
|
|
2260
2326
|
var toggleList = (listTypeOrName, itemTypeOrName, keepMarks, attributes = {}) => ({ editor, tr, state: state2, dispatch, chain, commands: commands2, can }) => {
|
|
2261
|
-
const { extensions
|
|
2327
|
+
const { extensions, splittableMarks } = editor.extensionManager;
|
|
2262
2328
|
const listType = getNodeType(listTypeOrName, state2.schema);
|
|
2263
2329
|
const itemType = getNodeType(itemTypeOrName, state2.schema);
|
|
2264
2330
|
const { selection, storedMarks } = state2;
|
|
@@ -2268,12 +2334,12 @@ var toggleList = (listTypeOrName, itemTypeOrName, keepMarks, attributes = {}) =>
|
|
|
2268
2334
|
if (!range) {
|
|
2269
2335
|
return false;
|
|
2270
2336
|
}
|
|
2271
|
-
const parentList = findParentNode((node) => isList(node.type.name,
|
|
2337
|
+
const parentList = findParentNode((node) => isList(node.type.name, extensions))(selection);
|
|
2272
2338
|
if (range.depth >= 1 && parentList && range.depth - parentList.depth <= 1) {
|
|
2273
2339
|
if (parentList.node.type === listType) {
|
|
2274
2340
|
return commands2.liftListItem(itemType);
|
|
2275
2341
|
}
|
|
2276
|
-
if (isList(parentList.node.type.name,
|
|
2342
|
+
if (isList(parentList.node.type.name, extensions) && listType.validContent(parentList.node.content) && dispatch) {
|
|
2277
2343
|
return chain().command(() => {
|
|
2278
2344
|
tr.setNodeMarkup(parentList.pos, listType);
|
|
2279
2345
|
return true;
|
|
@@ -3608,7 +3674,7 @@ var Heading = Node3.create({
|
|
|
3608
3674
|
}
|
|
3609
3675
|
});
|
|
3610
3676
|
var index_default = Heading;
|
|
3611
|
-
const
|
|
3677
|
+
const BaseHeadingWithSEOTag = index_default.extend({
|
|
3612
3678
|
addAttributes() {
|
|
3613
3679
|
return {
|
|
3614
3680
|
...this.parent?.(),
|
|
@@ -3616,7 +3682,8 @@ const HeadingWithSEOTag = index_default.extend({
|
|
|
3616
3682
|
tag: { default: null }
|
|
3617
3683
|
};
|
|
3618
3684
|
}
|
|
3619
|
-
})
|
|
3685
|
+
});
|
|
3686
|
+
BaseHeadingWithSEOTag.configure({ levels: [1, 2, 3, 4] });
|
|
3620
3687
|
function useHeading(editor, props = { disabled: false }) {
|
|
3621
3688
|
const editorState = react.useEditorState({
|
|
3622
3689
|
editor,
|
|
@@ -3735,425 +3802,72 @@ function useScript(editor, props = { disabled: false }) {
|
|
|
3735
3802
|
)
|
|
3736
3803
|
};
|
|
3737
3804
|
}
|
|
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
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
if (initialContentSize > limit) {
|
|
3786
|
-
const over = initialContentSize - limit;
|
|
3787
|
-
const from = 0;
|
|
3788
|
-
const to = over;
|
|
3789
|
-
console.warn(
|
|
3790
|
-
`[CharacterCount] Initial content exceeded limit of ${limit} characters. Content was automatically trimmed.`
|
|
3791
|
-
);
|
|
3792
|
-
const tr = newState.tr.deleteRange(from, to);
|
|
3793
|
-
initialEvaluationDone = true;
|
|
3794
|
-
return tr;
|
|
3795
|
-
}
|
|
3796
|
-
initialEvaluationDone = true;
|
|
3797
|
-
},
|
|
3798
|
-
filterTransaction: (transaction, state2) => {
|
|
3799
|
-
const limit = this.options.limit;
|
|
3800
|
-
if (!transaction.docChanged || limit === 0 || limit === null || limit === void 0) {
|
|
3801
|
-
return true;
|
|
3802
|
-
}
|
|
3803
|
-
const oldSize = this.storage.characters({ node: state2.doc });
|
|
3804
|
-
const newSize = this.storage.characters({ node: transaction.doc });
|
|
3805
|
-
if (newSize <= limit) {
|
|
3806
|
-
return true;
|
|
3807
|
-
}
|
|
3808
|
-
if (oldSize > limit && newSize > limit && newSize <= oldSize) {
|
|
3809
|
-
return true;
|
|
3810
|
-
}
|
|
3811
|
-
if (oldSize > limit && newSize > limit && newSize > oldSize) {
|
|
3812
|
-
return false;
|
|
3813
|
-
}
|
|
3814
|
-
const isPaste = transaction.getMeta("paste");
|
|
3815
|
-
if (!isPaste) {
|
|
3816
|
-
return false;
|
|
3817
|
-
}
|
|
3818
|
-
const pos = transaction.selection.$head.pos;
|
|
3819
|
-
const over = newSize - limit;
|
|
3820
|
-
const from = pos - over;
|
|
3821
|
-
const to = pos;
|
|
3822
|
-
transaction.deleteRange(from, to);
|
|
3823
|
-
const updatedSize = this.storage.characters({ node: transaction.doc });
|
|
3824
|
-
if (updatedSize > limit) {
|
|
3825
|
-
return false;
|
|
3826
|
-
}
|
|
3827
|
-
return true;
|
|
3828
|
-
}
|
|
3829
|
-
})
|
|
3830
|
-
];
|
|
3831
|
-
}
|
|
3832
|
-
});
|
|
3833
|
-
Extension.create({
|
|
3834
|
-
name: "dropCursor",
|
|
3835
|
-
addOptions() {
|
|
3836
|
-
return {
|
|
3837
|
-
color: "currentColor",
|
|
3838
|
-
width: 1,
|
|
3839
|
-
class: void 0
|
|
3840
|
-
};
|
|
3841
|
-
},
|
|
3842
|
-
addProseMirrorPlugins() {
|
|
3843
|
-
return [dropcursor.dropCursor(this.options)];
|
|
3844
|
-
}
|
|
3845
|
-
});
|
|
3846
|
-
Extension.create({
|
|
3847
|
-
name: "focus",
|
|
3848
|
-
addOptions() {
|
|
3849
|
-
return {
|
|
3850
|
-
className: "has-focus",
|
|
3851
|
-
mode: "all"
|
|
3852
|
-
};
|
|
3853
|
-
},
|
|
3854
|
-
addProseMirrorPlugins() {
|
|
3855
|
-
return [
|
|
3856
|
-
new state.Plugin({
|
|
3857
|
-
key: new state.PluginKey("focus"),
|
|
3858
|
-
props: {
|
|
3859
|
-
decorations: ({ doc, selection }) => {
|
|
3860
|
-
const { isEditable, isFocused } = this.editor;
|
|
3861
|
-
const { anchor } = selection;
|
|
3862
|
-
const decorations = [];
|
|
3863
|
-
if (!isEditable || !isFocused) {
|
|
3864
|
-
return view.DecorationSet.create(doc, []);
|
|
3865
|
-
}
|
|
3866
|
-
let maxLevels = 0;
|
|
3867
|
-
if (this.options.mode === "deepest") {
|
|
3868
|
-
doc.descendants((node, pos) => {
|
|
3869
|
-
if (node.isText) {
|
|
3870
|
-
return;
|
|
3871
|
-
}
|
|
3872
|
-
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
|
|
3873
|
-
if (!isCurrent) {
|
|
3874
|
-
return false;
|
|
3875
|
-
}
|
|
3876
|
-
maxLevels += 1;
|
|
3877
|
-
});
|
|
3878
|
-
}
|
|
3879
|
-
let currentLevel = 0;
|
|
3880
|
-
doc.descendants((node, pos) => {
|
|
3881
|
-
if (node.isText) {
|
|
3882
|
-
return false;
|
|
3883
|
-
}
|
|
3884
|
-
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
|
|
3885
|
-
if (!isCurrent) {
|
|
3886
|
-
return false;
|
|
3805
|
+
const clamp = (val, min, max) => Math.max(min, Math.min(max, val));
|
|
3806
|
+
const parseNum = (value, fallback) => {
|
|
3807
|
+
const n = Number(value);
|
|
3808
|
+
return Number.isFinite(n) ? n : fallback;
|
|
3809
|
+
};
|
|
3810
|
+
const TableSizeDialog = ({
|
|
3811
|
+
open,
|
|
3812
|
+
defaultRows = 3,
|
|
3813
|
+
defaultCols = 3,
|
|
3814
|
+
onClose,
|
|
3815
|
+
onSave
|
|
3816
|
+
}) => {
|
|
3817
|
+
const [rows, setRows] = React.useState(defaultRows);
|
|
3818
|
+
const [cols, setCols] = React.useState(defaultCols);
|
|
3819
|
+
React.useEffect(() => {
|
|
3820
|
+
if (open) {
|
|
3821
|
+
setRows(defaultRows);
|
|
3822
|
+
setCols(defaultCols);
|
|
3823
|
+
}
|
|
3824
|
+
}, [open, defaultRows, defaultCols]);
|
|
3825
|
+
const min = 1;
|
|
3826
|
+
const max = 10;
|
|
3827
|
+
const isValid = rows >= min && rows <= max && cols >= min && cols <= max;
|
|
3828
|
+
const handleSave = () => {
|
|
3829
|
+
if (!isValid) return;
|
|
3830
|
+
onSave(clamp(rows, min, max), clamp(cols, min, max));
|
|
3831
|
+
};
|
|
3832
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3833
|
+
designSystem.Dialog.Root,
|
|
3834
|
+
{
|
|
3835
|
+
open,
|
|
3836
|
+
onOpenChange: (v) => {
|
|
3837
|
+
if (!v) onClose();
|
|
3838
|
+
},
|
|
3839
|
+
children: open && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
|
|
3840
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: "Insert table" }),
|
|
3841
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 4, alignItems: "flex-end", children: [
|
|
3842
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { width: "100%", children: [
|
|
3843
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Rows" }),
|
|
3844
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3845
|
+
designSystem.TextInput,
|
|
3846
|
+
{
|
|
3847
|
+
name: "table-rows",
|
|
3848
|
+
type: "number",
|
|
3849
|
+
value: String(rows),
|
|
3850
|
+
onChange: (e) => setRows(clamp(parseNum(e.target.value, rows), min, max)),
|
|
3851
|
+
placeholder: String(defaultRows)
|
|
3887
3852
|
}
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
var Gapcursor = Extension.create({
|
|
3907
|
-
name: "gapCursor",
|
|
3908
|
-
addProseMirrorPlugins() {
|
|
3909
|
-
return [gapcursor.gapCursor()];
|
|
3910
|
-
},
|
|
3911
|
-
extendNodeSchema(extension) {
|
|
3912
|
-
var _a;
|
|
3913
|
-
const context = {
|
|
3914
|
-
name: extension.name,
|
|
3915
|
-
options: extension.options,
|
|
3916
|
-
storage: extension.storage
|
|
3917
|
-
};
|
|
3918
|
-
return {
|
|
3919
|
-
allowGapCursor: (_a = callOrReturn(getExtensionField(extension, "allowGapCursor", context))) != null ? _a : null
|
|
3920
|
-
};
|
|
3921
|
-
}
|
|
3922
|
-
});
|
|
3923
|
-
var DEFAULT_DATA_ATTRIBUTE = "placeholder";
|
|
3924
|
-
function preparePlaceholderAttribute(attr) {
|
|
3925
|
-
return attr.replace(/\s+/g, "-").replace(/[^a-zA-Z0-9-]/g, "").replace(/^[0-9-]+/, "").replace(/^-+/, "").toLowerCase();
|
|
3926
|
-
}
|
|
3927
|
-
Extension.create({
|
|
3928
|
-
name: "placeholder",
|
|
3929
|
-
addOptions() {
|
|
3930
|
-
return {
|
|
3931
|
-
emptyEditorClass: "is-editor-empty",
|
|
3932
|
-
emptyNodeClass: "is-empty",
|
|
3933
|
-
dataAttribute: DEFAULT_DATA_ATTRIBUTE,
|
|
3934
|
-
placeholder: "Write something …",
|
|
3935
|
-
showOnlyWhenEditable: true,
|
|
3936
|
-
showOnlyCurrent: true,
|
|
3937
|
-
includeChildren: false
|
|
3938
|
-
};
|
|
3939
|
-
},
|
|
3940
|
-
addProseMirrorPlugins() {
|
|
3941
|
-
const dataAttribute = this.options.dataAttribute ? `data-${preparePlaceholderAttribute(this.options.dataAttribute)}` : `data-${DEFAULT_DATA_ATTRIBUTE}`;
|
|
3942
|
-
return [
|
|
3943
|
-
new state.Plugin({
|
|
3944
|
-
key: new state.PluginKey("placeholder"),
|
|
3945
|
-
props: {
|
|
3946
|
-
decorations: ({ doc, selection }) => {
|
|
3947
|
-
const active = this.editor.isEditable || !this.options.showOnlyWhenEditable;
|
|
3948
|
-
const { anchor } = selection;
|
|
3949
|
-
const decorations = [];
|
|
3950
|
-
if (!active) {
|
|
3951
|
-
return null;
|
|
3952
|
-
}
|
|
3953
|
-
const isEmptyDoc = this.editor.isEmpty;
|
|
3954
|
-
doc.descendants((node, pos) => {
|
|
3955
|
-
const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
|
|
3956
|
-
const isEmpty = !node.isLeaf && isNodeEmpty(node);
|
|
3957
|
-
if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
|
|
3958
|
-
const classes = [this.options.emptyNodeClass];
|
|
3959
|
-
if (isEmptyDoc) {
|
|
3960
|
-
classes.push(this.options.emptyEditorClass);
|
|
3961
|
-
}
|
|
3962
|
-
const decoration = view.Decoration.node(pos, pos + node.nodeSize, {
|
|
3963
|
-
class: classes.join(" "),
|
|
3964
|
-
[dataAttribute]: typeof this.options.placeholder === "function" ? this.options.placeholder({
|
|
3965
|
-
editor: this.editor,
|
|
3966
|
-
node,
|
|
3967
|
-
pos,
|
|
3968
|
-
hasAnchor
|
|
3969
|
-
}) : this.options.placeholder
|
|
3970
|
-
});
|
|
3971
|
-
decorations.push(decoration);
|
|
3972
|
-
}
|
|
3973
|
-
return this.options.includeChildren;
|
|
3974
|
-
});
|
|
3975
|
-
return view.DecorationSet.create(doc, decorations);
|
|
3976
|
-
}
|
|
3977
|
-
}
|
|
3978
|
-
})
|
|
3979
|
-
];
|
|
3980
|
-
}
|
|
3981
|
-
});
|
|
3982
|
-
Extension.create({
|
|
3983
|
-
name: "selection",
|
|
3984
|
-
addOptions() {
|
|
3985
|
-
return {
|
|
3986
|
-
className: "selection"
|
|
3987
|
-
};
|
|
3988
|
-
},
|
|
3989
|
-
addProseMirrorPlugins() {
|
|
3990
|
-
const { editor, options } = this;
|
|
3991
|
-
return [
|
|
3992
|
-
new state.Plugin({
|
|
3993
|
-
key: new state.PluginKey("selection"),
|
|
3994
|
-
props: {
|
|
3995
|
-
decorations(state2) {
|
|
3996
|
-
if (state2.selection.empty || editor.isFocused || !editor.isEditable || isNodeSelection(state2.selection) || editor.view.dragging) {
|
|
3997
|
-
return null;
|
|
3998
|
-
}
|
|
3999
|
-
return view.DecorationSet.create(state2.doc, [
|
|
4000
|
-
view.Decoration.inline(state2.selection.from, state2.selection.to, {
|
|
4001
|
-
class: options.className
|
|
4002
|
-
})
|
|
4003
|
-
]);
|
|
4004
|
-
}
|
|
4005
|
-
}
|
|
4006
|
-
})
|
|
4007
|
-
];
|
|
4008
|
-
}
|
|
4009
|
-
});
|
|
4010
|
-
function nodeEqualsType({ types, node }) {
|
|
4011
|
-
return node && Array.isArray(types) && types.includes(node.type) || (node == null ? void 0 : node.type) === types;
|
|
4012
|
-
}
|
|
4013
|
-
Extension.create({
|
|
4014
|
-
name: "trailingNode",
|
|
4015
|
-
addOptions() {
|
|
4016
|
-
return {
|
|
4017
|
-
node: void 0,
|
|
4018
|
-
notAfter: []
|
|
4019
|
-
};
|
|
4020
|
-
},
|
|
4021
|
-
addProseMirrorPlugins() {
|
|
4022
|
-
var _a;
|
|
4023
|
-
const plugin = new state.PluginKey(this.name);
|
|
4024
|
-
const defaultNode = this.options.node || ((_a = this.editor.schema.topNodeType.contentMatch.defaultType) == null ? void 0 : _a.name) || "paragraph";
|
|
4025
|
-
const disabledNodes = Object.entries(this.editor.schema.nodes).map(([, value]) => value).filter((node) => (this.options.notAfter || []).concat(defaultNode).includes(node.name));
|
|
4026
|
-
return [
|
|
4027
|
-
new state.Plugin({
|
|
4028
|
-
key: plugin,
|
|
4029
|
-
appendTransaction: (_, __, state2) => {
|
|
4030
|
-
const { doc, tr, schema } = state2;
|
|
4031
|
-
const shouldInsertNodeAtEnd = plugin.getState(state2);
|
|
4032
|
-
const endPosition = doc.content.size;
|
|
4033
|
-
const type = schema.nodes[defaultNode];
|
|
4034
|
-
if (!shouldInsertNodeAtEnd) {
|
|
4035
|
-
return;
|
|
4036
|
-
}
|
|
4037
|
-
return tr.insert(endPosition, type.create());
|
|
4038
|
-
},
|
|
4039
|
-
state: {
|
|
4040
|
-
init: (_, state2) => {
|
|
4041
|
-
const lastNode = state2.tr.doc.lastChild;
|
|
4042
|
-
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
|
|
4043
|
-
},
|
|
4044
|
-
apply: (tr, value) => {
|
|
4045
|
-
if (!tr.docChanged) {
|
|
4046
|
-
return value;
|
|
4047
|
-
}
|
|
4048
|
-
if (tr.getMeta("__uniqueIDTransaction")) {
|
|
4049
|
-
return value;
|
|
4050
|
-
}
|
|
4051
|
-
const lastNode = tr.doc.lastChild;
|
|
4052
|
-
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
|
|
4053
|
-
}
|
|
4054
|
-
}
|
|
4055
|
-
})
|
|
4056
|
-
];
|
|
4057
|
-
}
|
|
4058
|
-
});
|
|
4059
|
-
Extension.create({
|
|
4060
|
-
name: "undoRedo",
|
|
4061
|
-
addOptions() {
|
|
4062
|
-
return {
|
|
4063
|
-
depth: 100,
|
|
4064
|
-
newGroupDelay: 500
|
|
4065
|
-
};
|
|
4066
|
-
},
|
|
4067
|
-
addCommands() {
|
|
4068
|
-
return {
|
|
4069
|
-
undo: () => ({ state: state2, dispatch }) => {
|
|
4070
|
-
return history.undo(state2, dispatch);
|
|
4071
|
-
},
|
|
4072
|
-
redo: () => ({ state: state2, dispatch }) => {
|
|
4073
|
-
return history.redo(state2, dispatch);
|
|
4074
|
-
}
|
|
4075
|
-
};
|
|
4076
|
-
},
|
|
4077
|
-
addProseMirrorPlugins() {
|
|
4078
|
-
return [history.history(this.options)];
|
|
4079
|
-
},
|
|
4080
|
-
addKeyboardShortcuts() {
|
|
4081
|
-
return {
|
|
4082
|
-
"Mod-z": () => this.editor.commands.undo(),
|
|
4083
|
-
"Shift-Mod-z": () => this.editor.commands.redo(),
|
|
4084
|
-
"Mod-y": () => this.editor.commands.redo(),
|
|
4085
|
-
// Russian keyboard layouts
|
|
4086
|
-
"Mod-я": () => this.editor.commands.undo(),
|
|
4087
|
-
"Shift-Mod-я": () => this.editor.commands.redo()
|
|
4088
|
-
};
|
|
4089
|
-
}
|
|
4090
|
-
});
|
|
4091
|
-
const clamp = (val, min, max) => Math.max(min, Math.min(max, val));
|
|
4092
|
-
const parseNum = (value, fallback) => {
|
|
4093
|
-
const n = Number(value);
|
|
4094
|
-
return Number.isFinite(n) ? n : fallback;
|
|
4095
|
-
};
|
|
4096
|
-
const TableSizeDialog = ({
|
|
4097
|
-
open,
|
|
4098
|
-
defaultRows = 3,
|
|
4099
|
-
defaultCols = 3,
|
|
4100
|
-
onClose,
|
|
4101
|
-
onSave
|
|
4102
|
-
}) => {
|
|
4103
|
-
const [rows, setRows] = React.useState(defaultRows);
|
|
4104
|
-
const [cols, setCols] = React.useState(defaultCols);
|
|
4105
|
-
React.useEffect(() => {
|
|
4106
|
-
if (open) {
|
|
4107
|
-
setRows(defaultRows);
|
|
4108
|
-
setCols(defaultCols);
|
|
4109
|
-
}
|
|
4110
|
-
}, [open, defaultRows, defaultCols]);
|
|
4111
|
-
const min = 1;
|
|
4112
|
-
const max = 10;
|
|
4113
|
-
const isValid = rows >= min && rows <= max && cols >= min && cols <= max;
|
|
4114
|
-
const handleSave = () => {
|
|
4115
|
-
if (!isValid) return;
|
|
4116
|
-
onSave(clamp(rows, min, max), clamp(cols, min, max));
|
|
4117
|
-
};
|
|
4118
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4119
|
-
designSystem.Dialog.Root,
|
|
4120
|
-
{
|
|
4121
|
-
open,
|
|
4122
|
-
onOpenChange: (v) => {
|
|
4123
|
-
if (!v) onClose();
|
|
4124
|
-
},
|
|
4125
|
-
children: open && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
|
|
4126
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: "Insert table" }),
|
|
4127
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 4, alignItems: "flex-end", children: [
|
|
4128
|
-
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { width: "100%", children: [
|
|
4129
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Rows" }),
|
|
4130
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4131
|
-
designSystem.TextInput,
|
|
4132
|
-
{
|
|
4133
|
-
name: "table-rows",
|
|
4134
|
-
type: "number",
|
|
4135
|
-
value: String(rows),
|
|
4136
|
-
onChange: (e) => setRows(clamp(parseNum(e.target.value, rows), min, max)),
|
|
4137
|
-
placeholder: String(defaultRows)
|
|
4138
|
-
}
|
|
4139
|
-
),
|
|
4140
|
-
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Hint, { children: [
|
|
4141
|
-
"Min ",
|
|
4142
|
-
min,
|
|
4143
|
-
", max ",
|
|
4144
|
-
max
|
|
4145
|
-
] })
|
|
4146
|
-
] }),
|
|
4147
|
-
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { width: "100%", children: [
|
|
4148
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Columns" }),
|
|
4149
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4150
|
-
designSystem.TextInput,
|
|
4151
|
-
{
|
|
4152
|
-
name: "table-cols",
|
|
4153
|
-
type: "number",
|
|
4154
|
-
value: String(cols),
|
|
4155
|
-
onChange: (e) => setCols(clamp(parseNum(e.target.value, cols), min, max)),
|
|
4156
|
-
placeholder: String(defaultCols)
|
|
3853
|
+
),
|
|
3854
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Hint, { children: [
|
|
3855
|
+
"Min ",
|
|
3856
|
+
min,
|
|
3857
|
+
", max ",
|
|
3858
|
+
max
|
|
3859
|
+
] })
|
|
3860
|
+
] }),
|
|
3861
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { width: "100%", children: [
|
|
3862
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Columns" }),
|
|
3863
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3864
|
+
designSystem.TextInput,
|
|
3865
|
+
{
|
|
3866
|
+
name: "table-cols",
|
|
3867
|
+
type: "number",
|
|
3868
|
+
value: String(cols),
|
|
3869
|
+
onChange: (e) => setCols(clamp(parseNum(e.target.value, cols), min, max)),
|
|
3870
|
+
placeholder: String(defaultCols)
|
|
4157
3871
|
}
|
|
4158
3872
|
),
|
|
4159
3873
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Hint, { children: [
|
|
@@ -4311,140 +4025,597 @@ function TextAlignJustify(props) {
|
|
|
4311
4025
|
"stroke-linecap": "round",
|
|
4312
4026
|
"stroke-linejoin": "round"
|
|
4313
4027
|
}
|
|
4314
|
-
)
|
|
4315
|
-
}
|
|
4316
|
-
);
|
|
4317
|
-
}
|
|
4318
|
-
function TextAlignRight(props) {
|
|
4319
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4320
|
-
"svg",
|
|
4321
|
-
{
|
|
4322
|
-
width: "16",
|
|
4323
|
-
height: "16",
|
|
4324
|
-
viewBox: "0 0 24 24",
|
|
4325
|
-
fill: "currentColor",
|
|
4326
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
4327
|
-
...props,
|
|
4328
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4329
|
-
"path",
|
|
4330
|
-
{
|
|
4331
|
-
d: "M8 10H21M3 14H21M8 18H21M3 6H21",
|
|
4332
|
-
stroke: "currentColor",
|
|
4333
|
-
"stroke-width": "2",
|
|
4334
|
-
"stroke-linecap": "round",
|
|
4335
|
-
"stroke-linejoin": "round"
|
|
4028
|
+
)
|
|
4029
|
+
}
|
|
4030
|
+
);
|
|
4031
|
+
}
|
|
4032
|
+
function TextAlignRight(props) {
|
|
4033
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4034
|
+
"svg",
|
|
4035
|
+
{
|
|
4036
|
+
width: "16",
|
|
4037
|
+
height: "16",
|
|
4038
|
+
viewBox: "0 0 24 24",
|
|
4039
|
+
fill: "currentColor",
|
|
4040
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4041
|
+
...props,
|
|
4042
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4043
|
+
"path",
|
|
4044
|
+
{
|
|
4045
|
+
d: "M8 10H21M3 14H21M8 18H21M3 6H21",
|
|
4046
|
+
stroke: "currentColor",
|
|
4047
|
+
"stroke-width": "2",
|
|
4048
|
+
"stroke-linecap": "round",
|
|
4049
|
+
"stroke-linejoin": "round"
|
|
4050
|
+
}
|
|
4051
|
+
)
|
|
4052
|
+
}
|
|
4053
|
+
);
|
|
4054
|
+
}
|
|
4055
|
+
function TextAlignCenter(props) {
|
|
4056
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4057
|
+
"svg",
|
|
4058
|
+
{
|
|
4059
|
+
width: "16",
|
|
4060
|
+
height: "16",
|
|
4061
|
+
viewBox: "0 0 24 24",
|
|
4062
|
+
fill: "currentColor",
|
|
4063
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4064
|
+
...props,
|
|
4065
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4066
|
+
"path",
|
|
4067
|
+
{
|
|
4068
|
+
d: "M3 6H21M3 14H21M17 10H7M17 18H7",
|
|
4069
|
+
stroke: "currentColor",
|
|
4070
|
+
"stroke-width": "2",
|
|
4071
|
+
"stroke-linecap": "round",
|
|
4072
|
+
"stroke-linejoin": "round"
|
|
4073
|
+
}
|
|
4074
|
+
)
|
|
4075
|
+
}
|
|
4076
|
+
);
|
|
4077
|
+
}
|
|
4078
|
+
function useTextAlign(editor, props = { disabled: false }) {
|
|
4079
|
+
const editorState = react.useEditorState({
|
|
4080
|
+
editor,
|
|
4081
|
+
selector: (ctx) => {
|
|
4082
|
+
return {
|
|
4083
|
+
isTextAlignLeft: ctx.editor.isActive({ textAlign: "left" }) ?? false,
|
|
4084
|
+
isTextAlignRight: ctx.editor.isActive({ textAlign: "right" }) ?? false,
|
|
4085
|
+
isTextAlignCenter: ctx.editor.isActive({ textAlign: "center" }) ?? false,
|
|
4086
|
+
isTextAlignJustify: ctx.editor.isActive({ textAlign: "justify" }) ?? false,
|
|
4087
|
+
canToggleAlign: ctx.editor.can().chain().setTextAlign("left").run() ?? false
|
|
4088
|
+
};
|
|
4089
|
+
}
|
|
4090
|
+
});
|
|
4091
|
+
const setTextAlign = (alignment) => {
|
|
4092
|
+
editor.chain().focus().setTextAlign(alignment).run();
|
|
4093
|
+
};
|
|
4094
|
+
return {
|
|
4095
|
+
textAlignLeftButton: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4096
|
+
ToolbarButton,
|
|
4097
|
+
{
|
|
4098
|
+
onClick: () => setTextAlign("left"),
|
|
4099
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(TextAlignLeft, {}),
|
|
4100
|
+
active: editorState.isTextAlignLeft,
|
|
4101
|
+
disabled: props.disabled || !editor || !editorState.canToggleAlign,
|
|
4102
|
+
tooltip: "Text Align Left"
|
|
4103
|
+
},
|
|
4104
|
+
"text-align-left"
|
|
4105
|
+
),
|
|
4106
|
+
textAlignCenterButton: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4107
|
+
ToolbarButton,
|
|
4108
|
+
{
|
|
4109
|
+
onClick: () => setTextAlign("center"),
|
|
4110
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(TextAlignCenter, {}),
|
|
4111
|
+
active: editorState.isTextAlignCenter,
|
|
4112
|
+
disabled: props.disabled || !editor || !editorState.canToggleAlign,
|
|
4113
|
+
tooltip: "Text Align Center"
|
|
4114
|
+
},
|
|
4115
|
+
"text-align-center"
|
|
4116
|
+
),
|
|
4117
|
+
textAlignRightButton: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4118
|
+
ToolbarButton,
|
|
4119
|
+
{
|
|
4120
|
+
onClick: () => setTextAlign("right"),
|
|
4121
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(TextAlignRight, {}),
|
|
4122
|
+
active: editorState.isTextAlignRight,
|
|
4123
|
+
disabled: props.disabled || !editor || !editorState.canToggleAlign,
|
|
4124
|
+
tooltip: "Text Align Right"
|
|
4125
|
+
},
|
|
4126
|
+
"text-align-right"
|
|
4127
|
+
),
|
|
4128
|
+
textAlignJustifyButton: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4129
|
+
ToolbarButton,
|
|
4130
|
+
{
|
|
4131
|
+
onClick: () => setTextAlign("justify"),
|
|
4132
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(TextAlignJustify, {}),
|
|
4133
|
+
active: editorState.isTextAlignJustify,
|
|
4134
|
+
disabled: props.disabled || !editor || !editorState.canToggleAlign,
|
|
4135
|
+
tooltip: "Text Align Justify"
|
|
4136
|
+
},
|
|
4137
|
+
"text-align-justify"
|
|
4138
|
+
)
|
|
4139
|
+
};
|
|
4140
|
+
}
|
|
4141
|
+
function usePresetConfig(presetName) {
|
|
4142
|
+
const { get } = admin.useFetchClient();
|
|
4143
|
+
const normalizedPresetName = React.useMemo(
|
|
4144
|
+
() => presetName?.trim() || void 0,
|
|
4145
|
+
[presetName]
|
|
4146
|
+
);
|
|
4147
|
+
const [config, setConfig] = React.useState(
|
|
4148
|
+
normalizedPresetName ? null : MINIMAL_PRESET_CONFIG
|
|
4149
|
+
);
|
|
4150
|
+
const [isLoading, setIsLoading] = React.useState(Boolean(normalizedPresetName));
|
|
4151
|
+
React.useEffect(() => {
|
|
4152
|
+
let mounted = true;
|
|
4153
|
+
if (!normalizedPresetName) {
|
|
4154
|
+
setConfig(MINIMAL_PRESET_CONFIG);
|
|
4155
|
+
setIsLoading(false);
|
|
4156
|
+
return;
|
|
4157
|
+
}
|
|
4158
|
+
const fetchPreset = async () => {
|
|
4159
|
+
setIsLoading(true);
|
|
4160
|
+
try {
|
|
4161
|
+
const response = await get(
|
|
4162
|
+
`/api/tiptap-editor/presets/${normalizedPresetName}`
|
|
4163
|
+
);
|
|
4164
|
+
if (!mounted) return;
|
|
4165
|
+
setConfig(response.data || MINIMAL_PRESET_CONFIG);
|
|
4166
|
+
} catch (error) {
|
|
4167
|
+
console.warn(
|
|
4168
|
+
"[TiptapEditor] Failed to fetch preset config:",
|
|
4169
|
+
error
|
|
4170
|
+
);
|
|
4171
|
+
if (!mounted) return;
|
|
4172
|
+
setConfig(MINIMAL_PRESET_CONFIG);
|
|
4173
|
+
} finally {
|
|
4174
|
+
if (mounted) {
|
|
4175
|
+
setIsLoading(false);
|
|
4176
|
+
}
|
|
4177
|
+
}
|
|
4178
|
+
};
|
|
4179
|
+
fetchPreset();
|
|
4180
|
+
return () => {
|
|
4181
|
+
mounted = false;
|
|
4182
|
+
};
|
|
4183
|
+
}, [get, normalizedPresetName]);
|
|
4184
|
+
return { config, isLoading };
|
|
4185
|
+
}
|
|
4186
|
+
Extension.create({
|
|
4187
|
+
name: "characterCount",
|
|
4188
|
+
addOptions() {
|
|
4189
|
+
return {
|
|
4190
|
+
limit: null,
|
|
4191
|
+
mode: "textSize",
|
|
4192
|
+
textCounter: (text) => text.length,
|
|
4193
|
+
wordCounter: (text) => text.split(" ").filter((word) => word !== "").length
|
|
4194
|
+
};
|
|
4195
|
+
},
|
|
4196
|
+
addStorage() {
|
|
4197
|
+
return {
|
|
4198
|
+
characters: () => 0,
|
|
4199
|
+
words: () => 0
|
|
4200
|
+
};
|
|
4201
|
+
},
|
|
4202
|
+
onBeforeCreate() {
|
|
4203
|
+
this.storage.characters = (options) => {
|
|
4204
|
+
const node = (options == null ? void 0 : options.node) || this.editor.state.doc;
|
|
4205
|
+
const mode = (options == null ? void 0 : options.mode) || this.options.mode;
|
|
4206
|
+
if (mode === "textSize") {
|
|
4207
|
+
const text = node.textBetween(0, node.content.size, void 0, " ");
|
|
4208
|
+
return this.options.textCounter(text);
|
|
4209
|
+
}
|
|
4210
|
+
return node.nodeSize;
|
|
4211
|
+
};
|
|
4212
|
+
this.storage.words = (options) => {
|
|
4213
|
+
const node = (options == null ? void 0 : options.node) || this.editor.state.doc;
|
|
4214
|
+
const text = node.textBetween(0, node.content.size, " ", " ");
|
|
4215
|
+
return this.options.wordCounter(text);
|
|
4216
|
+
};
|
|
4217
|
+
},
|
|
4218
|
+
addProseMirrorPlugins() {
|
|
4219
|
+
let initialEvaluationDone = false;
|
|
4220
|
+
return [
|
|
4221
|
+
new state.Plugin({
|
|
4222
|
+
key: new state.PluginKey("characterCount"),
|
|
4223
|
+
appendTransaction: (transactions, oldState, newState) => {
|
|
4224
|
+
if (initialEvaluationDone) {
|
|
4225
|
+
return;
|
|
4226
|
+
}
|
|
4227
|
+
const limit = this.options.limit;
|
|
4228
|
+
if (limit === null || limit === void 0 || limit === 0) {
|
|
4229
|
+
initialEvaluationDone = true;
|
|
4230
|
+
return;
|
|
4231
|
+
}
|
|
4232
|
+
const initialContentSize = this.storage.characters({ node: newState.doc });
|
|
4233
|
+
if (initialContentSize > limit) {
|
|
4234
|
+
const over = initialContentSize - limit;
|
|
4235
|
+
const from = 0;
|
|
4236
|
+
const to = over;
|
|
4237
|
+
console.warn(
|
|
4238
|
+
`[CharacterCount] Initial content exceeded limit of ${limit} characters. Content was automatically trimmed.`
|
|
4239
|
+
);
|
|
4240
|
+
const tr = newState.tr.deleteRange(from, to);
|
|
4241
|
+
initialEvaluationDone = true;
|
|
4242
|
+
return tr;
|
|
4243
|
+
}
|
|
4244
|
+
initialEvaluationDone = true;
|
|
4245
|
+
},
|
|
4246
|
+
filterTransaction: (transaction, state2) => {
|
|
4247
|
+
const limit = this.options.limit;
|
|
4248
|
+
if (!transaction.docChanged || limit === 0 || limit === null || limit === void 0) {
|
|
4249
|
+
return true;
|
|
4250
|
+
}
|
|
4251
|
+
const oldSize = this.storage.characters({ node: state2.doc });
|
|
4252
|
+
const newSize = this.storage.characters({ node: transaction.doc });
|
|
4253
|
+
if (newSize <= limit) {
|
|
4254
|
+
return true;
|
|
4255
|
+
}
|
|
4256
|
+
if (oldSize > limit && newSize > limit && newSize <= oldSize) {
|
|
4257
|
+
return true;
|
|
4258
|
+
}
|
|
4259
|
+
if (oldSize > limit && newSize > limit && newSize > oldSize) {
|
|
4260
|
+
return false;
|
|
4261
|
+
}
|
|
4262
|
+
const isPaste = transaction.getMeta("paste");
|
|
4263
|
+
if (!isPaste) {
|
|
4264
|
+
return false;
|
|
4265
|
+
}
|
|
4266
|
+
const pos = transaction.selection.$head.pos;
|
|
4267
|
+
const over = newSize - limit;
|
|
4268
|
+
const from = pos - over;
|
|
4269
|
+
const to = pos;
|
|
4270
|
+
transaction.deleteRange(from, to);
|
|
4271
|
+
const updatedSize = this.storage.characters({ node: transaction.doc });
|
|
4272
|
+
if (updatedSize > limit) {
|
|
4273
|
+
return false;
|
|
4274
|
+
}
|
|
4275
|
+
return true;
|
|
4276
|
+
}
|
|
4277
|
+
})
|
|
4278
|
+
];
|
|
4279
|
+
}
|
|
4280
|
+
});
|
|
4281
|
+
Extension.create({
|
|
4282
|
+
name: "dropCursor",
|
|
4283
|
+
addOptions() {
|
|
4284
|
+
return {
|
|
4285
|
+
color: "currentColor",
|
|
4286
|
+
width: 1,
|
|
4287
|
+
class: void 0
|
|
4288
|
+
};
|
|
4289
|
+
},
|
|
4290
|
+
addProseMirrorPlugins() {
|
|
4291
|
+
return [dropcursor.dropCursor(this.options)];
|
|
4292
|
+
}
|
|
4293
|
+
});
|
|
4294
|
+
Extension.create({
|
|
4295
|
+
name: "focus",
|
|
4296
|
+
addOptions() {
|
|
4297
|
+
return {
|
|
4298
|
+
className: "has-focus",
|
|
4299
|
+
mode: "all"
|
|
4300
|
+
};
|
|
4301
|
+
},
|
|
4302
|
+
addProseMirrorPlugins() {
|
|
4303
|
+
return [
|
|
4304
|
+
new state.Plugin({
|
|
4305
|
+
key: new state.PluginKey("focus"),
|
|
4306
|
+
props: {
|
|
4307
|
+
decorations: ({ doc, selection }) => {
|
|
4308
|
+
const { isEditable, isFocused } = this.editor;
|
|
4309
|
+
const { anchor } = selection;
|
|
4310
|
+
const decorations = [];
|
|
4311
|
+
if (!isEditable || !isFocused) {
|
|
4312
|
+
return view.DecorationSet.create(doc, []);
|
|
4313
|
+
}
|
|
4314
|
+
let maxLevels = 0;
|
|
4315
|
+
if (this.options.mode === "deepest") {
|
|
4316
|
+
doc.descendants((node, pos) => {
|
|
4317
|
+
if (node.isText) {
|
|
4318
|
+
return;
|
|
4319
|
+
}
|
|
4320
|
+
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
|
|
4321
|
+
if (!isCurrent) {
|
|
4322
|
+
return false;
|
|
4323
|
+
}
|
|
4324
|
+
maxLevels += 1;
|
|
4325
|
+
});
|
|
4326
|
+
}
|
|
4327
|
+
let currentLevel = 0;
|
|
4328
|
+
doc.descendants((node, pos) => {
|
|
4329
|
+
if (node.isText) {
|
|
4330
|
+
return false;
|
|
4331
|
+
}
|
|
4332
|
+
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
|
|
4333
|
+
if (!isCurrent) {
|
|
4334
|
+
return false;
|
|
4335
|
+
}
|
|
4336
|
+
currentLevel += 1;
|
|
4337
|
+
const outOfScope = this.options.mode === "deepest" && maxLevels - currentLevel > 0 || this.options.mode === "shallowest" && currentLevel > 1;
|
|
4338
|
+
if (outOfScope) {
|
|
4339
|
+
return this.options.mode === "deepest";
|
|
4340
|
+
}
|
|
4341
|
+
decorations.push(
|
|
4342
|
+
view.Decoration.node(pos, pos + node.nodeSize, {
|
|
4343
|
+
class: this.options.className
|
|
4344
|
+
})
|
|
4345
|
+
);
|
|
4346
|
+
});
|
|
4347
|
+
return view.DecorationSet.create(doc, decorations);
|
|
4348
|
+
}
|
|
4349
|
+
}
|
|
4350
|
+
})
|
|
4351
|
+
];
|
|
4352
|
+
}
|
|
4353
|
+
});
|
|
4354
|
+
var Gapcursor = Extension.create({
|
|
4355
|
+
name: "gapCursor",
|
|
4356
|
+
addProseMirrorPlugins() {
|
|
4357
|
+
return [gapcursor.gapCursor()];
|
|
4358
|
+
},
|
|
4359
|
+
extendNodeSchema(extension) {
|
|
4360
|
+
var _a;
|
|
4361
|
+
const context = {
|
|
4362
|
+
name: extension.name,
|
|
4363
|
+
options: extension.options,
|
|
4364
|
+
storage: extension.storage
|
|
4365
|
+
};
|
|
4366
|
+
return {
|
|
4367
|
+
allowGapCursor: (_a = callOrReturn(getExtensionField(extension, "allowGapCursor", context))) != null ? _a : null
|
|
4368
|
+
};
|
|
4369
|
+
}
|
|
4370
|
+
});
|
|
4371
|
+
var DEFAULT_DATA_ATTRIBUTE = "placeholder";
|
|
4372
|
+
function preparePlaceholderAttribute(attr) {
|
|
4373
|
+
return attr.replace(/\s+/g, "-").replace(/[^a-zA-Z0-9-]/g, "").replace(/^[0-9-]+/, "").replace(/^-+/, "").toLowerCase();
|
|
4374
|
+
}
|
|
4375
|
+
Extension.create({
|
|
4376
|
+
name: "placeholder",
|
|
4377
|
+
addOptions() {
|
|
4378
|
+
return {
|
|
4379
|
+
emptyEditorClass: "is-editor-empty",
|
|
4380
|
+
emptyNodeClass: "is-empty",
|
|
4381
|
+
dataAttribute: DEFAULT_DATA_ATTRIBUTE,
|
|
4382
|
+
placeholder: "Write something …",
|
|
4383
|
+
showOnlyWhenEditable: true,
|
|
4384
|
+
showOnlyCurrent: true,
|
|
4385
|
+
includeChildren: false
|
|
4386
|
+
};
|
|
4387
|
+
},
|
|
4388
|
+
addProseMirrorPlugins() {
|
|
4389
|
+
const dataAttribute = this.options.dataAttribute ? `data-${preparePlaceholderAttribute(this.options.dataAttribute)}` : `data-${DEFAULT_DATA_ATTRIBUTE}`;
|
|
4390
|
+
return [
|
|
4391
|
+
new state.Plugin({
|
|
4392
|
+
key: new state.PluginKey("placeholder"),
|
|
4393
|
+
props: {
|
|
4394
|
+
decorations: ({ doc, selection }) => {
|
|
4395
|
+
const active = this.editor.isEditable || !this.options.showOnlyWhenEditable;
|
|
4396
|
+
const { anchor } = selection;
|
|
4397
|
+
const decorations = [];
|
|
4398
|
+
if (!active) {
|
|
4399
|
+
return null;
|
|
4400
|
+
}
|
|
4401
|
+
const isEmptyDoc = this.editor.isEmpty;
|
|
4402
|
+
doc.descendants((node, pos) => {
|
|
4403
|
+
const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
|
|
4404
|
+
const isEmpty = !node.isLeaf && isNodeEmpty(node);
|
|
4405
|
+
if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
|
|
4406
|
+
const classes = [this.options.emptyNodeClass];
|
|
4407
|
+
if (isEmptyDoc) {
|
|
4408
|
+
classes.push(this.options.emptyEditorClass);
|
|
4409
|
+
}
|
|
4410
|
+
const decoration = view.Decoration.node(pos, pos + node.nodeSize, {
|
|
4411
|
+
class: classes.join(" "),
|
|
4412
|
+
[dataAttribute]: typeof this.options.placeholder === "function" ? this.options.placeholder({
|
|
4413
|
+
editor: this.editor,
|
|
4414
|
+
node,
|
|
4415
|
+
pos,
|
|
4416
|
+
hasAnchor
|
|
4417
|
+
}) : this.options.placeholder
|
|
4418
|
+
});
|
|
4419
|
+
decorations.push(decoration);
|
|
4420
|
+
}
|
|
4421
|
+
return this.options.includeChildren;
|
|
4422
|
+
});
|
|
4423
|
+
return view.DecorationSet.create(doc, decorations);
|
|
4424
|
+
}
|
|
4425
|
+
}
|
|
4426
|
+
})
|
|
4427
|
+
];
|
|
4428
|
+
}
|
|
4429
|
+
});
|
|
4430
|
+
Extension.create({
|
|
4431
|
+
name: "selection",
|
|
4432
|
+
addOptions() {
|
|
4433
|
+
return {
|
|
4434
|
+
className: "selection"
|
|
4435
|
+
};
|
|
4436
|
+
},
|
|
4437
|
+
addProseMirrorPlugins() {
|
|
4438
|
+
const { editor, options } = this;
|
|
4439
|
+
return [
|
|
4440
|
+
new state.Plugin({
|
|
4441
|
+
key: new state.PluginKey("selection"),
|
|
4442
|
+
props: {
|
|
4443
|
+
decorations(state2) {
|
|
4444
|
+
if (state2.selection.empty || editor.isFocused || !editor.isEditable || isNodeSelection(state2.selection) || editor.view.dragging) {
|
|
4445
|
+
return null;
|
|
4446
|
+
}
|
|
4447
|
+
return view.DecorationSet.create(state2.doc, [
|
|
4448
|
+
view.Decoration.inline(state2.selection.from, state2.selection.to, {
|
|
4449
|
+
class: options.className
|
|
4450
|
+
})
|
|
4451
|
+
]);
|
|
4452
|
+
}
|
|
4336
4453
|
}
|
|
4337
|
-
)
|
|
4338
|
-
|
|
4339
|
-
|
|
4454
|
+
})
|
|
4455
|
+
];
|
|
4456
|
+
}
|
|
4457
|
+
});
|
|
4458
|
+
function nodeEqualsType({ types, node }) {
|
|
4459
|
+
return node && Array.isArray(types) && types.includes(node.type) || (node == null ? void 0 : node.type) === types;
|
|
4340
4460
|
}
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
{
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4461
|
+
Extension.create({
|
|
4462
|
+
name: "trailingNode",
|
|
4463
|
+
addOptions() {
|
|
4464
|
+
return {
|
|
4465
|
+
node: void 0,
|
|
4466
|
+
notAfter: []
|
|
4467
|
+
};
|
|
4468
|
+
},
|
|
4469
|
+
addProseMirrorPlugins() {
|
|
4470
|
+
var _a;
|
|
4471
|
+
const plugin = new state.PluginKey(this.name);
|
|
4472
|
+
const defaultNode = this.options.node || ((_a = this.editor.schema.topNodeType.contentMatch.defaultType) == null ? void 0 : _a.name) || "paragraph";
|
|
4473
|
+
const disabledNodes = Object.entries(this.editor.schema.nodes).map(([, value]) => value).filter((node) => (this.options.notAfter || []).concat(defaultNode).includes(node.name));
|
|
4474
|
+
return [
|
|
4475
|
+
new state.Plugin({
|
|
4476
|
+
key: plugin,
|
|
4477
|
+
appendTransaction: (_, __, state2) => {
|
|
4478
|
+
const { doc, tr, schema } = state2;
|
|
4479
|
+
const shouldInsertNodeAtEnd = plugin.getState(state2);
|
|
4480
|
+
const endPosition = doc.content.size;
|
|
4481
|
+
const type = schema.nodes[defaultNode];
|
|
4482
|
+
if (!shouldInsertNodeAtEnd) {
|
|
4483
|
+
return;
|
|
4484
|
+
}
|
|
4485
|
+
return tr.insert(endPosition, type.create());
|
|
4486
|
+
},
|
|
4487
|
+
state: {
|
|
4488
|
+
init: (_, state2) => {
|
|
4489
|
+
const lastNode = state2.tr.doc.lastChild;
|
|
4490
|
+
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
|
|
4491
|
+
},
|
|
4492
|
+
apply: (tr, value) => {
|
|
4493
|
+
if (!tr.docChanged) {
|
|
4494
|
+
return value;
|
|
4495
|
+
}
|
|
4496
|
+
if (tr.getMeta("__uniqueIDTransaction")) {
|
|
4497
|
+
return value;
|
|
4498
|
+
}
|
|
4499
|
+
const lastNode = tr.doc.lastChild;
|
|
4500
|
+
return !nodeEqualsType({ node: lastNode, types: disabledNodes });
|
|
4501
|
+
}
|
|
4359
4502
|
}
|
|
4360
|
-
)
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
}
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
}
|
|
4375
|
-
|
|
4376
|
-
});
|
|
4377
|
-
const setTextAlign = (alignment) => {
|
|
4378
|
-
editor.chain().focus().setTextAlign(alignment).run();
|
|
4379
|
-
};
|
|
4380
|
-
return {
|
|
4381
|
-
textAlignLeftButton: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4382
|
-
ToolbarButton,
|
|
4383
|
-
{
|
|
4384
|
-
onClick: () => setTextAlign("left"),
|
|
4385
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(TextAlignLeft, {}),
|
|
4386
|
-
active: editorState.isTextAlignLeft,
|
|
4387
|
-
disabled: props.disabled || !editor || !editorState.canToggleAlign,
|
|
4388
|
-
tooltip: "Text Align Left"
|
|
4389
|
-
},
|
|
4390
|
-
"text-align-left"
|
|
4391
|
-
),
|
|
4392
|
-
textAlignCenterButton: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4393
|
-
ToolbarButton,
|
|
4394
|
-
{
|
|
4395
|
-
onClick: () => setTextAlign("center"),
|
|
4396
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(TextAlignCenter, {}),
|
|
4397
|
-
active: editorState.isTextAlignCenter,
|
|
4398
|
-
disabled: props.disabled || !editor || !editorState.canToggleAlign,
|
|
4399
|
-
tooltip: "Text Align Center"
|
|
4400
|
-
},
|
|
4401
|
-
"text-align-center"
|
|
4402
|
-
),
|
|
4403
|
-
textAlignRightButton: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4404
|
-
ToolbarButton,
|
|
4405
|
-
{
|
|
4406
|
-
onClick: () => setTextAlign("right"),
|
|
4407
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(TextAlignRight, {}),
|
|
4408
|
-
active: editorState.isTextAlignRight,
|
|
4409
|
-
disabled: props.disabled || !editor || !editorState.canToggleAlign,
|
|
4410
|
-
tooltip: "Text Align Right"
|
|
4411
|
-
},
|
|
4412
|
-
"text-align-right"
|
|
4413
|
-
),
|
|
4414
|
-
textAlignJustifyButton: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4415
|
-
ToolbarButton,
|
|
4416
|
-
{
|
|
4417
|
-
onClick: () => setTextAlign("justify"),
|
|
4418
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(TextAlignJustify, {}),
|
|
4419
|
-
active: editorState.isTextAlignJustify,
|
|
4420
|
-
disabled: props.disabled || !editor || !editorState.canToggleAlign,
|
|
4421
|
-
tooltip: "Text Align Justify"
|
|
4503
|
+
})
|
|
4504
|
+
];
|
|
4505
|
+
}
|
|
4506
|
+
});
|
|
4507
|
+
Extension.create({
|
|
4508
|
+
name: "undoRedo",
|
|
4509
|
+
addOptions() {
|
|
4510
|
+
return {
|
|
4511
|
+
depth: 100,
|
|
4512
|
+
newGroupDelay: 500
|
|
4513
|
+
};
|
|
4514
|
+
},
|
|
4515
|
+
addCommands() {
|
|
4516
|
+
return {
|
|
4517
|
+
undo: () => ({ state: state2, dispatch }) => {
|
|
4518
|
+
return history.undo(state2, dispatch);
|
|
4422
4519
|
},
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
}
|
|
4427
|
-
|
|
4428
|
-
|
|
4520
|
+
redo: () => ({ state: state2, dispatch }) => {
|
|
4521
|
+
return history.redo(state2, dispatch);
|
|
4522
|
+
}
|
|
4523
|
+
};
|
|
4524
|
+
},
|
|
4525
|
+
addProseMirrorPlugins() {
|
|
4526
|
+
return [history.history(this.options)];
|
|
4527
|
+
},
|
|
4528
|
+
addKeyboardShortcuts() {
|
|
4529
|
+
return {
|
|
4530
|
+
"Mod-z": () => this.editor.commands.undo(),
|
|
4531
|
+
"Shift-Mod-z": () => this.editor.commands.redo(),
|
|
4532
|
+
"Mod-y": () => this.editor.commands.redo(),
|
|
4533
|
+
// Russian keyboard layouts
|
|
4534
|
+
"Mod-я": () => this.editor.commands.undo(),
|
|
4535
|
+
"Shift-Mod-я": () => this.editor.commands.redo()
|
|
4536
|
+
};
|
|
4537
|
+
}
|
|
4538
|
+
});
|
|
4539
|
+
const starterKitFeatureValue = (value) => {
|
|
4540
|
+
if (!isFeatureEnabled(value)) {
|
|
4541
|
+
return false;
|
|
4542
|
+
}
|
|
4543
|
+
return getFeatureOptions(value, {}) ?? {};
|
|
4544
|
+
};
|
|
4545
|
+
function buildExtensions(config) {
|
|
4546
|
+
const starterKitConfig = {
|
|
4429
4547
|
heading: false,
|
|
4430
|
-
//
|
|
4431
|
-
|
|
4432
|
-
|
|
4548
|
+
// ALWAYS false — heading handled separately via BaseHeadingWithSEOTag
|
|
4549
|
+
bold: starterKitFeatureValue(config.bold),
|
|
4550
|
+
italic: starterKitFeatureValue(config.italic),
|
|
4551
|
+
strike: starterKitFeatureValue(config.strike),
|
|
4552
|
+
code: starterKitFeatureValue(config.code),
|
|
4553
|
+
codeBlock: starterKitFeatureValue(config.codeBlock),
|
|
4554
|
+
blockquote: starterKitFeatureValue(config.blockquote),
|
|
4555
|
+
bulletList: starterKitFeatureValue(config.bulletList),
|
|
4556
|
+
orderedList: starterKitFeatureValue(config.orderedList),
|
|
4557
|
+
hardBreak: starterKitFeatureValue(config.hardBreak),
|
|
4558
|
+
horizontalRule: starterKitFeatureValue(config.horizontalRule),
|
|
4559
|
+
history: starterKitFeatureValue(config.history),
|
|
4560
|
+
link: !isFeatureEnabled(config.link) ? false : {
|
|
4561
|
+
openOnClick: false,
|
|
4562
|
+
...getFeatureOptions(config.link, {})
|
|
4433
4563
|
}
|
|
4434
|
-
}
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4564
|
+
};
|
|
4565
|
+
const extensions = [
|
|
4566
|
+
StarterKit__default.default.configure(starterKitConfig)
|
|
4567
|
+
];
|
|
4568
|
+
if (isFeatureEnabled(config.heading)) {
|
|
4569
|
+
const headingConfig = getFeatureOptions(config.heading, {
|
|
4570
|
+
levels: [1, 2, 3, 4]
|
|
4571
|
+
});
|
|
4572
|
+
const levels = headingConfig?.levels || [1, 2, 3, 4];
|
|
4573
|
+
extensions.push(BaseHeadingWithSEOTag.configure({ levels }));
|
|
4574
|
+
}
|
|
4575
|
+
if (isFeatureEnabled(config.superscript)) {
|
|
4576
|
+
extensions.push(Superscript__default.default);
|
|
4577
|
+
}
|
|
4578
|
+
if (isFeatureEnabled(config.subscript)) {
|
|
4579
|
+
extensions.push(Subscript__default.default);
|
|
4580
|
+
}
|
|
4581
|
+
if (isFeatureEnabled(config.table)) {
|
|
4582
|
+
extensions.push(
|
|
4583
|
+
extensionTable.TableKit.configure({
|
|
4584
|
+
table: {
|
|
4585
|
+
resizable: true,
|
|
4586
|
+
...getFeatureOptions(config.table, {})
|
|
4587
|
+
}
|
|
4588
|
+
})
|
|
4589
|
+
);
|
|
4590
|
+
}
|
|
4591
|
+
if (isFeatureEnabled(config.textAlign)) {
|
|
4592
|
+
const textAlignConfig = getFeatureOptions(config.textAlign, {
|
|
4593
|
+
types: ["heading", "paragraph"],
|
|
4594
|
+
alignments: ["left", "center", "right", "justify"]
|
|
4595
|
+
});
|
|
4596
|
+
extensions.push(
|
|
4597
|
+
TextAlign__default.default.configure({
|
|
4598
|
+
types: textAlignConfig?.types || ["heading", "paragraph"],
|
|
4599
|
+
alignments: textAlignConfig?.alignments || [
|
|
4600
|
+
"left",
|
|
4601
|
+
"center",
|
|
4602
|
+
"right",
|
|
4603
|
+
"justify"
|
|
4604
|
+
]
|
|
4605
|
+
})
|
|
4606
|
+
);
|
|
4607
|
+
}
|
|
4608
|
+
extensions.push(Gapcursor);
|
|
4609
|
+
return extensions;
|
|
4610
|
+
}
|
|
4447
4611
|
const RichTextInput = React.forwardRef((props, forwardedRef) => {
|
|
4612
|
+
const attribute = props.attribute;
|
|
4613
|
+
const presetName = attribute?.options?.preset;
|
|
4614
|
+
const { config, isLoading } = usePresetConfig(presetName);
|
|
4615
|
+
const extensions = React.useMemo(() => {
|
|
4616
|
+
if (!config) return [];
|
|
4617
|
+
return buildExtensions(config);
|
|
4618
|
+
}, [presetName]);
|
|
4448
4619
|
const { editor, field } = useTiptapEditor(props.name, "", extensions);
|
|
4449
4620
|
const starterKit = useStarterKit(editor, { disabled: props.disabled });
|
|
4450
4621
|
const heading = useHeading(editor, { disabled: props.disabled });
|
|
@@ -4452,37 +4623,56 @@ const RichTextInput = React.forwardRef((props, forwardedRef) => {
|
|
|
4452
4623
|
const script = useScript(editor, { disabled: props.disabled });
|
|
4453
4624
|
const table = useTable(editor, { disabled: props.disabled });
|
|
4454
4625
|
const textAlign = useTextAlign(editor, { disabled: props.disabled });
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4626
|
+
if (isLoading) {
|
|
4627
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 4, children: "Loading editor..." });
|
|
4628
|
+
}
|
|
4629
|
+
return /* @__PURE__ */ jsxRuntime.jsx(EditorErrorBoundary, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4630
|
+
BaseTiptapInput,
|
|
4631
|
+
{
|
|
4632
|
+
editor,
|
|
4633
|
+
field,
|
|
4634
|
+
...props,
|
|
4635
|
+
ref: forwardedRef,
|
|
4636
|
+
noPresetConfigured: !presetName,
|
|
4637
|
+
children: [
|
|
4638
|
+
/* @__PURE__ */ jsxRuntime.jsxs(FeatureGuard, { featureValue: config?.heading, children: [
|
|
4639
|
+
heading.headingSelect,
|
|
4640
|
+
heading.headingTagSelect,
|
|
4641
|
+
/* @__PURE__ */ jsxRuntime.jsx(Spacer, { width: 8 })
|
|
4642
|
+
] }),
|
|
4643
|
+
starterKit.boldButton,
|
|
4644
|
+
starterKit.italicButton,
|
|
4645
|
+
starterKit.underlineButton,
|
|
4646
|
+
starterKit.strikeButton,
|
|
4647
|
+
script.superscriptButton,
|
|
4648
|
+
script.subscriptButton,
|
|
4649
|
+
/* @__PURE__ */ jsxRuntime.jsx(Spacer, { width: 8 }),
|
|
4650
|
+
/* @__PURE__ */ jsxRuntime.jsxs(FeatureGuard, { featureValue: config?.textAlign, children: [
|
|
4651
|
+
textAlign.textAlignLeftButton,
|
|
4652
|
+
textAlign.textAlignCenterButton,
|
|
4653
|
+
textAlign.textAlignRightButton,
|
|
4654
|
+
textAlign.textAlignJustifyButton,
|
|
4655
|
+
/* @__PURE__ */ jsxRuntime.jsx(Spacer, { width: 8 })
|
|
4656
|
+
] }),
|
|
4657
|
+
starterKit.bulletButton,
|
|
4658
|
+
starterKit.orderedButton,
|
|
4659
|
+
/* @__PURE__ */ jsxRuntime.jsx(Spacer, { width: 8 }),
|
|
4660
|
+
starterKit.codeButton,
|
|
4661
|
+
starterKit.blockquoteButton,
|
|
4662
|
+
link.linkButton,
|
|
4663
|
+
link.linkDialog,
|
|
4664
|
+
/* @__PURE__ */ jsxRuntime.jsxs(FeatureGuard, { featureValue: config?.table, children: [
|
|
4665
|
+
/* @__PURE__ */ jsxRuntime.jsx(Spacer, { width: 8 }),
|
|
4666
|
+
table.tableButton,
|
|
4667
|
+
table.addColumnButton,
|
|
4668
|
+
table.removeColumnButton,
|
|
4669
|
+
table.addRowButton,
|
|
4670
|
+
table.removeRowButton,
|
|
4671
|
+
table.tableDialog
|
|
4672
|
+
] })
|
|
4673
|
+
]
|
|
4674
|
+
}
|
|
4675
|
+
) });
|
|
4486
4676
|
});
|
|
4487
4677
|
exports.default = RichTextInput;
|
|
4488
|
-
//# sourceMappingURL=RichTextInput-
|
|
4678
|
+
//# sourceMappingURL=RichTextInput-Wc2q__HY.js.map
|