tetrons 2.3.100 → 2.4.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.
@@ -1,3 +1,3 @@
1
- import { TetronsEditorProps } from "./types/TetronsEditorProps";
1
+ import { EditorRuntimeProps } from "./types/TetronsEditorProps";
2
2
  import "katex/dist/katex.min.css";
3
- export default function Editor(props: TetronsEditorProps): import("react/jsx-runtime").JSX.Element | null;
3
+ export default function Editor(props: EditorRuntimeProps): import("react/jsx-runtime").JSX.Element | null;
@@ -1,8 +1,14 @@
1
+ import type { TetronsConfig } from "./types/TetronsEditorProps";
1
2
  import type { ValidationResponse } from "./types/ValidationResponse";
2
3
  interface TetronsEditorProps {
3
4
  apiKey: string;
5
+ config?: TetronsConfig;
4
6
  onError?: (msg: string) => void;
5
7
  onSuccess?: (details: ValidationResponse) => void;
8
+ onChange?: (payload: {
9
+ html: string;
10
+ json: unknown;
11
+ }) => void;
6
12
  }
7
- export default function TetronsEditor({ apiKey, onError, onSuccess, }: TetronsEditorProps): import("react/jsx-runtime").JSX.Element | null;
13
+ export default function TetronsEditor({ apiKey, config, onError, onSuccess, onChange, }: TetronsEditorProps): import("react/jsx-runtime").JSX.Element | null;
8
14
  export {};
@@ -61,6 +61,36 @@ export interface PlatinumOnlyFeatureFlags {
61
61
  export type ProFeatureFlags = FreeFeatureFlags;
62
62
  export type PremiumFeatureFlags = FreeFeatureFlags & PremiumOnlyFeatureFlags;
63
63
  export type PlatinumFeatureFlags = FreeFeatureFlags & PremiumOnlyFeatureFlags & PlatinumOnlyFeatureFlags;
64
+ export interface TetronsConfig {
65
+ version?: ProductVersion;
66
+ features?: FeatureFlags;
67
+ addOns?: PremiumOnlyFeatureFlags & PlatinumOnlyFeatureFlags;
68
+ autoSave?: boolean;
69
+ showVersions?: boolean;
70
+ ui?: {
71
+ topMenu?: boolean;
72
+ paragraphDropdown?: boolean;
73
+ fontDropdown?: boolean;
74
+ fontSizeDropdown?: boolean;
75
+ };
76
+ }
77
+ export interface EditorRuntimeProps {
78
+ version: ProductVersion;
79
+ apiKey: string;
80
+ features?: FeatureFlags;
81
+ addOns?: PremiumOnlyFeatureFlags & PlatinumOnlyFeatureFlags;
82
+ platinumAddOns?: PlatinumOnlyFeatureFlags;
83
+ autoSave?: boolean;
84
+ showVersions?: boolean;
85
+ topMenu?: boolean;
86
+ showParagraphDropdown?: boolean;
87
+ showFontDropdown?: boolean;
88
+ showFontSizeDropdown?: boolean;
89
+ onChange?: (payload: {
90
+ html: string;
91
+ json: unknown;
92
+ }) => void;
93
+ }
64
94
  interface BaseProps {
65
95
  apiKey: string;
66
96
  topMenu?: boolean;
package/dist/index.css CHANGED
@@ -4886,3 +4886,69 @@ textarea#email-body {
4886
4886
  z-index: 9999999999 !important;
4887
4887
  position: relative;
4888
4888
  }
4889
+ .ProseMirror table {
4890
+ border-collapse: collapse;
4891
+ table-layout: fixed;
4892
+ width: 100%;
4893
+ max-width: 100%;
4894
+ margin: 0.75em 0;
4895
+ background: #fff;
4896
+ }
4897
+ .ProseMirror th,
4898
+ .ProseMirror td {
4899
+ border: 1px solid #d0d0d0;
4900
+ padding: 6px 8px;
4901
+ vertical-align: top;
4902
+ word-break: break-word;
4903
+ overflow-wrap: anywhere;
4904
+ }
4905
+ .ProseMirror th {
4906
+ background-color: #f5f5f5;
4907
+ font-weight: 600;
4908
+ text-align: left;
4909
+ }
4910
+ .ProseMirror .selectedCell {
4911
+ background: rgba(200, 200, 255, 0.4);
4912
+ }
4913
+ .ProseMirror table p {
4914
+ margin: 0;
4915
+ }
4916
+ .ProseMirror {
4917
+ overflow-x: auto;
4918
+ }
4919
+ @media (max-width: 768px) {
4920
+ .ProseMirror table {
4921
+ display: block;
4922
+ width: max-content;
4923
+ max-width: 100%;
4924
+ }
4925
+ .ProseMirror th,
4926
+ .ProseMirror td {
4927
+ min-width: 120px;
4928
+ }
4929
+ }
4930
+ @media (max-width: 480px) {
4931
+ .ProseMirror th,
4932
+ .ProseMirror td {
4933
+ min-width: 100px;
4934
+ padding: 6px;
4935
+ font-size: 13px;
4936
+ }
4937
+ }
4938
+ .ProseMirror .column-resize-handle {
4939
+ position: absolute;
4940
+ right: -2px;
4941
+ top: 0;
4942
+ bottom: 0;
4943
+ width: 4px;
4944
+ background-color: rgba(0, 0, 0, 0.15);
4945
+ pointer-events: none;
4946
+ }
4947
+ .ProseMirror th:hover .column-resize-handle,
4948
+ .ProseMirror td:hover .column-resize-handle {
4949
+ pointer-events: auto;
4950
+ }
4951
+ .ProseMirror table:focus-within {
4952
+ outline: 2px solid rgba(100, 150, 255, 0.35);
4953
+ outline-offset: 2px;
4954
+ }
package/dist/index.mjs CHANGED
@@ -10940,85 +10940,6 @@ function InsertGroup({
10940
10940
  };
10941
10941
  const handleTableInsert = (rows, cols) => {
10942
10942
  editor.chain().focus().insertTable({ rows, cols, withHeaderRow: true }).run();
10943
- setTimeout(() => {
10944
- var _a, _b;
10945
- const table = editor.view.dom.querySelector("table");
10946
- if (table && !((_a = table.parentElement) == null ? void 0 : _a.classList.contains("resizable-table-wrapper"))) {
10947
- const wrapper = document.createElement("div");
10948
- wrapper.className = "resizable-table-wrapper";
10949
- wrapper.style.position = "relative";
10950
- wrapper.style.display = "inline-block";
10951
- wrapper.style.width = "600px";
10952
- wrapper.style.maxWidth = "100%";
10953
- (_b = table.parentNode) == null ? void 0 : _b.insertBefore(wrapper, table);
10954
- wrapper.appendChild(table);
10955
- const resizeHandle = document.createElement("div");
10956
- resizeHandle.className = "resize-handle";
10957
- resizeHandle.style.position = "absolute";
10958
- resizeHandle.style.right = "0";
10959
- resizeHandle.style.bottom = "0";
10960
- resizeHandle.style.width = "12px";
10961
- resizeHandle.style.height = "12px";
10962
- resizeHandle.style.cursor = "se-resize";
10963
- resizeHandle.style.background = "transparent";
10964
- wrapper.appendChild(resizeHandle);
10965
- const dragHandle = document.createElement("div");
10966
- dragHandle.className = "drag-handle";
10967
- dragHandle.style.position = "absolute";
10968
- dragHandle.style.left = "0";
10969
- dragHandle.style.top = "0";
10970
- dragHandle.style.width = "16px";
10971
- dragHandle.style.height = "16px";
10972
- dragHandle.style.cursor = "move";
10973
- dragHandle.style.background = "transparent";
10974
- dragHandle.style.display = "flex";
10975
- dragHandle.style.justifyContent = "center";
10976
- dragHandle.style.alignItems = "center";
10977
- dragHandle.innerHTML = "\u2630";
10978
- dragHandle.style.color = "#fff";
10979
- dragHandle.style.fontSize = "12px";
10980
- wrapper.appendChild(dragHandle);
10981
- let startWidth = 0;
10982
- let startHeight = 0;
10983
- let startX = 0;
10984
- let startY = 0;
10985
- resizeHandle.addEventListener("mousedown", (e) => {
10986
- e.preventDefault();
10987
- startX = e.clientX;
10988
- startY = e.clientY;
10989
- startWidth = wrapper.offsetWidth;
10990
- startHeight = wrapper.offsetHeight;
10991
- const onMouseMove = (e2) => {
10992
- const dx = e2.clientX - startX;
10993
- const dy = e2.clientY - startY;
10994
- wrapper.style.width = Math.max(100, startWidth + dx) + "px";
10995
- wrapper.style.height = Math.max(50, startHeight + dy) + "px";
10996
- };
10997
- const onMouseUp = () => {
10998
- document.removeEventListener("mousemove", onMouseMove);
10999
- document.removeEventListener("mouseup", onMouseUp);
11000
- };
11001
- document.addEventListener("mousemove", onMouseMove);
11002
- document.addEventListener("mouseup", onMouseUp);
11003
- });
11004
- dragHandle.addEventListener("mousedown", (e) => {
11005
- e.preventDefault();
11006
- startX = e.clientX;
11007
- startY = e.clientY;
11008
- const onMouseMove = (e2) => {
11009
- const dx = e2.clientX - startX;
11010
- const dy = e2.clientY - startY;
11011
- wrapper.style.transform = `translate(${dx}px, ${dy}px)`;
11012
- };
11013
- const onMouseUp = () => {
11014
- document.removeEventListener("mousemove", onMouseMove);
11015
- document.removeEventListener("mouseup", onMouseUp);
11016
- };
11017
- document.addEventListener("mousemove", onMouseMove);
11018
- document.addEventListener("mouseup", onMouseUp);
11019
- });
11020
- }
11021
- }, 0);
11022
10943
  setShowTableGrid(false);
11023
10944
  setSelectedRows(1);
11024
10945
  setSelectedCols(1);
@@ -12142,6 +12063,7 @@ var SpellCheck = Extension.create({
12142
12063
  let spell = null;
12143
12064
  let activePopup = null;
12144
12065
  let lastHoveredWord = null;
12066
+ const key = new PluginKey("spellcheck");
12145
12067
  function closePopup() {
12146
12068
  if (activePopup) {
12147
12069
  activePopup.remove();
@@ -12150,25 +12072,22 @@ var SpellCheck = Extension.create({
12150
12072
  }
12151
12073
  return [
12152
12074
  new Plugin({
12153
- key: new PluginKey("spellcheck"),
12154
- view: (editorView) => {
12155
- fetch("https://tetrons.com/api/dictionary").then((r) => r.json()).then((dict) => spell = nspell(dict)).catch(
12156
- (e) => console.error("Spellcheck dictionary load failed:", e)
12157
- );
12158
- const handleMouseMove2 = (event) => {
12159
- if (!spell) return;
12160
- if (activePopup) {
12161
- const rect = activePopup.getBoundingClientRect();
12162
- if (event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom) {
12163
- return;
12164
- }
12075
+ key,
12076
+ view(view) {
12077
+ let destroyed = false;
12078
+ fetch("https://tetrons.com/api/dictionary").then((r) => r.json()).then((dict) => {
12079
+ if (!destroyed) {
12080
+ spell = nspell(dict);
12165
12081
  }
12166
- const pos = editorView.posAtCoords({
12167
- left: event.clientX,
12168
- top: event.clientY
12082
+ }).catch(console.error);
12083
+ const onMouseMove = (e) => {
12084
+ if (!spell) return;
12085
+ const coords = view.posAtCoords({
12086
+ left: e.clientX,
12087
+ top: e.clientY
12169
12088
  });
12170
- if (!pos) return;
12171
- const word = getWordAtPosition(editorView, pos.pos);
12089
+ if (!coords) return;
12090
+ const word = getWordAtPosition(view, coords.pos);
12172
12091
  if (!word) return;
12173
12092
  if (!spell.correct(word.text)) {
12174
12093
  if (lastHoveredWord && lastHoveredWord.start === word.start && lastHoveredWord.end === word.end) {
@@ -12176,57 +12095,54 @@ var SpellCheck = Extension.create({
12176
12095
  }
12177
12096
  lastHoveredWord = word;
12178
12097
  closePopup();
12179
- const suggestions = spell.suggest(word.text);
12180
12098
  activePopup = showSuggestionsPopup(
12181
- editorView,
12182
- pos.pos,
12099
+ view,
12100
+ coords.pos,
12183
12101
  word,
12184
- suggestions,
12102
+ spell.suggest(word.text),
12185
12103
  closePopup
12186
12104
  );
12187
- }
12188
- };
12189
- const handleOutsideClick = (event) => {
12190
- if (activePopup && !activePopup.contains(event.target)) {
12105
+ } else {
12191
12106
  closePopup();
12192
12107
  }
12193
12108
  };
12194
- document.addEventListener("mousemove", handleMouseMove2);
12195
- document.addEventListener("mousedown", handleOutsideClick);
12109
+ document.addEventListener("mousemove", onMouseMove);
12110
+ document.addEventListener("mousedown", closePopup);
12196
12111
  return {
12197
12112
  destroy() {
12198
- document.removeEventListener("mousemove", handleMouseMove2);
12199
- document.removeEventListener("mousedown", handleOutsideClick);
12113
+ destroyed = true;
12114
+ closePopup();
12115
+ document.removeEventListener("mousemove", onMouseMove);
12116
+ document.removeEventListener("mousedown", closePopup);
12200
12117
  }
12201
12118
  };
12202
12119
  },
12203
- state: {
12204
- init() {
12205
- return DecorationSet.empty;
12206
- },
12207
- apply(tr, old) {
12208
- if (!spell) return old;
12209
- const text = tr.doc.textBetween(0, tr.doc.content.size, " ");
12210
- const words = text.split(/\s+/);
12211
- const decorations = [];
12212
- let pos = 0;
12213
- for (const word of words) {
12214
- const clean = word.replace(/[.,!?;:()"\']/g, "");
12215
- if (clean.length > 0 && !spell.correct(clean)) {
12216
- decorations.push(
12217
- Decoration.inline(pos, pos + word.length, {
12218
- class: "spell-wrong"
12219
- })
12220
- );
12221
- }
12222
- pos += word.length + 1;
12223
- }
12224
- return DecorationSet.create(tr.doc, decorations);
12225
- }
12226
- },
12227
12120
  props: {
12228
12121
  decorations(state) {
12229
- return this.getState(state);
12122
+ const sp = spell;
12123
+ if (!sp) return DecorationSet.empty;
12124
+ const decorations = [];
12125
+ state.doc.descendants((node, pos) => {
12126
+ if (!node.isText || !node.text) return;
12127
+ const text = node.text;
12128
+ const wordRegex = /\b[^\s.,!?;:()"'`]+\b/g;
12129
+ let match;
12130
+ while (match = wordRegex.exec(text)) {
12131
+ const word = match[0];
12132
+ const from = pos + match.index;
12133
+ const to = from + word.length;
12134
+ if (from < 0) continue;
12135
+ if (to > state.doc.content.size) continue;
12136
+ if (!sp.correct(word)) {
12137
+ decorations.push(
12138
+ Decoration.inline(from, to, {
12139
+ class: "spell-wrong"
12140
+ })
12141
+ );
12142
+ }
12143
+ }
12144
+ });
12145
+ return DecorationSet.create(state.doc, decorations);
12230
12146
  }
12231
12147
  }
12232
12148
  })
@@ -12235,41 +12151,39 @@ var SpellCheck = Extension.create({
12235
12151
  });
12236
12152
  function getWordAtPosition(view, pos) {
12237
12153
  const $pos = view.state.doc.resolve(pos);
12238
- const parent = $pos.parent;
12239
- const offset = $pos.parentOffset;
12240
- const text = parent.textContent;
12241
- let start = offset;
12242
- let end = offset;
12243
- while (start > 0 && !/\s/.test(text[start - 1])) {
12244
- start--;
12245
- }
12246
- while (end < text.length && !/\s/.test(text[end])) {
12247
- end++;
12248
- }
12154
+ if (!$pos.parent.isTextblock) return null;
12155
+ const text = $pos.parent.textContent;
12156
+ let start = $pos.parentOffset;
12157
+ let end = start;
12158
+ while (start > 0 && !/\s/.test(text[start - 1])) start--;
12159
+ while (end < text.length && !/\s/.test(text[end])) end++;
12249
12160
  const word = text.slice(start, end);
12250
12161
  if (!word.trim()) return null;
12251
- const absStart = $pos.start() + start;
12252
- const absEnd = $pos.start() + end;
12253
- return { text: word, start: absStart, end: absEnd };
12162
+ return {
12163
+ text: word,
12164
+ start: $pos.start() + start,
12165
+ end: $pos.start() + end
12166
+ };
12254
12167
  }
12255
- function showSuggestionsPopup(view, pos, word, suggestions, closePopup) {
12256
- const dom = document.createElement("div");
12257
- dom.className = "spell-suggestions-popup";
12168
+ function showSuggestionsPopup(view, pos, word, suggestions, close2) {
12169
+ const el = document.createElement("div");
12170
+ el.className = "spell-suggestions-popup";
12171
+ el.style.position = "absolute";
12258
12172
  suggestions.forEach((s) => {
12259
12173
  const item = document.createElement("div");
12260
12174
  item.className = "suggestion-item";
12261
12175
  item.textContent = s;
12262
12176
  item.onclick = () => {
12263
12177
  view.dispatch(view.state.tr.insertText(s, word.start, word.end));
12264
- closePopup();
12178
+ close2();
12265
12179
  };
12266
- dom.appendChild(item);
12180
+ el.appendChild(item);
12267
12181
  });
12268
- document.body.appendChild(dom);
12182
+ document.body.appendChild(el);
12269
12183
  const coords = view.coordsAtPos(pos);
12270
- dom.style.left = coords.left + "px";
12271
- dom.style.top = coords.bottom + "px";
12272
- return dom;
12184
+ el.style.left = `${coords.left}px`;
12185
+ el.style.top = `${coords.bottom}px`;
12186
+ return el;
12273
12187
  }
12274
12188
  function AIModal({
12275
12189
  open,
@@ -16588,9 +16502,8 @@ function Editor2(props) {
16588
16502
  }, [versions]);
16589
16503
  useEffect(() => {
16590
16504
  if (!editor) return;
16591
- const current = editor.getHTML();
16592
- editor.commands.setContent(current);
16593
- }, [editor, spellCheckEnabled]);
16505
+ editor.view.dispatch(editor.state.tr);
16506
+ }, [spellCheckEnabled]);
16594
16507
  const showThirdRow = props.showParagraphDropdown || props.showFontDropdown || props.showFontSizeDropdown;
16595
16508
  const handleAISubmit = async (prompt) => {
16596
16509
  try {
@@ -16820,16 +16733,6 @@ function Editor2(props) {
16820
16733
  if (!editor || !editorRight) return;
16821
16734
  editorRight.commands.setContent(editor.getJSON());
16822
16735
  }, [editor, editorRight]);
16823
- useEffect(() => {
16824
- if (!editor || !editorRight) return;
16825
- const handler = () => {
16826
- editorRight.commands.setContent(editor.getJSON());
16827
- };
16828
- editor.on("update", handler);
16829
- return () => {
16830
- editor.off("update", handler);
16831
- };
16832
- }, [editor, editorRight]);
16833
16736
  function dispatchTetronsEvent2(name, detail) {
16834
16737
  if (typeof window !== "undefined") {
16835
16738
  window.dispatchEvent(new CustomEvent(name, { detail }));
@@ -16979,6 +16882,20 @@ function Editor2(props) {
16979
16882
  onHelpOpen
16980
16883
  );
16981
16884
  }, []);
16885
+ useEffect(() => {
16886
+ if (!editor || !props.onChange) return;
16887
+ const handler = () => {
16888
+ var _a2;
16889
+ (_a2 = props.onChange) == null ? void 0 : _a2.call(props, {
16890
+ html: editor.getHTML(),
16891
+ json: editor.getJSON()
16892
+ });
16893
+ };
16894
+ editor.on("update", handler);
16895
+ return () => {
16896
+ editor.off("update", handler);
16897
+ };
16898
+ }, [editor, props.onChange]);
16982
16899
  if (!editor) return null;
16983
16900
  return /* @__PURE__ */ jsxs("div", { className: "tetrons-editor__container", children: [
16984
16901
  props.topMenu && /* @__PURE__ */ jsx(
@@ -17320,9 +17237,12 @@ Output: ${output}
17320
17237
  }
17321
17238
  function TetronsEditor({
17322
17239
  apiKey,
17240
+ config,
17323
17241
  onError,
17324
- onSuccess
17242
+ onSuccess,
17243
+ onChange
17325
17244
  }) {
17245
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
17326
17246
  const [loading, setLoading] = useState(true);
17327
17247
  const [error, setError] = useState(null);
17328
17248
  const [details, setDetails] = useState(null);
@@ -17335,31 +17255,25 @@ function TetronsEditor({
17335
17255
  body: JSON.stringify({ apiKey })
17336
17256
  });
17337
17257
  if (!res.ok) {
17338
- const errData = await res.text();
17339
- console.error("Server response:", errData);
17340
- setError("Invalid or expired API key.");
17341
- if (onError) onError("Invalid or expired API key.");
17342
- setLoading(false);
17343
- return;
17258
+ throw new Error("Invalid or expired API key.");
17344
17259
  }
17345
17260
  const data = await res.json();
17346
17261
  setDetails(data);
17347
- if (onSuccess) onSuccess(data);
17262
+ onSuccess == null ? void 0 : onSuccess(data);
17348
17263
  } catch (err) {
17349
- console.error("Fetch error:", err);
17350
17264
  const msg = err instanceof Error ? err.message : "Failed to validate API key.";
17351
17265
  setError(msg);
17352
- if (onError) onError(msg);
17266
+ onError == null ? void 0 : onError(msg);
17353
17267
  } finally {
17354
17268
  setLoading(false);
17355
17269
  }
17356
17270
  }
17357
17271
  validateApiKey();
17358
- }, [apiKey]);
17272
+ }, [apiKey, onError, onSuccess]);
17359
17273
  if (loading) return /* @__PURE__ */ jsx("p", { children: "Validating API key..." });
17360
17274
  if (error) return /* @__PURE__ */ jsx("p", { className: "error-message", children: error });
17361
17275
  if (!details) return null;
17362
- const normalizedVersion = details.version.charAt(0).toUpperCase() + details.version.slice(1).toLowerCase();
17276
+ const backendVersion = details.version.charAt(0).toUpperCase() + details.version.slice(1).toLowerCase();
17363
17277
  const freeFeatures = {
17364
17278
  newFile: true,
17365
17279
  openFile: true,
@@ -17367,157 +17281,57 @@ function TetronsEditor({
17367
17281
  cut: true,
17368
17282
  copy: true,
17369
17283
  paste: true,
17370
- formatPainter: true,
17371
17284
  undo: true,
17372
17285
  redo: true,
17373
17286
  bold: true,
17374
17287
  italic: true,
17375
17288
  underline: true,
17376
- strikeout: true,
17377
- subscript: true,
17378
- superscript: true,
17379
- fontColor: true,
17380
- highlightColor: true,
17381
- clearFormatting: true,
17382
17289
  bulletedList: true,
17383
- numberedList: true,
17384
- lineHeight: true,
17385
- lineSpacing: true,
17386
- indentIncrease: true,
17387
- indentDecrease: true,
17388
- alignLeft: true,
17389
- alignCenter: true,
17390
- alignRight: true,
17391
- alignJustify: true
17290
+ numberedList: true
17392
17291
  };
17393
- const allPremiumFeatures = {
17292
+ const premiumFeatures = {
17394
17293
  insertTable: true,
17395
17294
  insertImage: true,
17396
17295
  insertVideo: true,
17397
17296
  insertAudio: true,
17398
- insertCheckboxList: true,
17399
17297
  insertLink: true,
17400
- insertComments: true,
17401
- insertEmoji: true,
17402
- insertHorizontalRule: true,
17403
- insertEmbedVideo: true,
17404
- zoomIn: true,
17405
- zoomOut: true,
17406
17298
  print: true,
17407
17299
  exportFile: true
17408
17300
  };
17409
- const allPlatinumFeatures = {
17410
- resetFormatting: true,
17411
- preview: true,
17412
- codeBlock: true,
17413
- spellCheck: true,
17414
- voice: true,
17301
+ const platinumFeatures = {
17415
17302
  ai: true,
17416
- languageConverter: true,
17417
- codeEditor: true,
17303
+ voice: true,
17304
+ spellCheck: true,
17418
17305
  mathEquation: true,
17419
- virtualKeyboard: true,
17420
- getContentFromImage: true
17306
+ codeEditor: true
17421
17307
  };
17422
- const premiumAddOnKeys = [
17423
- "insertTable",
17424
- "insertImage",
17425
- "insertVideo",
17426
- "insertAudio",
17427
- "insertCheckboxList",
17428
- "insertLink",
17429
- "insertComments",
17430
- "insertEmoji",
17431
- "insertHorizontalRule",
17432
- "insertEmbedVideo",
17433
- "zoomIn",
17434
- "zoomOut",
17435
- "print",
17436
- "exportFile"
17437
- ];
17438
- const platinumAddOnKeys = [
17439
- "resetFormatting",
17440
- "preview",
17441
- "codeBlock",
17442
- "spellCheck",
17443
- "voice",
17444
- "ai",
17445
- "languageConverter",
17446
- "codeEditor",
17447
- "mathEquation",
17448
- "virtualKeyboard"
17449
- ];
17450
- const activePremiumAddOns = {};
17451
- const activePlatinumAddOns = {};
17452
- const isPremiumAddOn = (add) => premiumAddOnKeys.includes(add);
17453
- const isPlatinumAddOn = (add) => platinumAddOnKeys.includes(add);
17454
- details.addOn.forEach((add) => {
17455
- if (isPremiumAddOn(add)) activePremiumAddOns[add] = true;
17456
- if (isPlatinumAddOn(add)) activePlatinumAddOns[add] = true;
17457
- });
17458
- switch (normalizedVersion) {
17459
- case "Free":
17460
- return /* @__PURE__ */ jsx(
17461
- Editor2,
17462
- {
17463
- version: "Free",
17464
- apiKey,
17465
- topMenu: true,
17466
- showParagraphDropdown: true,
17467
- showFontDropdown: true,
17468
- showFontSizeDropdown: true,
17469
- features: freeFeatures
17470
- }
17471
- );
17472
- case "Pro":
17473
- return /* @__PURE__ */ jsx(
17474
- Editor2,
17475
- {
17476
- version: "Pro",
17477
- apiKey,
17478
- topMenu: true,
17479
- showParagraphDropdown: true,
17480
- showFontDropdown: true,
17481
- showFontSizeDropdown: true,
17482
- autoSave: true,
17483
- showVersions: true,
17484
- features: freeFeatures,
17485
- addOns: __spreadValues(__spreadValues({}, activePremiumAddOns), activePlatinumAddOns)
17486
- }
17487
- );
17488
- case "Premium":
17489
- return /* @__PURE__ */ jsx(
17490
- Editor2,
17491
- {
17492
- version: "Premium",
17493
- apiKey,
17494
- topMenu: true,
17495
- showParagraphDropdown: true,
17496
- showFontDropdown: true,
17497
- showFontSizeDropdown: true,
17498
- autoSave: true,
17499
- showVersions: true,
17500
- features: __spreadValues(__spreadValues({}, freeFeatures), allPremiumFeatures),
17501
- platinumAddOns: activePlatinumAddOns
17502
- }
17503
- );
17504
- case "Platinum":
17505
- return /* @__PURE__ */ jsx(
17506
- Editor2,
17507
- {
17508
- version: "Platinum",
17509
- apiKey,
17510
- topMenu: true,
17511
- showParagraphDropdown: true,
17512
- showFontDropdown: true,
17513
- showFontSizeDropdown: true,
17514
- autoSave: true,
17515
- showVersions: true,
17516
- features: __spreadValues(__spreadValues(__spreadValues({}, freeFeatures), allPremiumFeatures), allPlatinumFeatures),
17517
- platinumAddOns: activePlatinumAddOns
17518
- }
17519
- );
17308
+ let entitledFeatures = __spreadValues({}, freeFeatures);
17309
+ if (backendVersion === "Premium" || backendVersion === "Platinum") {
17310
+ entitledFeatures = __spreadValues(__spreadValues({}, entitledFeatures), premiumFeatures);
17520
17311
  }
17312
+ if (backendVersion === "Platinum") {
17313
+ entitledFeatures = __spreadValues(__spreadValues({}, entitledFeatures), platinumFeatures);
17314
+ }
17315
+ const effectiveVersion = (_a = config == null ? void 0 : config.version) != null ? _a : backendVersion;
17316
+ const effectiveFeatures = (_b = config == null ? void 0 : config.features) != null ? _b : entitledFeatures;
17317
+ const effectiveAddOns = config == null ? void 0 : config.addOns;
17318
+ return /* @__PURE__ */ jsx(
17319
+ Editor2,
17320
+ {
17321
+ version: effectiveVersion,
17322
+ apiKey,
17323
+ features: effectiveFeatures,
17324
+ addOns: effectiveAddOns,
17325
+ platinumAddOns: effectiveAddOns,
17326
+ autoSave: config == null ? void 0 : config.autoSave,
17327
+ showVersions: config == null ? void 0 : config.showVersions,
17328
+ topMenu: (_d = (_c = config == null ? void 0 : config.ui) == null ? void 0 : _c.topMenu) != null ? _d : true,
17329
+ showParagraphDropdown: (_f = (_e = config == null ? void 0 : config.ui) == null ? void 0 : _e.paragraphDropdown) != null ? _f : true,
17330
+ showFontDropdown: (_h = (_g = config == null ? void 0 : config.ui) == null ? void 0 : _g.fontDropdown) != null ? _h : true,
17331
+ showFontSizeDropdown: (_j = (_i = config == null ? void 0 : config.ui) == null ? void 0 : _i.fontSizeDropdown) != null ? _j : true,
17332
+ onChange
17333
+ }
17334
+ );
17521
17335
  }
17522
17336
 
17523
17337
  // src/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tetrons",
3
- "version": "2.3.100",
3
+ "version": "2.4.1",
4
4
  "description": "Tetrons is a fully-featured, modern WYSIWYG rich text editor built on TipTap.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.mjs",
@@ -68,7 +68,7 @@
68
68
  "nspell": "^2.1.5",
69
69
  "re-resizable": "^6.11.2",
70
70
  "react-icons": "^5.5.0",
71
- "tesseract.js": "^6.0.1"
71
+ "tesseract.js": "^7.0.0"
72
72
  },
73
73
  "peerDependencies": {
74
74
  "react": ">=18",
@@ -93,7 +93,7 @@
93
93
  "optionalDependencies": {
94
94
  "mongoose": "^9.0.1",
95
95
  "nodemailer": "^7.0.11",
96
- "openai": "^6.10.0"
96
+ "openai": "^6.13.0"
97
97
  },
98
98
  "exports": {
99
99
  ".": {