@questpie/admin 3.5.1 → 3.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/builder/types/collection-types.d.mts +9 -0
- package/dist/client/components/actions/action-dialog.mjs +5 -0
- package/dist/client/components/fields/rich-text-editor/bubble-menu.mjs +7 -0
- package/dist/client/components/fields/rich-text-editor/extensions.mjs +17 -1
- package/dist/client/components/fields/rich-text-editor/index.d.mts +2 -1
- package/dist/client/components/fields/rich-text-editor/index.mjs +35 -74
- package/dist/client/components/fields/rich-text-editor/slash-commands.mjs +30 -7
- package/dist/client/components/fields/rich-text-editor/toolbar.mjs +1 -312
- package/dist/client/components/fields/rich-text-editor/types.d.mts +4 -0
- package/dist/client/components/fields/rich-text-editor/types.mjs +1 -1
- package/dist/client/components/fields/rich-text-editor/utils.mjs +6 -12
- package/dist/client/components/filter-builder/filter-builder-sheet.mjs +75 -22
- package/dist/client/components/ui/dropdown-menu.mjs +1 -34
- package/dist/client/hooks/query-access.d.mts +9 -0
- package/dist/client/hooks/query-access.mjs +20 -0
- package/dist/client/hooks/typed-hooks.d.mts +4 -2
- package/dist/client/hooks/typed-hooks.mjs +30 -29
- package/dist/client/hooks/use-reactive-fields.d.mts +1 -0
- package/dist/client/hooks/use-reactive-fields.mjs +16 -1
- package/dist/client/hooks/use-server-actions.mjs +12 -1
- package/dist/client/hooks/use-view-state.mjs +15 -7
- package/dist/client/lib/view-filter-utils.mjs +30 -0
- package/dist/client/preview/block-scope-context.d.mts +2 -2
- package/dist/client/preview/preview-banner.d.mts +2 -2
- package/dist/client/preview/preview-field.d.mts +4 -4
- package/dist/client/scope/picker.d.mts +2 -2
- package/dist/client/scope/provider.d.mts +2 -2
- package/dist/client/styles/base.css +69 -77
- package/dist/client/utils/build-field-definitions-from-schema.mjs +1 -0
- package/dist/client/views/collection/auto-form-fields.mjs +3 -2
- package/dist/client/views/collection/cells/primitive-cells.mjs +9 -6
- package/dist/client/views/collection/columns/build-columns.mjs +3 -1
- package/dist/client/views/collection/field-renderer.mjs +11 -3
- package/dist/client/views/collection/form-view.mjs +207 -202
- package/dist/client/views/collection/list-view.mjs +581 -183
- package/dist/client/views/collection/outline.mjs +44 -19
- package/dist/client/views/collection/quick-filter-bar.mjs +45 -0
- package/dist/client/views/collection/table-view.mjs +60 -16
- package/dist/client/views/globals/global-form-view.mjs +12 -9
- package/dist/client/views/layout/admin-layout.mjs +1 -1
- package/dist/client/views/layout/admin-sidebar.mjs +20 -14
- package/dist/client/views/layout/admin-theme.mjs +5 -4
- package/dist/client.mjs +1 -1
- package/dist/components/rich-text/rich-text-renderer.d.mts +5 -5
- package/dist/components/rich-text/rich-text-renderer.mjs +5 -2
- package/dist/index.mjs +1 -1
- package/dist/modules/admin.d.mts +1 -1
- package/dist/server/augmentation/actions.d.mts +4 -3
- package/dist/server/augmentation/dashboard.d.mts +11 -11
- package/dist/server/augmentation/form-layout.d.mts +11 -6
- package/dist/server/augmentation/index.d.mts +7 -0
- package/dist/server/augmentation/sidebar.d.mts +8 -8
- package/dist/server/codegen/admin-client-template.mjs +55 -38
- package/dist/server/fields/index.d.mts +1 -1
- package/dist/server/fields/rich-text.d.mts +16 -17
- package/dist/server/fields/rich-text.mjs +18 -7
- package/dist/server/i18n/messages/cs.mjs +2 -0
- package/dist/server/i18n/messages/de.mjs +2 -0
- package/dist/server/i18n/messages/en.mjs +4 -0
- package/dist/server/i18n/messages/es.mjs +2 -0
- package/dist/server/i18n/messages/fr.mjs +2 -0
- package/dist/server/i18n/messages/pl.mjs +2 -0
- package/dist/server/i18n/messages/pt.mjs +2 -0
- package/dist/server/i18n/messages/sk.mjs +2 -0
- package/dist/server/modules/admin/block/block-builder.d.mts +0 -8
- package/dist/server/modules/admin/block/introspection.d.mts +2 -2
- package/dist/server/modules/admin/collections/account.d.mts +53 -52
- package/dist/server/modules/admin/collections/admin-locks.d.mts +57 -56
- package/dist/server/modules/admin/collections/admin-preferences.d.mts +3 -2
- package/dist/server/modules/admin/collections/admin-saved-views.d.mts +50 -49
- package/dist/server/modules/admin/collections/apikey.d.mts +72 -71
- package/dist/server/modules/admin/collections/assets.d.mts +42 -41
- package/dist/server/modules/admin/collections/session.d.mts +46 -45
- package/dist/server/modules/admin/collections/user.d.mts +67 -66
- package/dist/server/modules/admin/collections/verification.d.mts +39 -38
- package/dist/server/modules/admin/index.d.mts +3 -3
- package/dist/server/modules/admin/routes/admin-config.d.mts +2 -2
- package/dist/server/modules/admin/routes/admin-config.mjs +39 -23
- package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
- package/dist/server/modules/admin/routes/execute-action.mjs +28 -8
- package/dist/server/modules/admin/routes/locales.d.mts +2 -2
- package/dist/server/modules/admin/routes/reactive.mjs +2 -2
- package/dist/server/modules/admin/routes/route-helpers.d.mts +11 -7
- package/dist/server/modules/admin/routes/translations.d.mts +4 -4
- package/dist/server/modules/admin/routes/widget-data.mjs +12 -4
- package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +27 -27
- package/dist/server/modules/audit/.generated/module.d.mts +6 -6
- package/dist/server/modules/audit/collections/audit-log.d.mts +40 -39
- package/dist/server/plugin.mjs +3 -3
- package/dist/server.d.mts +1 -1
- package/dist/shared/types/index.d.mts +1 -0
- package/dist/shared/types/saved-views.types.d.mts +14 -7
- package/dist/shared.d.mts +3 -2
- package/package.json +4 -3
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "../../i18n/types.mjs";
|
|
2
2
|
import { MaybeLazyComponent } from "./common.mjs";
|
|
3
|
+
import { FilterRule, QuickFilterConfig } from "../../../shared/types/saved-views.types.mjs";
|
|
3
4
|
import "../../../server/augmentation.mjs";
|
|
4
5
|
import "../field/field.mjs";
|
|
5
6
|
import "../admin.mjs";
|
|
@@ -124,6 +125,14 @@ interface ListViewConfig<TFieldNames extends string = string> {
|
|
|
124
125
|
field: TFieldNames;
|
|
125
126
|
direction: "asc" | "desc";
|
|
126
127
|
};
|
|
128
|
+
/**
|
|
129
|
+
* Initial filters used when the user has no saved view state.
|
|
130
|
+
*/
|
|
131
|
+
defaultFilters?: FilterRule[];
|
|
132
|
+
/**
|
|
133
|
+
* Header-level quick filter presets.
|
|
134
|
+
*/
|
|
135
|
+
quickFilters?: QuickFilterConfig[];
|
|
127
136
|
/**
|
|
128
137
|
* Enables reorder mode for this list.
|
|
129
138
|
* Requires a numeric field named `order` on the collection.
|
|
@@ -92,6 +92,11 @@ function FormDialogContent({ action, ctx, onClose }) {
|
|
|
92
92
|
return message || t("toast.actionSuccess");
|
|
93
93
|
},
|
|
94
94
|
error: (error) => {
|
|
95
|
+
const validationError = error;
|
|
96
|
+
if (validationError.fieldErrors) for (const [field, message] of Object.entries(validationError.fieldErrors)) form.setError(field, {
|
|
97
|
+
type: "server",
|
|
98
|
+
message
|
|
99
|
+
});
|
|
95
100
|
return error instanceof Error ? error.message : t("toast.actionFailed");
|
|
96
101
|
},
|
|
97
102
|
finally: () => {
|
|
@@ -283,6 +283,13 @@ function RichTextBubbleMenu({ editor, features, disabled, linkOpen, onImageClick
|
|
|
283
283
|
shortcut: "⌘U",
|
|
284
284
|
onClick: () => editor.chain().focus().toggleUnderline().run()
|
|
285
285
|
}),
|
|
286
|
+
features.strike && /* @__PURE__ */ jsx(ToolbarButton, {
|
|
287
|
+
icon: EDITOR_ICONS.strikethrough,
|
|
288
|
+
active: editor.isActive("strike"),
|
|
289
|
+
disabled: !isEditable,
|
|
290
|
+
title: t("editor.strikethrough"),
|
|
291
|
+
onClick: () => editor.chain().focus().toggleStrike().run()
|
|
292
|
+
}),
|
|
286
293
|
features.code && /* @__PURE__ */ jsx(ToolbarButton, {
|
|
287
294
|
icon: EDITOR_ICONS.code,
|
|
288
295
|
active: editor.isActive("code"),
|
|
@@ -10,6 +10,7 @@ import TableRow from "@tiptap/extension-table-row";
|
|
|
10
10
|
import TextAlign from "@tiptap/extension-text-align";
|
|
11
11
|
import Underline from "@tiptap/extension-underline";
|
|
12
12
|
import StarterKit from "@tiptap/starter-kit";
|
|
13
|
+
import { Markdown } from "tiptap-markdown";
|
|
13
14
|
|
|
14
15
|
//#region src/client/components/fields/rich-text-editor/extensions.tsx
|
|
15
16
|
let codeBlockExtension = null;
|
|
@@ -67,7 +68,7 @@ function buildExtensions({ features, labels, placeholder, maxCharacters, customE
|
|
|
67
68
|
if (!(codeBlock instanceof Promise)) return [...base, codeBlock];
|
|
68
69
|
return codeBlock.then((ext) => [...base, ext]);
|
|
69
70
|
}
|
|
70
|
-
function buildBaseExtensions({ features, labels = defaultLabels, placeholder, maxCharacters, customExtensions }) {
|
|
71
|
+
function buildBaseExtensions({ features, labels = defaultLabels, placeholder, maxCharacters, outputMode, customExtensions }) {
|
|
71
72
|
const starterKitConfig = { codeBlock: false };
|
|
72
73
|
if (!features.bold) starterKitConfig.bold = false;
|
|
73
74
|
if (!features.italic) starterKitConfig.italic = false;
|
|
@@ -97,18 +98,21 @@ function buildBaseExtensions({ features, labels = defaultLabels, placeholder, ma
|
|
|
97
98
|
title: labels.heading(1),
|
|
98
99
|
description: labels.heading1Description,
|
|
99
100
|
icon: "ph:text-h-one",
|
|
101
|
+
group: "Headings",
|
|
100
102
|
keywords: ["h1"],
|
|
101
103
|
command: (cmdEditor) => cmdEditor.chain().focus().toggleHeading({ level: 1 }).run()
|
|
102
104
|
}, {
|
|
103
105
|
title: labels.heading(2),
|
|
104
106
|
description: labels.heading2Description,
|
|
105
107
|
icon: "ph:text-h-two",
|
|
108
|
+
group: "Headings",
|
|
106
109
|
keywords: ["h2"],
|
|
107
110
|
command: (cmdEditor) => cmdEditor.chain().focus().toggleHeading({ level: 2 }).run()
|
|
108
111
|
}, {
|
|
109
112
|
title: labels.heading(3),
|
|
110
113
|
description: labels.heading3Description,
|
|
111
114
|
icon: "ph:text-h-three",
|
|
115
|
+
group: "Headings",
|
|
112
116
|
keywords: ["h3"],
|
|
113
117
|
command: (cmdEditor) => cmdEditor.chain().focus().toggleHeading({ level: 3 }).run()
|
|
114
118
|
});
|
|
@@ -116,6 +120,7 @@ function buildBaseExtensions({ features, labels = defaultLabels, placeholder, ma
|
|
|
116
120
|
title: labels.paragraph,
|
|
117
121
|
description: labels.paragraphDescription,
|
|
118
122
|
icon: "ph:text-align-left",
|
|
123
|
+
group: "Text",
|
|
119
124
|
keywords: ["text"],
|
|
120
125
|
command: (cmdEditor) => cmdEditor.chain().focus().setParagraph().run()
|
|
121
126
|
});
|
|
@@ -123,6 +128,7 @@ function buildBaseExtensions({ features, labels = defaultLabels, placeholder, ma
|
|
|
123
128
|
title: labels.bulletList,
|
|
124
129
|
description: labels.bulletListDescription,
|
|
125
130
|
icon: "ph:list-bullets",
|
|
131
|
+
group: "Lists",
|
|
126
132
|
keywords: ["list", "ul"],
|
|
127
133
|
command: (cmdEditor) => cmdEditor.chain().focus().toggleBulletList().run()
|
|
128
134
|
});
|
|
@@ -130,6 +136,7 @@ function buildBaseExtensions({ features, labels = defaultLabels, placeholder, ma
|
|
|
130
136
|
title: labels.orderedList,
|
|
131
137
|
description: labels.orderedListDescription,
|
|
132
138
|
icon: "ph:list-numbers",
|
|
139
|
+
group: "Lists",
|
|
133
140
|
keywords: ["list", "ol"],
|
|
134
141
|
command: (cmdEditor) => cmdEditor.chain().focus().toggleOrderedList().run()
|
|
135
142
|
});
|
|
@@ -137,6 +144,7 @@ function buildBaseExtensions({ features, labels = defaultLabels, placeholder, ma
|
|
|
137
144
|
title: labels.quote,
|
|
138
145
|
description: labels.quoteDescription,
|
|
139
146
|
icon: "ph:quotes",
|
|
147
|
+
group: "Blocks",
|
|
140
148
|
keywords: ["blockquote"],
|
|
141
149
|
command: (cmdEditor) => cmdEditor.chain().focus().toggleBlockquote().run()
|
|
142
150
|
});
|
|
@@ -144,6 +152,7 @@ function buildBaseExtensions({ features, labels = defaultLabels, placeholder, ma
|
|
|
144
152
|
title: labels.codeBlock,
|
|
145
153
|
description: labels.codeBlockDescription,
|
|
146
154
|
icon: "ph:code-block",
|
|
155
|
+
group: "Blocks",
|
|
147
156
|
keywords: ["code"],
|
|
148
157
|
command: (cmdEditor) => cmdEditor.chain().focus().toggleCodeBlock().run()
|
|
149
158
|
});
|
|
@@ -151,6 +160,7 @@ function buildBaseExtensions({ features, labels = defaultLabels, placeholder, ma
|
|
|
151
160
|
title: labels.divider,
|
|
152
161
|
description: labels.dividerDescription,
|
|
153
162
|
icon: "ph:minus",
|
|
163
|
+
group: "Blocks",
|
|
154
164
|
keywords: ["hr"],
|
|
155
165
|
command: (cmdEditor) => cmdEditor.chain().focus().setHorizontalRule().run()
|
|
156
166
|
});
|
|
@@ -158,6 +168,7 @@ function buildBaseExtensions({ features, labels = defaultLabels, placeholder, ma
|
|
|
158
168
|
title: labels.table,
|
|
159
169
|
description: labels.tableDescription,
|
|
160
170
|
icon: "ph:table",
|
|
171
|
+
group: "Blocks",
|
|
161
172
|
keywords: ["grid"],
|
|
162
173
|
command: (cmdEditor) => cmdEditor.chain().focus().insertTable({
|
|
163
174
|
rows: 3,
|
|
@@ -167,6 +178,11 @@ function buildBaseExtensions({ features, labels = defaultLabels, placeholder, ma
|
|
|
167
178
|
});
|
|
168
179
|
return commands;
|
|
169
180
|
}));
|
|
181
|
+
if (outputMode === "markdown") extensions.push(Markdown.configure({
|
|
182
|
+
html: true,
|
|
183
|
+
transformCopiedText: true,
|
|
184
|
+
transformPastedText: true
|
|
185
|
+
}));
|
|
170
186
|
if (customExtensions?.length) extensions.push(...customExtensions);
|
|
171
187
|
return extensions;
|
|
172
188
|
}
|
|
@@ -5,48 +5,24 @@ import { Skeleton } from "../../ui/skeleton.mjs";
|
|
|
5
5
|
import { isModifierShortcut } from "../../../utils/keyboard-shortcuts.mjs";
|
|
6
6
|
import { LocaleBadge } from "../locale-badge.mjs";
|
|
7
7
|
import { createLinkAttributes, isLikelyLinkHref } from "./link-utils.mjs";
|
|
8
|
-
import {
|
|
8
|
+
import { TableControls } from "./table-controls.mjs";
|
|
9
|
+
import { ToolbarButton } from "./toolbar.mjs";
|
|
9
10
|
import { RichTextBubbleMenu } from "./bubble-menu.mjs";
|
|
10
11
|
import { buildExtensions } from "./extensions.mjs";
|
|
11
12
|
import { getImageAltFromFile, getImageFilesFromDataTransfer, useRichTextImageUpload } from "./image-upload.mjs";
|
|
12
13
|
import { ImagePopover } from "./image-popover.mjs";
|
|
13
14
|
import { mergePresetFeatures } from "./presets.mjs";
|
|
14
15
|
import { defaultFeatures } from "./types.mjs";
|
|
15
|
-
import { getCharacterCount,
|
|
16
|
+
import { getCharacterCount, getOutput, isSameValue } from "./utils.mjs";
|
|
16
17
|
import * as React from "react";
|
|
17
18
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
18
19
|
import { toast } from "sonner";
|
|
19
20
|
import { EditorContent, useEditor } from "@tiptap/react";
|
|
20
21
|
|
|
21
22
|
//#region src/client/components/fields/rich-text-editor/index.tsx
|
|
22
|
-
function RichTextToolbarSkeleton() {
|
|
23
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
24
|
-
className: "qp-rich-text-editor__toolbar border-border-subtle bg-surface-low flex flex-nowrap items-center gap-1.5 overflow-hidden border-b p-1.5",
|
|
25
|
-
"aria-hidden": "true",
|
|
26
|
-
children: [
|
|
27
|
-
/* @__PURE__ */ jsxs("div", {
|
|
28
|
-
className: "flex items-center gap-1",
|
|
29
|
-
role: "presentation",
|
|
30
|
-
children: [/* @__PURE__ */ jsx(Skeleton, { className: "size-8" }), /* @__PURE__ */ jsx(Skeleton, { className: "size-8" })]
|
|
31
|
-
}),
|
|
32
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-8 min-w-[136px]" }),
|
|
33
|
-
/* @__PURE__ */ jsxs("div", {
|
|
34
|
-
className: "flex items-center gap-1",
|
|
35
|
-
role: "presentation",
|
|
36
|
-
children: [
|
|
37
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "size-8" }),
|
|
38
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "size-8" }),
|
|
39
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "size-8" })
|
|
40
|
-
]
|
|
41
|
-
}),
|
|
42
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "size-8" }),
|
|
43
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "size-8" })
|
|
44
|
-
]
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
23
|
function RichTextEditorContentSkeleton() {
|
|
48
24
|
return /* @__PURE__ */ jsxs("div", {
|
|
49
|
-
className: "qp-rich-text-editor__content space-y-
|
|
25
|
+
className: "qp-rich-text-editor__content space-y-4",
|
|
50
26
|
"aria-hidden": "true",
|
|
51
27
|
children: [
|
|
52
28
|
/* @__PURE__ */ jsx(Skeleton, {
|
|
@@ -62,7 +38,7 @@ function RichTextEditorContentSkeleton() {
|
|
|
62
38
|
className: "h-4 w-full max-w-[86%]"
|
|
63
39
|
}),
|
|
64
40
|
/* @__PURE__ */ jsx("div", {
|
|
65
|
-
className: "pt-
|
|
41
|
+
className: "pt-2",
|
|
66
42
|
children: /* @__PURE__ */ jsx(Skeleton, {
|
|
67
43
|
variant: "text",
|
|
68
44
|
className: "h-4 w-full max-w-[58%]"
|
|
@@ -71,19 +47,15 @@ function RichTextEditorContentSkeleton() {
|
|
|
71
47
|
]
|
|
72
48
|
});
|
|
73
49
|
}
|
|
74
|
-
function RichTextEditorLoadingSkeleton({ disabled, readOnly
|
|
50
|
+
function RichTextEditorLoadingSkeleton({ disabled, readOnly }) {
|
|
75
51
|
return /* @__PURE__ */ jsxs("div", {
|
|
76
|
-
className: cn("qp-rich-text-editor
|
|
52
|
+
className: cn("qp-rich-text-editor", disabled || readOnly ? "opacity-60" : ""),
|
|
77
53
|
"data-admin-rich-text-editor": "root",
|
|
78
54
|
"aria-busy": "true",
|
|
79
|
-
children: [
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}),
|
|
84
|
-
showToolbar && /* @__PURE__ */ jsx(RichTextToolbarSkeleton, {}),
|
|
85
|
-
/* @__PURE__ */ jsx(RichTextEditorContentSkeleton, {})
|
|
86
|
-
]
|
|
55
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
56
|
+
className: "sr-only",
|
|
57
|
+
children: "Loading editor"
|
|
58
|
+
}), /* @__PURE__ */ jsx(RichTextEditorContentSkeleton, {})]
|
|
87
59
|
});
|
|
88
60
|
}
|
|
89
61
|
/**
|
|
@@ -94,7 +66,7 @@ function RichTextEditorLoadingSkeleton({ disabled, readOnly, error, showToolbar
|
|
|
94
66
|
* `useEditor` with an empty extension list which causes the ProseMirror
|
|
95
67
|
* "Schema is missing its top node type" error.
|
|
96
68
|
*/
|
|
97
|
-
function RichTextEditor({ name, value, onChange, disabled, readOnly, label, description, placeholder, required, error, localized, locale, extensions, preset, features, showCharacterCount, maxCharacters, enableImages, onImageUpload, imageCollection, enableMediaLibrary }) {
|
|
69
|
+
function RichTextEditor({ name, value, onChange, disabled, readOnly, label, description, placeholder, required, error, localized, locale, extensions, preset, features, showCharacterCount, maxCharacters, enableImages, onImageUpload, imageCollection, enableMediaLibrary, outputMode }) {
|
|
98
70
|
const { t } = useTranslation();
|
|
99
71
|
const resolveText = useResolveText();
|
|
100
72
|
const resolvedLabel = label ? resolveText(label) : void 0;
|
|
@@ -134,12 +106,14 @@ function RichTextEditor({ name, value, onChange, disabled, readOnly, label, desc
|
|
|
134
106
|
labels: extensionLabels,
|
|
135
107
|
placeholder: placeholder || t("editor.startWriting"),
|
|
136
108
|
maxCharacters,
|
|
109
|
+
outputMode,
|
|
137
110
|
customExtensions: extensions
|
|
138
111
|
}), [
|
|
139
112
|
resolvedFeatures,
|
|
140
113
|
extensionLabels,
|
|
141
114
|
placeholder,
|
|
142
115
|
maxCharacters,
|
|
116
|
+
outputMode,
|
|
143
117
|
extensions,
|
|
144
118
|
t
|
|
145
119
|
]);
|
|
@@ -190,12 +164,11 @@ function RichTextEditor({ name, value, onChange, disabled, readOnly, label, desc
|
|
|
190
164
|
enableImages,
|
|
191
165
|
onImageUpload,
|
|
192
166
|
imageCollection,
|
|
193
|
-
enableMediaLibrary
|
|
167
|
+
enableMediaLibrary,
|
|
168
|
+
outputMode
|
|
194
169
|
}) : /* @__PURE__ */ jsx(RichTextEditorLoadingSkeleton, {
|
|
195
170
|
disabled,
|
|
196
|
-
readOnly
|
|
197
|
-
error,
|
|
198
|
-
showToolbar: resolvedFeatures.toolbar
|
|
171
|
+
readOnly
|
|
199
172
|
}),
|
|
200
173
|
resolvedDescription && /* @__PURE__ */ jsx("p", {
|
|
201
174
|
id: descriptionId,
|
|
@@ -215,7 +188,7 @@ function RichTextEditor({ name, value, onChange, disabled, readOnly, label, desc
|
|
|
215
188
|
* `useEditor` always receives a complete extension list, so the ProseMirror
|
|
216
189
|
* schema always has its `doc` node.
|
|
217
190
|
*/
|
|
218
|
-
function RichTextEditorCore({ name, ariaLabel, ariaDescribedBy, value, onChange, disabled, readOnly, error, locale, features, resolvedExtensions, showCharacterCount, maxCharacters, enableImages, onImageUpload, imageCollection, enableMediaLibrary }) {
|
|
191
|
+
function RichTextEditorCore({ name, ariaLabel, ariaDescribedBy, value, onChange, disabled, readOnly, error, locale, features, resolvedExtensions, showCharacterCount, maxCharacters, enableImages, onImageUpload, imageCollection, enableMediaLibrary, outputMode }) {
|
|
219
192
|
const { t } = useTranslation();
|
|
220
193
|
const [linkOpen, setLinkOpen] = React.useState(false);
|
|
221
194
|
const [imageOpen, setImageOpen] = React.useState(false);
|
|
@@ -225,7 +198,6 @@ function RichTextEditorCore({ name, ariaLabel, ariaDescribedBy, value, onChange,
|
|
|
225
198
|
const allowImages = features.image && (enableImages ?? true);
|
|
226
199
|
const allowLinks = features.link;
|
|
227
200
|
const allowBubbleMenu = features.bubbleMenu;
|
|
228
|
-
const allowToolbar = features.toolbar;
|
|
229
201
|
const allowCharacterCount = features.characterCount && (showCharacterCount || maxCharacters);
|
|
230
202
|
const isEditable = !disabled && !readOnly;
|
|
231
203
|
const editorStateRef = React.useRef({
|
|
@@ -339,7 +311,7 @@ function RichTextEditorCore({ name, ariaLabel, ariaDescribedBy, value, onChange,
|
|
|
339
311
|
editable: isEditable,
|
|
340
312
|
onUpdate: ({ editor: currentEditor }) => {
|
|
341
313
|
if (disabled || readOnly) return;
|
|
342
|
-
const nextValue = getOutput(currentEditor);
|
|
314
|
+
const nextValue = getOutput(currentEditor, outputMode);
|
|
343
315
|
lastEmittedValueRef.current = nextValue;
|
|
344
316
|
onChange?.(nextValue);
|
|
345
317
|
}
|
|
@@ -350,7 +322,6 @@ function RichTextEditorCore({ name, ariaLabel, ariaDescribedBy, value, onChange,
|
|
|
350
322
|
if (editorRef.current === editor) editorRef.current = null;
|
|
351
323
|
};
|
|
352
324
|
}, [editor]);
|
|
353
|
-
const headingValue = getHeadingLevel(editor);
|
|
354
325
|
const inTable = editor?.isActive("table") ?? false;
|
|
355
326
|
React.useEffect(() => {
|
|
356
327
|
if (!editor) return;
|
|
@@ -372,33 +343,9 @@ function RichTextEditorCore({ name, ariaLabel, ariaDescribedBy, value, onChange,
|
|
|
372
343
|
}, [editor, value]);
|
|
373
344
|
const characterCount = getCharacterCount(editor);
|
|
374
345
|
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
|
|
375
|
-
className: cn("qp-rich-text-editor
|
|
346
|
+
className: cn("qp-rich-text-editor", disabled || readOnly ? "opacity-60" : ""),
|
|
376
347
|
"data-admin-rich-text-editor": "root",
|
|
377
348
|
children: [
|
|
378
|
-
editor && allowToolbar && /* @__PURE__ */ jsx(RichTextToolbar, {
|
|
379
|
-
editor,
|
|
380
|
-
features,
|
|
381
|
-
disabled: !isEditable,
|
|
382
|
-
headingValue,
|
|
383
|
-
onHeadingChange: (value$1) => {
|
|
384
|
-
if (!editor) return;
|
|
385
|
-
if (value$1 === "paragraph") {
|
|
386
|
-
editor.chain().focus().setParagraph().run();
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
editor.chain().focus().toggleHeading({ level: Number(value$1) }).run();
|
|
390
|
-
},
|
|
391
|
-
onLinkClick: () => setLinkOpen(true),
|
|
392
|
-
onImageClick: () => setImageOpen(true),
|
|
393
|
-
onTableClick: () => {
|
|
394
|
-
if (!inTable) editor.chain().focus().insertTable({
|
|
395
|
-
rows: 3,
|
|
396
|
-
cols: 3,
|
|
397
|
-
withHeaderRow: true
|
|
398
|
-
}).run();
|
|
399
|
-
},
|
|
400
|
-
inTable
|
|
401
|
-
}),
|
|
402
349
|
editor && (allowBubbleMenu || linkOpen) && /* @__PURE__ */ jsx(RichTextBubbleMenu, {
|
|
403
350
|
editor,
|
|
404
351
|
features,
|
|
@@ -412,6 +359,20 @@ function RichTextEditorCore({ name, ariaLabel, ariaDescribedBy, value, onChange,
|
|
|
412
359
|
editor,
|
|
413
360
|
id: name
|
|
414
361
|
}) : /* @__PURE__ */ jsx(RichTextEditorContentSkeleton, {}),
|
|
362
|
+
editor && features.table && features.tableControls && inTable && /* @__PURE__ */ jsx("div", {
|
|
363
|
+
className: "flex justify-end px-2 py-1",
|
|
364
|
+
children: /* @__PURE__ */ jsx(TableControls, {
|
|
365
|
+
editor,
|
|
366
|
+
disabled: !isEditable,
|
|
367
|
+
inTable,
|
|
368
|
+
triggerButton: /* @__PURE__ */ jsx(ToolbarButton, {
|
|
369
|
+
icon: "ph:table",
|
|
370
|
+
active: inTable,
|
|
371
|
+
disabled: !isEditable,
|
|
372
|
+
title: t("editor.table")
|
|
373
|
+
})
|
|
374
|
+
})
|
|
375
|
+
}),
|
|
415
376
|
uploadingInlineImage && /* @__PURE__ */ jsx("div", {
|
|
416
377
|
className: "qp-rich-text-editor__upload-status",
|
|
417
378
|
role: "status",
|
|
@@ -419,7 +380,7 @@ function RichTextEditorCore({ name, ariaLabel, ariaDescribedBy, value, onChange,
|
|
|
419
380
|
children: t("editor.uploading")
|
|
420
381
|
}),
|
|
421
382
|
allowCharacterCount && showCharacterCount && /* @__PURE__ */ jsxs("div", {
|
|
422
|
-
className: "
|
|
383
|
+
className: "text-muted-foreground flex items-center justify-between px-1.5 pt-2 text-xs",
|
|
423
384
|
children: [/* @__PURE__ */ jsxs("span", { children: [
|
|
424
385
|
characterCount.words,
|
|
425
386
|
" word",
|
|
@@ -47,21 +47,44 @@ const SlashCommandList = React.forwardRef(function SlashCommandList$1({ items, c
|
|
|
47
47
|
}
|
|
48
48
|
return false;
|
|
49
49
|
} }));
|
|
50
|
+
const grouped = React.useMemo(() => {
|
|
51
|
+
const groups = [];
|
|
52
|
+
let currentLabel;
|
|
53
|
+
for (let i = 0; i < items.length; i++) {
|
|
54
|
+
const item = items[i];
|
|
55
|
+
if (item.group !== currentLabel || i === 0) {
|
|
56
|
+
currentLabel = item.group;
|
|
57
|
+
groups.push({
|
|
58
|
+
label: currentLabel,
|
|
59
|
+
items: []
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
groups[groups.length - 1].items.push({
|
|
63
|
+
item,
|
|
64
|
+
globalIndex: i
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return groups;
|
|
68
|
+
}, [items]);
|
|
50
69
|
return /* @__PURE__ */ jsxs("div", {
|
|
51
70
|
className: "qp-rich-text-editor__slash",
|
|
52
71
|
role: "listbox",
|
|
53
72
|
children: [items.length === 0 && /* @__PURE__ */ jsx("div", {
|
|
54
73
|
className: "qp-rich-text-editor__slash-empty",
|
|
55
74
|
children: "No results"
|
|
56
|
-
}),
|
|
75
|
+
}), grouped.map((group) => /* @__PURE__ */ jsxs("div", { children: [group.label && /* @__PURE__ */ jsx("div", {
|
|
76
|
+
className: "qp-rich-text-editor__slash-group",
|
|
77
|
+
"aria-hidden": "true",
|
|
78
|
+
children: group.label
|
|
79
|
+
}), group.items.map(({ item, globalIndex }) => /* @__PURE__ */ jsxs("button", {
|
|
57
80
|
type: "button",
|
|
58
|
-
"aria-selected":
|
|
81
|
+
"aria-selected": globalIndex === safeIndex,
|
|
59
82
|
role: "option",
|
|
60
83
|
tabIndex: -1,
|
|
61
|
-
className: cn("qp-rich-text-editor__slash-item",
|
|
62
|
-
onMouseEnter: () => setSelectedIndex(
|
|
84
|
+
className: cn("qp-rich-text-editor__slash-item", globalIndex === safeIndex ? "qp-rich-text-editor__slash-item--active" : ""),
|
|
85
|
+
onMouseEnter: () => setSelectedIndex(globalIndex),
|
|
63
86
|
onMouseDown: (event) => event.preventDefault(),
|
|
64
|
-
onClick: () => selectItem(
|
|
87
|
+
onClick: () => selectItem(globalIndex),
|
|
65
88
|
children: [item.icon && /* @__PURE__ */ jsx("span", {
|
|
66
89
|
className: "qp-rich-text-editor__slash-icon",
|
|
67
90
|
"aria-hidden": "true",
|
|
@@ -80,7 +103,7 @@ const SlashCommandList = React.forwardRef(function SlashCommandList$1({ items, c
|
|
|
80
103
|
children: item.description
|
|
81
104
|
})]
|
|
82
105
|
})]
|
|
83
|
-
}, item.title))]
|
|
106
|
+
}, item.title))] }, group.label ?? "ungrouped"))]
|
|
84
107
|
});
|
|
85
108
|
});
|
|
86
109
|
/**
|
|
@@ -92,7 +115,7 @@ function createSlashCommandExtension(getItems) {
|
|
|
92
115
|
addOptions() {
|
|
93
116
|
return { suggestion: {
|
|
94
117
|
char: "/",
|
|
95
|
-
startOfLine:
|
|
118
|
+
startOfLine: false,
|
|
96
119
|
command: ({ editor, range, props }) => {
|
|
97
120
|
editor.chain().focus().deleteRange(range).run();
|
|
98
121
|
props.command(editor);
|