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