@notum-cz/strapi-plugin-tiptap-editor 1.0.3-rc.5 → 1.1.0

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.
@@ -6,7 +6,7 @@ import ReactDOM, { flushSync } from "react-dom";
6
6
  import styled from "styled-components";
7
7
  import { useField, useFetchClient } from "@strapi/strapi/admin";
8
8
  import { Quotes, Code as Code$1, NumberList, BulletList as BulletList$1, StrikeThrough, Underline as Underline$1, Italic as Italic$1, Bold as Bold$1, Link as Link$1, Trash, Image as Image$1, GridNine } from "@strapi/icons";
9
- import { g as getMediaLibraryComponent, a as getThemeCache } from "./index-D4RQaRyr.mjs";
9
+ import { g as getMediaLibraryComponent, a as getThemeCache } from "./index-sX8SY6P-.mjs";
10
10
  var shim = { exports: {} };
11
11
  var useSyncExternalStoreShim_production = {};
12
12
  /**
@@ -8,7 +8,7 @@ const ReactDOM = require("react-dom");
8
8
  const styled = require("styled-components");
9
9
  const admin = require("@strapi/strapi/admin");
10
10
  const icons = require("@strapi/icons");
11
- const index = require("./index-Nmu3V1bE.js");
11
+ const index = require("./index-yXpX_VsO.js");
12
12
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
13
13
  const React__default = /* @__PURE__ */ _interopDefault(React);
14
14
  const ReactDOM__default = /* @__PURE__ */ _interopDefault(ReactDOM);
@@ -28,26 +28,44 @@ function setThemeCache(theme) {
28
28
  function getThemeCache() {
29
29
  return cache;
30
30
  }
31
- const LINK_ID = "tiptap-theme-stylesheet";
32
- function reconcileThemeStylesheet(href) {
33
- const existing = document.getElementById(LINK_ID);
34
- if (!href) {
31
+ const THEME_STYLE_ID = "tiptap-theme-styles";
32
+ function reconcileThemeStyles(theme) {
33
+ const existing = document.getElementById(THEME_STYLE_ID);
34
+ const { stylesheet, css } = theme;
35
+ if (!stylesheet && !css) {
35
36
  existing?.remove();
36
37
  return Promise.resolve();
37
38
  }
38
- const resolved = new URL(href, document.baseURI).href;
39
- if (existing && existing.href === resolved && existing.sheet) {
39
+ if (css) {
40
+ if (existing && existing.tagName === "STYLE" && existing.textContent === css) {
41
+ return Promise.resolve();
42
+ }
43
+ existing?.remove();
44
+ const style = document.createElement("style");
45
+ style.id = THEME_STYLE_ID;
46
+ style.textContent = css;
47
+ document.head.appendChild(style);
48
+ return Promise.resolve();
49
+ }
50
+ let resolved;
51
+ try {
52
+ resolved = new URL(stylesheet, document.baseURI).href;
53
+ } catch {
54
+ console.warn("[TiptapEditor] Invalid stylesheet URL:", stylesheet);
55
+ return Promise.resolve();
56
+ }
57
+ if (existing && existing.tagName === "LINK" && existing.href === resolved && existing.sheet) {
40
58
  return Promise.resolve();
41
59
  }
42
60
  existing?.remove();
43
61
  return new Promise((resolve) => {
44
62
  const link = document.createElement("link");
45
- link.id = LINK_ID;
63
+ link.id = THEME_STYLE_ID;
46
64
  link.rel = "stylesheet";
47
- link.href = href;
65
+ link.href = stylesheet;
48
66
  link.onload = () => resolve();
49
67
  link.onerror = () => {
50
- console.warn("[TiptapEditor] Failed to load theme stylesheet:", href);
68
+ console.warn("[TiptapEditor] Failed to load theme stylesheet:", stylesheet);
51
69
  resolve();
52
70
  };
53
71
  document.head.appendChild(link);
@@ -58,20 +76,27 @@ const Initializer = ({ setPlugin }) => {
58
76
  const { get } = useFetchClient();
59
77
  useEffect(() => {
60
78
  const fetchTheme = async () => {
61
- let stylesheetHref;
79
+ let themeStyles = {};
62
80
  try {
63
81
  const { data } = await get("/tiptap-editor/theme");
64
82
  if (data && typeof data === "object" && Object.keys(data).length > 0) {
65
83
  setThemeCache(data);
66
- if (typeof data.stylesheet === "string" && data.stylesheet) {
67
- stylesheetHref = data.stylesheet;
84
+ if (typeof data.css === "string" && data.css) {
85
+ themeStyles = { css: data.css };
86
+ } else if (typeof data.stylesheet === "string" && data.stylesheet) {
87
+ themeStyles = { stylesheet: data.stylesheet };
68
88
  }
69
89
  }
70
90
  } catch (error) {
71
91
  console.warn("[TiptapEditor] Failed to fetch theme config:", error);
72
92
  }
73
- await reconcileThemeStylesheet(stylesheetHref);
74
- ref.current(PLUGIN_ID);
93
+ try {
94
+ await reconcileThemeStyles(themeStyles);
95
+ } catch (error) {
96
+ console.warn("[TiptapEditor] Failed to reconcile theme styles:", error);
97
+ } finally {
98
+ ref.current(PLUGIN_ID);
99
+ }
75
100
  };
76
101
  fetchTheme();
77
102
  }, []);
@@ -121,7 +146,7 @@ const richTextField = {
121
146
  },
122
147
  icon: Paragraph,
123
148
  components: {
124
- Input: async () => import("./RichTextInput-C52A0D5O.mjs").then((m) => ({ default: m.default }))
149
+ Input: async () => import("./RichTextInput-B8CLPOyo.mjs").then((m) => ({ default: m.default }))
125
150
  },
126
151
  options: {
127
152
  advanced: [
@@ -29,26 +29,44 @@ function setThemeCache(theme) {
29
29
  function getThemeCache() {
30
30
  return cache;
31
31
  }
32
- const LINK_ID = "tiptap-theme-stylesheet";
33
- function reconcileThemeStylesheet(href) {
34
- const existing = document.getElementById(LINK_ID);
35
- if (!href) {
32
+ const THEME_STYLE_ID = "tiptap-theme-styles";
33
+ function reconcileThemeStyles(theme) {
34
+ const existing = document.getElementById(THEME_STYLE_ID);
35
+ const { stylesheet, css } = theme;
36
+ if (!stylesheet && !css) {
36
37
  existing?.remove();
37
38
  return Promise.resolve();
38
39
  }
39
- const resolved = new URL(href, document.baseURI).href;
40
- if (existing && existing.href === resolved && existing.sheet) {
40
+ if (css) {
41
+ if (existing && existing.tagName === "STYLE" && existing.textContent === css) {
42
+ return Promise.resolve();
43
+ }
44
+ existing?.remove();
45
+ const style = document.createElement("style");
46
+ style.id = THEME_STYLE_ID;
47
+ style.textContent = css;
48
+ document.head.appendChild(style);
49
+ return Promise.resolve();
50
+ }
51
+ let resolved;
52
+ try {
53
+ resolved = new URL(stylesheet, document.baseURI).href;
54
+ } catch {
55
+ console.warn("[TiptapEditor] Invalid stylesheet URL:", stylesheet);
56
+ return Promise.resolve();
57
+ }
58
+ if (existing && existing.tagName === "LINK" && existing.href === resolved && existing.sheet) {
41
59
  return Promise.resolve();
42
60
  }
43
61
  existing?.remove();
44
62
  return new Promise((resolve) => {
45
63
  const link = document.createElement("link");
46
- link.id = LINK_ID;
64
+ link.id = THEME_STYLE_ID;
47
65
  link.rel = "stylesheet";
48
- link.href = href;
66
+ link.href = stylesheet;
49
67
  link.onload = () => resolve();
50
68
  link.onerror = () => {
51
- console.warn("[TiptapEditor] Failed to load theme stylesheet:", href);
69
+ console.warn("[TiptapEditor] Failed to load theme stylesheet:", stylesheet);
52
70
  resolve();
53
71
  };
54
72
  document.head.appendChild(link);
@@ -59,20 +77,27 @@ const Initializer = ({ setPlugin }) => {
59
77
  const { get } = admin.useFetchClient();
60
78
  React.useEffect(() => {
61
79
  const fetchTheme = async () => {
62
- let stylesheetHref;
80
+ let themeStyles = {};
63
81
  try {
64
82
  const { data } = await get("/tiptap-editor/theme");
65
83
  if (data && typeof data === "object" && Object.keys(data).length > 0) {
66
84
  setThemeCache(data);
67
- if (typeof data.stylesheet === "string" && data.stylesheet) {
68
- stylesheetHref = data.stylesheet;
85
+ if (typeof data.css === "string" && data.css) {
86
+ themeStyles = { css: data.css };
87
+ } else if (typeof data.stylesheet === "string" && data.stylesheet) {
88
+ themeStyles = { stylesheet: data.stylesheet };
69
89
  }
70
90
  }
71
91
  } catch (error) {
72
92
  console.warn("[TiptapEditor] Failed to fetch theme config:", error);
73
93
  }
74
- await reconcileThemeStylesheet(stylesheetHref);
75
- ref.current(PLUGIN_ID);
94
+ try {
95
+ await reconcileThemeStyles(themeStyles);
96
+ } catch (error) {
97
+ console.warn("[TiptapEditor] Failed to reconcile theme styles:", error);
98
+ } finally {
99
+ ref.current(PLUGIN_ID);
100
+ }
76
101
  };
77
102
  fetchTheme();
78
103
  }, []);
@@ -122,7 +147,7 @@ const richTextField = {
122
147
  },
123
148
  icon: icons.Paragraph,
124
149
  components: {
125
- Input: async () => Promise.resolve().then(() => require("./RichTextInput-DFyaZboE.js")).then((m) => ({ default: m.default }))
150
+ Input: async () => Promise.resolve().then(() => require("./RichTextInput-EtL-yFqV.js")).then((m) => ({ default: m.default }))
126
151
  },
127
152
  options: {
128
153
  advanced: [
@@ -1,3 +1,3 @@
1
1
  "use strict";
2
- const index = require("../_chunks/index-Nmu3V1bE.js");
2
+ const index = require("../_chunks/index-yXpX_VsO.js");
3
3
  module.exports = index.index;
@@ -1,4 +1,4 @@
1
- import { i } from "../_chunks/index-D4RQaRyr.mjs";
1
+ import { i } from "../_chunks/index-sX8SY6P-.mjs";
2
2
  export {
3
3
  i as default
4
4
  };
@@ -85,7 +85,7 @@ const isPlainObject = (value) => {
85
85
  return prototype === Object.prototype || prototype === null;
86
86
  };
87
87
  const FEATURE_KEYS = new Set(PRESET_FEATURE_KEYS);
88
- const THEME_KEYS = /* @__PURE__ */ new Set(["colors", "stylesheet"]);
88
+ const THEME_KEYS = /* @__PURE__ */ new Set(["colors", "css", "stylesheet"]);
89
89
  const COLOR_VALUE_RE = /^(#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})|rgba?\([^)]+\)|hsla?\([^)]+\)|var\(--[^)]+\))$/;
90
90
  const isValidColorValue = (value) => COLOR_VALUE_RE.test(value.trim());
91
91
  const getInvalidKeys = (presetConfig) => {
@@ -139,10 +139,16 @@ const config = {
139
139
  );
140
140
  }
141
141
  }
142
- const { stylesheet, colors } = theme;
142
+ const { stylesheet, css, colors } = theme;
143
143
  if (stylesheet !== void 0 && typeof stylesheet !== "string") {
144
144
  throw new Error("tiptap-editor config.theme.stylesheet must be a string");
145
145
  }
146
+ if (css !== void 0 && typeof css !== "string") {
147
+ throw new Error("tiptap-editor config.theme.css must be a string");
148
+ }
149
+ if (stylesheet !== void 0 && css !== void 0) {
150
+ throw new Error('tiptap-editor config.theme: provide either "stylesheet" or "css", not both');
151
+ }
146
152
  if (colors !== void 0) {
147
153
  if (!Array.isArray(colors)) {
148
154
  throw new Error("tiptap-editor config.theme.colors must be an array");
@@ -83,7 +83,7 @@ const isPlainObject = (value) => {
83
83
  return prototype === Object.prototype || prototype === null;
84
84
  };
85
85
  const FEATURE_KEYS = new Set(PRESET_FEATURE_KEYS);
86
- const THEME_KEYS = /* @__PURE__ */ new Set(["colors", "stylesheet"]);
86
+ const THEME_KEYS = /* @__PURE__ */ new Set(["colors", "css", "stylesheet"]);
87
87
  const COLOR_VALUE_RE = /^(#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})|rgba?\([^)]+\)|hsla?\([^)]+\)|var\(--[^)]+\))$/;
88
88
  const isValidColorValue = (value) => COLOR_VALUE_RE.test(value.trim());
89
89
  const getInvalidKeys = (presetConfig) => {
@@ -137,10 +137,16 @@ const config = {
137
137
  );
138
138
  }
139
139
  }
140
- const { stylesheet, colors } = theme;
140
+ const { stylesheet, css, colors } = theme;
141
141
  if (stylesheet !== void 0 && typeof stylesheet !== "string") {
142
142
  throw new Error("tiptap-editor config.theme.stylesheet must be a string");
143
143
  }
144
+ if (css !== void 0 && typeof css !== "string") {
145
+ throw new Error("tiptap-editor config.theme.css must be a string");
146
+ }
147
+ if (stylesheet !== void 0 && css !== void 0) {
148
+ throw new Error('tiptap-editor config.theme: provide either "stylesheet" or "css", not both');
149
+ }
144
150
  if (colors !== void 0) {
145
151
  if (!Array.isArray(colors)) {
146
152
  throw new Error("tiptap-editor config.theme.colors must be an array");
@@ -17,10 +17,18 @@ export type ThemeColorEntry = {
17
17
  label: string;
18
18
  color: string;
19
19
  };
20
- export type TiptapThemeConfig = {
21
- colors?: ThemeColorEntry[];
20
+ type ThemeStyleSource = {
21
+ /** A browser-fetchable URL for an external stylesheet */
22
22
  stylesheet?: string;
23
+ css?: never;
24
+ } | {
25
+ stylesheet?: never;
26
+ /** Inline CSS content to inject via a <style> tag */
27
+ css?: string;
23
28
  };
29
+ export type TiptapThemeConfig = {
30
+ colors?: ThemeColorEntry[];
31
+ } & ThemeStyleSource;
24
32
  export interface TiptapPresetConfig {
25
33
  bold?: boolean | Record<string, unknown>;
26
34
  italic?: boolean | Record<string, unknown>;
@@ -64,3 +72,4 @@ export declare const isFeatureEnabled: (value: TiptapPresetConfig[keyof TiptapPr
64
72
  * NOTE: false returns null — DIVERGES from dist where false returns defaults.
65
73
  */
66
74
  export declare const getFeatureOptions: <T extends Record<string, unknown>>(value: boolean | T | undefined, defaults: T) => T | null;
75
+ export {};
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.3-rc.5",
2
+ "version": "1.1.0",
3
3
  "keywords": [
4
4
  "strapi",
5
5
  "plugin",