@_sh/strapi-plugin-ckeditor 4.0.11 → 5.0.1
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 +588 -575
- package/dist/_chunks/Field-BdtPMWJ1.js +600 -0
- package/dist/_chunks/Field-wVg5xgbq.mjs +576 -0
- package/dist/_chunks/index-CZRYkPJ8.js +1350 -0
- package/dist/_chunks/index-Clyv4ZPF.mjs +1330 -0
- package/dist/admin/index.js +11 -4
- package/dist/admin/index.mjs +10 -4
- package/dist/admin/src/components/CKEReact.d.ts +6 -0
- package/dist/admin/src/components/CKEditorIcon.d.ts +1 -0
- package/dist/admin/src/components/Editor.d.ts +1 -0
- package/dist/admin/src/components/EditorLayout.d.ts +4 -0
- package/dist/admin/src/components/EditorProvider.d.ts +20 -0
- package/dist/admin/src/components/Field.d.ts +20 -0
- package/dist/admin/src/components/GlobalStyling.d.ts +4 -0
- package/dist/admin/src/components/MediaLib.d.ts +9 -0
- package/dist/admin/src/config/htmlPreset.d.ts +2 -0
- package/dist/admin/src/config/index.d.ts +5 -0
- package/dist/admin/src/config/language.d.ts +15 -0
- package/dist/admin/src/config/markdownPreset.d.ts +2 -0
- package/dist/admin/src/config/pluginConfig.d.ts +23 -0
- package/dist/admin/src/config/types.d.ts +123 -0
- package/dist/admin/src/exports.d.ts +9 -0
- package/dist/admin/src/index.d.ts +6 -0
- package/dist/admin/src/plugins/StrapiMediaLib.d.ts +15 -0
- package/dist/admin/src/plugins/StrapiUploadAdapter.d.ts +12 -0
- package/dist/admin/src/plugins/index.d.ts +2 -0
- package/dist/admin/src/theme/additional.d.ts +1 -0
- package/dist/admin/src/theme/colors.d.ts +1 -0
- package/dist/admin/src/theme/common.d.ts +1 -0
- package/dist/admin/src/theme/dark.d.ts +1 -0
- package/dist/admin/src/theme/index.d.ts +2 -0
- package/dist/admin/src/theme/light.d.ts +1 -0
- package/dist/admin/src/utils/index.d.ts +4 -0
- package/dist/admin/src/utils/isImageResponsive.d.ts +3 -0
- package/dist/admin/src/utils/localStorage.d.ts +3 -0
- package/dist/admin/src/utils/pluginId.d.ts +1 -0
- package/dist/admin/src/utils/prefixWithBackendUrl.d.ts +1 -0
- package/dist/server/index.js +61 -119
- package/dist/server/index.mjs +61 -117
- package/dist/server/src/index.d.ts +7 -0
- package/package.json +50 -22
- package/dist/_chunks/index-5LGZsCS3.mjs +0 -1125
- package/dist/_chunks/index-5LGZsCS3.mjs.map +0 -1
- package/dist/_chunks/index-B5HkOicq.mjs +0 -3530
- package/dist/_chunks/index-B5HkOicq.mjs.map +0 -1
- package/dist/_chunks/index-BOqpyEaD.js +0 -1150
- package/dist/_chunks/index-BOqpyEaD.js.map +0 -1
- package/dist/_chunks/index-BQ7yqvCN.mjs +0 -1124
- package/dist/_chunks/index-BQ7yqvCN.mjs.map +0 -1
- package/dist/_chunks/index-BZP-quaN.mjs +0 -3530
- package/dist/_chunks/index-BZP-quaN.mjs.map +0 -1
- package/dist/_chunks/index-BZZiYjTp.mjs +0 -3530
- package/dist/_chunks/index-BZZiYjTp.mjs.map +0 -1
- package/dist/_chunks/index-Be-t5n4r.mjs +0 -1125
- package/dist/_chunks/index-Be-t5n4r.mjs.map +0 -1
- package/dist/_chunks/index-BiOS6ItS.js +0 -1150
- package/dist/_chunks/index-BiOS6ItS.js.map +0 -1
- package/dist/_chunks/index-C4BPSFZt.mjs +0 -3530
- package/dist/_chunks/index-C4BPSFZt.mjs.map +0 -1
- package/dist/_chunks/index-CFskHjqL.js +0 -3548
- package/dist/_chunks/index-CFskHjqL.js.map +0 -1
- package/dist/_chunks/index-CPBrnTwd.mjs +0 -1124
- package/dist/_chunks/index-CPBrnTwd.mjs.map +0 -1
- package/dist/_chunks/index-CRK4zk5I.js +0 -3548
- package/dist/_chunks/index-CRK4zk5I.js.map +0 -1
- package/dist/_chunks/index-CUmwBN9O.js +0 -1151
- package/dist/_chunks/index-CUmwBN9O.js.map +0 -1
- package/dist/_chunks/index-CaYpAgjX.js +0 -1151
- package/dist/_chunks/index-CaYpAgjX.js.map +0 -1
- package/dist/_chunks/index-pRK2Er3w.js +0 -3548
- package/dist/_chunks/index-pRK2Er3w.js.map +0 -1
- package/dist/_chunks/index-uYy-Myyv.js +0 -3548
- package/dist/_chunks/index-uYy-Myyv.js.map +0 -1
- package/dist/admin/index.js.map +0 -1
- package/dist/admin/index.mjs.map +0 -1
- package/dist/server/index.js.map +0 -1
- package/dist/server/index.mjs.map +0 -1
- package/strapi-server.js +0 -3
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
25
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
26
|
+
const React = require("react");
|
|
27
|
+
const designSystem = require("@strapi/design-system");
|
|
28
|
+
const styledComponents = require("styled-components");
|
|
29
|
+
const admin = require("@strapi/strapi/admin");
|
|
30
|
+
const ckeditor5 = require("ckeditor5");
|
|
31
|
+
const ckeditor5React = require("@ckeditor/ckeditor5-react");
|
|
32
|
+
require("ckeditor5/ckeditor5.css");
|
|
33
|
+
const index = require("./index-CZRYkPJ8.js");
|
|
34
|
+
const icons = require("@strapi/icons");
|
|
35
|
+
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
36
|
+
const React__default = /* @__PURE__ */ _interopDefault(React);
|
|
37
|
+
const STORAGE_KEYS = {
|
|
38
|
+
TOKEN: "jwtToken",
|
|
39
|
+
PREFERED_LANGUAGE: "strapi-admin-language",
|
|
40
|
+
PROFILE_THEME: "STRAPI_THEME"
|
|
41
|
+
};
|
|
42
|
+
function getStoredToken() {
|
|
43
|
+
const token = localStorage.getItem(STORAGE_KEYS.TOKEN) ?? sessionStorage.getItem(STORAGE_KEYS.TOKEN);
|
|
44
|
+
if (typeof token === "string") {
|
|
45
|
+
return JSON.parse(token);
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
function getPreferedLanguage() {
|
|
50
|
+
const language = localStorage.getItem(STORAGE_KEYS.PREFERED_LANGUAGE)?.replace(/^"|"$/g, "") || "en";
|
|
51
|
+
return language;
|
|
52
|
+
}
|
|
53
|
+
function getProfileTheme() {
|
|
54
|
+
const theme = localStorage.getItem(STORAGE_KEYS.PROFILE_THEME);
|
|
55
|
+
return theme;
|
|
56
|
+
}
|
|
57
|
+
const TRANSLATIONS = {};
|
|
58
|
+
async function setUpLanguage(config, isFieldLocalized) {
|
|
59
|
+
if (typeof config.language !== "object") {
|
|
60
|
+
config.language = {
|
|
61
|
+
ui: config.language,
|
|
62
|
+
content: config.language,
|
|
63
|
+
textPartLanguage: void 0
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
config.language.ui ||= getPreferedLanguage();
|
|
67
|
+
if (isFieldLocalized) {
|
|
68
|
+
config.language.content = detecti18n();
|
|
69
|
+
}
|
|
70
|
+
if (config.language.ui !== "en") {
|
|
71
|
+
await importLang(config, config.language.ui);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function importLang(config, language) {
|
|
75
|
+
if (TRANSLATIONS[language]) {
|
|
76
|
+
config.translations = TRANSLATIONS[language];
|
|
77
|
+
} else if (translationImports[language]) {
|
|
78
|
+
const translation = await translationImports[language]();
|
|
79
|
+
TRANSLATIONS[language] = translation.default;
|
|
80
|
+
config.translations = translation.default;
|
|
81
|
+
} else {
|
|
82
|
+
console.warn(`No CKEditor translation found for language: ${language}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function detecti18n() {
|
|
86
|
+
const urlSearchParams = new URLSearchParams(window.location.search);
|
|
87
|
+
const params = Object.fromEntries(urlSearchParams.entries());
|
|
88
|
+
const i18n = params["plugins[i18n][locale]"];
|
|
89
|
+
return i18n && i18n.split("-")[0];
|
|
90
|
+
}
|
|
91
|
+
const translationImports = {
|
|
92
|
+
af: () => import("ckeditor5/translations/af.js"),
|
|
93
|
+
ar: () => import("ckeditor5/translations/ar.js"),
|
|
94
|
+
ast: () => import("ckeditor5/translations/ast.js"),
|
|
95
|
+
az: () => import("ckeditor5/translations/az.js"),
|
|
96
|
+
bg: () => import("ckeditor5/translations/bg.js"),
|
|
97
|
+
bn: () => import("ckeditor5/translations/bn.js"),
|
|
98
|
+
bs: () => import("ckeditor5/translations/bs.js"),
|
|
99
|
+
ca: () => import("ckeditor5/translations/ca.js"),
|
|
100
|
+
cs: () => import("ckeditor5/translations/cs.js"),
|
|
101
|
+
da: () => import("ckeditor5/translations/da.js"),
|
|
102
|
+
"de-ch": () => import("ckeditor5/translations/de-ch.js"),
|
|
103
|
+
de: () => import("ckeditor5/translations/de.js"),
|
|
104
|
+
el: () => import("ckeditor5/translations/el.js"),
|
|
105
|
+
"en-au": () => import("ckeditor5/translations/en-au.js"),
|
|
106
|
+
"en-gb": () => import("ckeditor5/translations/en-gb.js"),
|
|
107
|
+
en: () => import("ckeditor5/translations/en.js"),
|
|
108
|
+
eo: () => import("ckeditor5/translations/eo.js"),
|
|
109
|
+
"es-co": () => import("ckeditor5/translations/es-co.js"),
|
|
110
|
+
es: () => import("ckeditor5/translations/es.js"),
|
|
111
|
+
et: () => import("ckeditor5/translations/et.js"),
|
|
112
|
+
eu: () => import("ckeditor5/translations/eu.js"),
|
|
113
|
+
fa: () => import("ckeditor5/translations/fa.js"),
|
|
114
|
+
fi: () => import("ckeditor5/translations/fi.js"),
|
|
115
|
+
fr: () => import("ckeditor5/translations/fr.js"),
|
|
116
|
+
gl: () => import("ckeditor5/translations/gl.js"),
|
|
117
|
+
gu: () => import("ckeditor5/translations/gu.js"),
|
|
118
|
+
he: () => import("ckeditor5/translations/he.js"),
|
|
119
|
+
hi: () => import("ckeditor5/translations/hi.js"),
|
|
120
|
+
hr: () => import("ckeditor5/translations/hr.js"),
|
|
121
|
+
hu: () => import("ckeditor5/translations/hu.js"),
|
|
122
|
+
hy: () => import("ckeditor5/translations/hy.js"),
|
|
123
|
+
id: () => import("ckeditor5/translations/id.js"),
|
|
124
|
+
it: () => import("ckeditor5/translations/it.js"),
|
|
125
|
+
ja: () => import("ckeditor5/translations/ja.js"),
|
|
126
|
+
jv: () => import("ckeditor5/translations/jv.js"),
|
|
127
|
+
kk: () => import("ckeditor5/translations/kk.js"),
|
|
128
|
+
km: () => import("ckeditor5/translations/km.js"),
|
|
129
|
+
kn: () => import("ckeditor5/translations/kn.js"),
|
|
130
|
+
ko: () => import("ckeditor5/translations/ko.js"),
|
|
131
|
+
ku: () => import("ckeditor5/translations/ku.js"),
|
|
132
|
+
lt: () => import("ckeditor5/translations/lt.js"),
|
|
133
|
+
lv: () => import("ckeditor5/translations/lv.js"),
|
|
134
|
+
ms: () => import("ckeditor5/translations/ms.js"),
|
|
135
|
+
nb: () => import("ckeditor5/translations/nb.js"),
|
|
136
|
+
ne: () => import("ckeditor5/translations/ne.js"),
|
|
137
|
+
nl: () => import("ckeditor5/translations/nl.js"),
|
|
138
|
+
no: () => import("ckeditor5/translations/no.js"),
|
|
139
|
+
oc: () => import("ckeditor5/translations/oc.js"),
|
|
140
|
+
pl: () => import("ckeditor5/translations/pl.js"),
|
|
141
|
+
"pt-br": () => import("ckeditor5/translations/pt-br.js"),
|
|
142
|
+
pt: () => import("ckeditor5/translations/pt.js"),
|
|
143
|
+
ro: () => import("ckeditor5/translations/ro.js"),
|
|
144
|
+
ru: () => import("ckeditor5/translations/ru.js"),
|
|
145
|
+
si: () => import("ckeditor5/translations/si.js"),
|
|
146
|
+
sk: () => import("ckeditor5/translations/sk.js"),
|
|
147
|
+
sl: () => import("ckeditor5/translations/sl.js"),
|
|
148
|
+
sq: () => import("ckeditor5/translations/sq.js"),
|
|
149
|
+
sr: () => import("ckeditor5/translations/sr.js"),
|
|
150
|
+
"sr-latn": () => import("ckeditor5/translations/sr-latn.js"),
|
|
151
|
+
sv: () => import("ckeditor5/translations/sv.js"),
|
|
152
|
+
th: () => import("ckeditor5/translations/th.js"),
|
|
153
|
+
ti: () => import("ckeditor5/translations/ti.js"),
|
|
154
|
+
tk: () => import("ckeditor5/translations/tk.js"),
|
|
155
|
+
tr: () => import("ckeditor5/translations/tr.js"),
|
|
156
|
+
tt: () => import("ckeditor5/translations/tt.js"),
|
|
157
|
+
ug: () => import("ckeditor5/translations/ug.js"),
|
|
158
|
+
uk: () => import("ckeditor5/translations/uk.js"),
|
|
159
|
+
ur: () => import("ckeditor5/translations/ur.js"),
|
|
160
|
+
uz: () => import("ckeditor5/translations/uz.js"),
|
|
161
|
+
vi: () => import("ckeditor5/translations/vi.js"),
|
|
162
|
+
"zh-cn": () => import("ckeditor5/translations/zh-cn.js"),
|
|
163
|
+
zh: () => import("ckeditor5/translations/zh.js")
|
|
164
|
+
};
|
|
165
|
+
const EditorContext = React.createContext(null);
|
|
166
|
+
function useEditorContext() {
|
|
167
|
+
const context = React.useContext(EditorContext);
|
|
168
|
+
if (!context) {
|
|
169
|
+
throw new Error("The useEditorContext hook must be used within the EditorProvider.");
|
|
170
|
+
}
|
|
171
|
+
return context;
|
|
172
|
+
}
|
|
173
|
+
function EditorProvider({
|
|
174
|
+
name,
|
|
175
|
+
disabled,
|
|
176
|
+
error,
|
|
177
|
+
placeholder,
|
|
178
|
+
hint,
|
|
179
|
+
label,
|
|
180
|
+
labelAction,
|
|
181
|
+
required,
|
|
182
|
+
presetName,
|
|
183
|
+
wordsLimit,
|
|
184
|
+
charsLimit,
|
|
185
|
+
children,
|
|
186
|
+
isFieldLocalized
|
|
187
|
+
}) {
|
|
188
|
+
const [preset, setPreset] = React.useState(null);
|
|
189
|
+
React.useEffect(() => {
|
|
190
|
+
(async () => {
|
|
191
|
+
const { presets } = index.getPluginConfig();
|
|
192
|
+
const currentPreset = clonePreset(presets[presetName]);
|
|
193
|
+
await setUpLanguage(currentPreset.editorConfig, isFieldLocalized);
|
|
194
|
+
if (placeholder) {
|
|
195
|
+
currentPreset.editorConfig.placeholder = placeholder;
|
|
196
|
+
}
|
|
197
|
+
setPreset(currentPreset);
|
|
198
|
+
})();
|
|
199
|
+
}, [presetName, placeholder, isFieldLocalized]);
|
|
200
|
+
const EditorContextValue = React.useMemo(
|
|
201
|
+
() => ({
|
|
202
|
+
name,
|
|
203
|
+
disabled,
|
|
204
|
+
placeholder,
|
|
205
|
+
hint,
|
|
206
|
+
label,
|
|
207
|
+
labelAction,
|
|
208
|
+
required,
|
|
209
|
+
presetName,
|
|
210
|
+
preset,
|
|
211
|
+
error,
|
|
212
|
+
wordsLimit,
|
|
213
|
+
charsLimit,
|
|
214
|
+
isFieldLocalized
|
|
215
|
+
}),
|
|
216
|
+
[
|
|
217
|
+
name,
|
|
218
|
+
disabled,
|
|
219
|
+
placeholder,
|
|
220
|
+
hint,
|
|
221
|
+
label,
|
|
222
|
+
labelAction,
|
|
223
|
+
required,
|
|
224
|
+
presetName,
|
|
225
|
+
wordsLimit,
|
|
226
|
+
charsLimit,
|
|
227
|
+
preset,
|
|
228
|
+
error,
|
|
229
|
+
isFieldLocalized
|
|
230
|
+
]
|
|
231
|
+
);
|
|
232
|
+
return /* @__PURE__ */ jsxRuntime.jsx(EditorContext.Provider, { value: EditorContextValue, children });
|
|
233
|
+
}
|
|
234
|
+
function clonePreset(preset) {
|
|
235
|
+
const clonedPreset = {
|
|
236
|
+
...preset,
|
|
237
|
+
editorConfig: {
|
|
238
|
+
...preset.editorConfig
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
Object.entries(clonedPreset.editorConfig).forEach(([key, val]) => {
|
|
242
|
+
if (val && typeof val === "object" && Object.getPrototypeOf(val) === Object.prototype) {
|
|
243
|
+
clonedPreset.editorConfig[key] = { ...val };
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
return clonedPreset;
|
|
247
|
+
}
|
|
248
|
+
function MediaLib({ isOpen = false, toggle, handleChangeAssets }) {
|
|
249
|
+
const components = admin.useStrapiApp("MediaLib", (state) => state.components);
|
|
250
|
+
const MediaLibraryDialog = components["media-library"];
|
|
251
|
+
function handleSelectAssets(files) {
|
|
252
|
+
const formattedFiles = files.map((f) => ({
|
|
253
|
+
name: f.name,
|
|
254
|
+
alt: f.alternativeText || f.name,
|
|
255
|
+
url: index.prefixFileUrlWithBackendUrl(f.url),
|
|
256
|
+
mime: f.mime,
|
|
257
|
+
formats: f.formats,
|
|
258
|
+
width: f.width,
|
|
259
|
+
height: f.height
|
|
260
|
+
}));
|
|
261
|
+
const newElems = getNewElems(formattedFiles);
|
|
262
|
+
handleChangeAssets(newElems);
|
|
263
|
+
}
|
|
264
|
+
function getNewElems(assets) {
|
|
265
|
+
let newElems = "";
|
|
266
|
+
assets.forEach(({ name, url, alt, formats, mime, width, height }) => {
|
|
267
|
+
if (mime.includes("image")) {
|
|
268
|
+
if (formats && index.isImageResponsive(formats)) {
|
|
269
|
+
const set = formSrcSet(formats);
|
|
270
|
+
newElems += `<img src="${url}" alt="${alt}" width="${width}" height="${height}" srcset="${set}" />`;
|
|
271
|
+
} else {
|
|
272
|
+
newElems += `<img src="${url}" alt="${alt}" width="${width}" height="${height}" />`;
|
|
273
|
+
}
|
|
274
|
+
} else if (mime.includes("video")) {
|
|
275
|
+
newElems += `
|
|
276
|
+
<video class="video" controls width="500px">
|
|
277
|
+
<source src="${url}" type="${mime}" />
|
|
278
|
+
</video>`;
|
|
279
|
+
} else {
|
|
280
|
+
newElems += `<a href="${url}">${name || "Open document"}</a>`;
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
return newElems;
|
|
284
|
+
}
|
|
285
|
+
function formSrcSet(formats) {
|
|
286
|
+
let set = "";
|
|
287
|
+
const keys = Object.keys(formats).sort((a, b) => formats[a].width - formats[b].width);
|
|
288
|
+
keys.forEach((k) => {
|
|
289
|
+
set += `${index.prefixFileUrlWithBackendUrl(formats[k].url)} ${formats[k].width}w,`;
|
|
290
|
+
});
|
|
291
|
+
return set;
|
|
292
|
+
}
|
|
293
|
+
if (!isOpen) {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MediaLibraryDialog, { onClose: toggle, onSelectAssets: handleSelectAssets });
|
|
297
|
+
}
|
|
298
|
+
const MemoizedMediaLib = React__default.default.memo(MediaLib);
|
|
299
|
+
function CKEReact() {
|
|
300
|
+
const [mediaLibVisible, setMediaLibVisible] = React.useState(false);
|
|
301
|
+
const [editorInstance, setEditorInstance] = React.useState(null);
|
|
302
|
+
const [isWordsMax, setIsWordsMax] = React.useState(false);
|
|
303
|
+
const [isCharsMax, setIsCharsMax] = React.useState(false);
|
|
304
|
+
const { name, disabled, preset, wordsLimit, charsLimit } = useEditorContext();
|
|
305
|
+
const { onChange: fieldOnChange, value: fieldValue } = admin.useField(name);
|
|
306
|
+
const wordCounterRef = React.useRef(null);
|
|
307
|
+
const onEditorReady = (editor) => {
|
|
308
|
+
setUpPlugins(editor);
|
|
309
|
+
setEditorInstance(editor);
|
|
310
|
+
};
|
|
311
|
+
const onEditorChange = (_e, editor) => {
|
|
312
|
+
const data = editor.getData();
|
|
313
|
+
fieldOnChange(name, data);
|
|
314
|
+
};
|
|
315
|
+
const toggleMediaLib = React.useCallback(() => setMediaLibVisible((prev) => !prev), [setMediaLibVisible]);
|
|
316
|
+
const handleChangeAssets = React.useCallback(
|
|
317
|
+
(newElems) => {
|
|
318
|
+
if (!editorInstance) {
|
|
319
|
+
throw new Error("The editor instance has not been initialized.");
|
|
320
|
+
}
|
|
321
|
+
const viewFragment = editorInstance.data.processor.toView(newElems);
|
|
322
|
+
const modelFragment = editorInstance.data.toModel(viewFragment);
|
|
323
|
+
editorInstance?.model.insertContent(modelFragment);
|
|
324
|
+
toggleMediaLib();
|
|
325
|
+
},
|
|
326
|
+
[toggleMediaLib, editorInstance]
|
|
327
|
+
);
|
|
328
|
+
if (!preset) {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
332
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
333
|
+
ckeditor5React.CKEditor,
|
|
334
|
+
{
|
|
335
|
+
editor: ckeditor5.ClassicEditor,
|
|
336
|
+
config: preset.editorConfig,
|
|
337
|
+
disabled,
|
|
338
|
+
data: fieldValue ?? "",
|
|
339
|
+
onReady: onEditorReady,
|
|
340
|
+
onChange: onEditorChange
|
|
341
|
+
}
|
|
342
|
+
),
|
|
343
|
+
/* @__PURE__ */ jsxRuntime.jsx(WordCounter, { ref: wordCounterRef, $isWordsMax: isWordsMax, $isCharsMax: isCharsMax }),
|
|
344
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
345
|
+
MemoizedMediaLib,
|
|
346
|
+
{
|
|
347
|
+
isOpen: mediaLibVisible,
|
|
348
|
+
toggle: toggleMediaLib,
|
|
349
|
+
handleChangeAssets
|
|
350
|
+
}
|
|
351
|
+
)
|
|
352
|
+
] });
|
|
353
|
+
function setUpPlugins(editor) {
|
|
354
|
+
const pluginsToSetup = {
|
|
355
|
+
WordCount: setUpWordCount,
|
|
356
|
+
ImageUploadEditing: setUpImageUploadEditing,
|
|
357
|
+
StrapiMediaLib: setUpStrapiMediaLib,
|
|
358
|
+
StrapiUploadAdapter: setUpStrapiUploadAdapter
|
|
359
|
+
};
|
|
360
|
+
Object.entries(pluginsToSetup).forEach(([pluginName, setUpFn]) => {
|
|
361
|
+
if (editor.plugins.has(pluginName)) {
|
|
362
|
+
try {
|
|
363
|
+
setUpFn(editor);
|
|
364
|
+
} catch (err) {
|
|
365
|
+
console.error(`Failed to set up the ${pluginName} plugin `, err);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
function setUpWordCount(editor) {
|
|
371
|
+
const wordCountPlugin = editor.plugins.get("WordCount");
|
|
372
|
+
if (wordsLimit || charsLimit) {
|
|
373
|
+
wordCountPlugin.on("update", (_e, stats) => validateInputLength(stats));
|
|
374
|
+
const { words, characters } = wordCountPlugin;
|
|
375
|
+
validateInputLength({ words, characters });
|
|
376
|
+
}
|
|
377
|
+
wordCounterRef.current?.appendChild(wordCountPlugin.wordCountContainer);
|
|
378
|
+
}
|
|
379
|
+
function setUpImageUploadEditing(editor) {
|
|
380
|
+
const imageUploadEditingPlugin = editor.plugins.get("ImageUploadEditing");
|
|
381
|
+
const setAltAttribute = (_e, { data, imageElement }) => {
|
|
382
|
+
editor.model.change((writer) => {
|
|
383
|
+
writer.setAttribute("alt", data.alt, imageElement);
|
|
384
|
+
});
|
|
385
|
+
};
|
|
386
|
+
imageUploadEditingPlugin.on("uploadComplete", setAltAttribute);
|
|
387
|
+
}
|
|
388
|
+
function setUpStrapiMediaLib(editor) {
|
|
389
|
+
const strapiMediaLibPlugin = editor.plugins.get("StrapiMediaLib");
|
|
390
|
+
strapiMediaLibPlugin.connect(toggleMediaLib);
|
|
391
|
+
}
|
|
392
|
+
function setUpStrapiUploadAdapter(editor) {
|
|
393
|
+
const StrapiUploadAdapterPlugin = editor.plugins.get(
|
|
394
|
+
"StrapiUploadAdapter"
|
|
395
|
+
);
|
|
396
|
+
const token = getStoredToken();
|
|
397
|
+
const config = {
|
|
398
|
+
uploadUrl: index.prefixFileUrlWithBackendUrl("/upload"),
|
|
399
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
400
|
+
};
|
|
401
|
+
StrapiUploadAdapterPlugin.initAdapter(config);
|
|
402
|
+
}
|
|
403
|
+
function validateInputLength(stats) {
|
|
404
|
+
if (wordsLimit) {
|
|
405
|
+
setIsWordsMax(stats.words > wordsLimit);
|
|
406
|
+
}
|
|
407
|
+
if (charsLimit) {
|
|
408
|
+
setIsCharsMax(stats.characters > charsLimit);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
const WordCounter = styledComponents.styled(designSystem.Flex)`
|
|
413
|
+
${({ theme, $isWordsMax, $isCharsMax }) => styledComponents.css`
|
|
414
|
+
.ck-word-count__words {
|
|
415
|
+
color: ${$isWordsMax ? theme.colors.danger600 : theme.colors.neutral400};
|
|
416
|
+
}
|
|
417
|
+
.ck-word-count__characters {
|
|
418
|
+
color: ${$isCharsMax ? theme.colors.danger600 : theme.colors.neutral400};
|
|
419
|
+
}
|
|
420
|
+
`}
|
|
421
|
+
`;
|
|
422
|
+
function EditorLayout({ children }) {
|
|
423
|
+
const { error, preset } = useEditorContext();
|
|
424
|
+
const [isExpandedMode, setIsExpandedMode] = React.useState(false);
|
|
425
|
+
const handleToggleExpand = () => setIsExpandedMode(true);
|
|
426
|
+
const handleOnCollapse = () => setIsExpandedMode(false);
|
|
427
|
+
React.useEffect(() => {
|
|
428
|
+
if (isExpandedMode) {
|
|
429
|
+
document.body.classList.add("lock-body-scroll");
|
|
430
|
+
}
|
|
431
|
+
return () => {
|
|
432
|
+
document.body.classList.remove("lock-body-scroll");
|
|
433
|
+
};
|
|
434
|
+
}, [isExpandedMode]);
|
|
435
|
+
if (isExpandedMode) {
|
|
436
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Portal, { role: "dialog", "aria-modal": false, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.FocusTrap, { onEscape: handleOnCollapse, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
437
|
+
Backdrop,
|
|
438
|
+
{
|
|
439
|
+
position: "fixed",
|
|
440
|
+
top: 0,
|
|
441
|
+
left: 0,
|
|
442
|
+
right: 0,
|
|
443
|
+
bottom: 0,
|
|
444
|
+
zIndex: 4,
|
|
445
|
+
justifyContent: "center",
|
|
446
|
+
onClick: handleOnCollapse,
|
|
447
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
448
|
+
FullScreenBox,
|
|
449
|
+
{
|
|
450
|
+
background: "neutral100",
|
|
451
|
+
hasRadius: true,
|
|
452
|
+
shadow: "popupShadow",
|
|
453
|
+
overflow: "hidden",
|
|
454
|
+
width: "90%",
|
|
455
|
+
height: "90%",
|
|
456
|
+
onClick: (e) => e.stopPropagation(),
|
|
457
|
+
position: "relative",
|
|
458
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { height: "100%", alignItems: "flex-start", direction: "column", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
459
|
+
EditorWrapper,
|
|
460
|
+
{
|
|
461
|
+
$presetStyles: preset?.styles,
|
|
462
|
+
$isExpanded: isExpandedMode,
|
|
463
|
+
$hasError: Boolean(error),
|
|
464
|
+
className: "ck-editor__expanded",
|
|
465
|
+
children: [
|
|
466
|
+
children,
|
|
467
|
+
/* @__PURE__ */ jsxRuntime.jsx(CollapseButton, { label: "Collapse", onClick: handleOnCollapse, children: /* @__PURE__ */ jsxRuntime.jsx(icons.Collapse, {}) })
|
|
468
|
+
]
|
|
469
|
+
}
|
|
470
|
+
) })
|
|
471
|
+
}
|
|
472
|
+
)
|
|
473
|
+
}
|
|
474
|
+
) }) });
|
|
475
|
+
}
|
|
476
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
477
|
+
EditorWrapper,
|
|
478
|
+
{
|
|
479
|
+
$presetStyles: preset?.styles,
|
|
480
|
+
$isExpanded: isExpandedMode,
|
|
481
|
+
$hasError: Boolean(error),
|
|
482
|
+
children: [
|
|
483
|
+
children,
|
|
484
|
+
/* @__PURE__ */ jsxRuntime.jsx(ExpandButton, { label: "Expand", onClick: handleToggleExpand, children: /* @__PURE__ */ jsxRuntime.jsx(icons.Expand, {}) })
|
|
485
|
+
]
|
|
486
|
+
}
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
const EditorWrapper = styledComponents.styled("div")`
|
|
490
|
+
position: relative;
|
|
491
|
+
width: 100%;
|
|
492
|
+
|
|
493
|
+
${({ $presetStyles, theme, $hasError = false, $isExpanded }) => styledComponents.css`
|
|
494
|
+
height: ${$isExpanded ? "100%" : "auto"};
|
|
495
|
+
border-radius: ${theme.borderRadius};
|
|
496
|
+
outline: none;
|
|
497
|
+
box-shadow: 0;
|
|
498
|
+
transition-property: border-color, box-shadow, fill;
|
|
499
|
+
transition-duration: 0.2s;
|
|
500
|
+
border: 1px solid ${$hasError ? theme.colors.danger600 : theme.colors.neutral200};
|
|
501
|
+
border-radius: ${theme.borderRadius};
|
|
502
|
+
|
|
503
|
+
&:focus-within {
|
|
504
|
+
border: 1px solid ${$isExpanded ? theme.colors.neutral200 : theme.colors.primary600};
|
|
505
|
+
border-color: ${$hasError && theme.colors.danger600};
|
|
506
|
+
box-shadow: ${$hasError ? theme.colors.danger600 : theme.colors.primary600} 0px 0px 0px 2px;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
${$presetStyles}
|
|
510
|
+
`}
|
|
511
|
+
`;
|
|
512
|
+
const Backdrop = styledComponents.styled(designSystem.Flex)`
|
|
513
|
+
background: ${({ theme }) => `${theme.colors.neutral800}1F`};
|
|
514
|
+
`;
|
|
515
|
+
const ExpandButton = styledComponents.styled(designSystem.IconButton)`
|
|
516
|
+
position: absolute;
|
|
517
|
+
bottom: 1.4rem;
|
|
518
|
+
right: 1.2rem;
|
|
519
|
+
z-index: 2;
|
|
520
|
+
`;
|
|
521
|
+
const CollapseButton = styledComponents.styled(designSystem.IconButton)`
|
|
522
|
+
position: absolute;
|
|
523
|
+
bottom: 2.5rem;
|
|
524
|
+
right: 1.2rem;
|
|
525
|
+
z-index: 2;
|
|
526
|
+
`;
|
|
527
|
+
const FullScreenBox = styledComponents.styled(designSystem.Box)`
|
|
528
|
+
max-width: var(--ck-editor-full-screen-box-max-width);
|
|
529
|
+
`;
|
|
530
|
+
const GlobalStyle = styledComponents.createGlobalStyle`
|
|
531
|
+
${({ $editortTheme, $variant }) => $editortTheme && styledComponents.css`
|
|
532
|
+
${$editortTheme.common}
|
|
533
|
+
${$editortTheme[$variant]}
|
|
534
|
+
${$editortTheme.additional}
|
|
535
|
+
`}
|
|
536
|
+
`;
|
|
537
|
+
const getSystemColorScheme = () => window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
538
|
+
function GlobalStyling() {
|
|
539
|
+
const { theme } = index.getPluginConfig();
|
|
540
|
+
const profileTheme = getProfileTheme();
|
|
541
|
+
const variant = profileTheme && profileTheme !== "system" ? profileTheme : getSystemColorScheme();
|
|
542
|
+
return /* @__PURE__ */ jsxRuntime.jsx(GlobalStyle, { $editortTheme: theme, $variant: variant });
|
|
543
|
+
}
|
|
544
|
+
const MemoizedGlobalStyling = React__default.default.memo(GlobalStyling);
|
|
545
|
+
function Editor() {
|
|
546
|
+
const { name, hint, required, labelAction, label, error, preset } = useEditorContext();
|
|
547
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Root, { id: name, name, error, hint, required, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 1, children: [
|
|
548
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { action: labelAction, children: label }),
|
|
549
|
+
preset ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
550
|
+
/* @__PURE__ */ jsxRuntime.jsx(MemoizedGlobalStyling, {}),
|
|
551
|
+
/* @__PURE__ */ jsxRuntime.jsx(EditorLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(CKEReact, {}) })
|
|
552
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(LoaderBox, { hasRadius: true, background: "neutral100", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { children: "Loading..." }) }),
|
|
553
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {}),
|
|
554
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {})
|
|
555
|
+
] }) });
|
|
556
|
+
}
|
|
557
|
+
const LoaderBox = styledComponents.styled(designSystem.Box)`
|
|
558
|
+
display: flex;
|
|
559
|
+
justify-content: center;
|
|
560
|
+
align-items: center;
|
|
561
|
+
height: 200px;
|
|
562
|
+
width: 100%;
|
|
563
|
+
`;
|
|
564
|
+
function Field({
|
|
565
|
+
name,
|
|
566
|
+
hint,
|
|
567
|
+
error,
|
|
568
|
+
placeholder,
|
|
569
|
+
label,
|
|
570
|
+
attribute,
|
|
571
|
+
labelAction = null,
|
|
572
|
+
disabled = false,
|
|
573
|
+
required = false
|
|
574
|
+
}) {
|
|
575
|
+
const { preset, maxLengthWords, maxLengthCharacters } = attribute.options;
|
|
576
|
+
const isFieldLocalized = attribute?.pluginOptions?.i18n?.localized ?? false;
|
|
577
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
578
|
+
EditorProvider,
|
|
579
|
+
{
|
|
580
|
+
name,
|
|
581
|
+
error,
|
|
582
|
+
disabled,
|
|
583
|
+
required,
|
|
584
|
+
placeholder,
|
|
585
|
+
hint,
|
|
586
|
+
label,
|
|
587
|
+
labelAction,
|
|
588
|
+
presetName: preset,
|
|
589
|
+
wordsLimit: maxLengthWords,
|
|
590
|
+
charsLimit: maxLengthCharacters,
|
|
591
|
+
isFieldLocalized,
|
|
592
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Editor, {})
|
|
593
|
+
}
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
function compare(oldProps, newProps) {
|
|
597
|
+
return oldProps.error === newProps.error && oldProps.labelAction === newProps.labelAction;
|
|
598
|
+
}
|
|
599
|
+
const MemoizedField = React__default.default.memo(Field, compare);
|
|
600
|
+
exports.Field = MemoizedField;
|