cms-block-editor 1.0.7 → 1.0.9

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 [Your Name]
3
+ Copyright (c) 2024 Samuel Clinton
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -71,6 +71,8 @@ Main editor component with full editing capabilities.
71
71
  **Props:**
72
72
  - `value?: string` - Initial editor state (JSON string)
73
73
  - `onChange?: (state: any) => void` - Callback fired when content changes
74
+ - `onImageAdded?: (file: File) => Promise<string>` - Custom image upload handler that returns the image URL
75
+ - `useBase64Url?: boolean` - Use base64 encoding for images (default: `true`)
74
76
 
75
77
  ### CMSRenderer
76
78
 
@@ -92,7 +94,7 @@ Read-only renderer for displaying saved content.
92
94
  - Code blocks
93
95
 
94
96
  ### Media
95
- - **Images**: Upload from computer, resize with 8-point handles, drag-and-drop positioning
97
+ - **Images**: Upload from computer, resize with 8-point handles, drag-and-drop positioning, custom upload handler support
96
98
  - **YouTube**: Embed videos with custom sizing
97
99
  - **Embeds**: Support for 8+ platforms with automatic URL detection
98
100
  - **Tables**: Visual builder with configurable dimensions, header rows, and professional styling
@@ -130,6 +132,47 @@ Read-only renderer for displaying saved content.
130
132
 
131
133
  ## Advanced Usage
132
134
 
135
+ ### Custom Image Upload
136
+
137
+ Upload images to your server instead of using base64 encoding:
138
+
139
+ ```tsx
140
+ import { CMSBlockEditor } from 'cms-block-editor';
141
+
142
+ function Editor() {
143
+ const [content, setContent] = useState('');
144
+
145
+ const handleImageUpload = async (file: File): Promise<string> => {
146
+ // Upload to your server
147
+ const formData = new FormData();
148
+ formData.append('image', file);
149
+
150
+ const response = await fetch('/api/upload', {
151
+ method: 'POST',
152
+ body: formData,
153
+ });
154
+
155
+ const data = await response.json();
156
+ return data.url; // Return the uploaded image URL
157
+ };
158
+
159
+ return (
160
+ <CMSBlockEditor
161
+ value={content}
162
+ onChange={(state) => setContent(JSON.stringify(state))}
163
+ onImageAdded={handleImageUpload}
164
+ useBase64Url={false}
165
+ />
166
+ );
167
+ }
168
+ ```
169
+
170
+ **Image Upload Options:**
171
+
172
+ - **With `onImageAdded`**: Provide a custom upload handler that uploads the file to your server and returns the URL
173
+ - **With `useBase64Url={true}`** (default): Images are encoded as base64 strings (no server upload needed)
174
+ - **With `useBase64Url={false}` and no `onImageAdded`**: Image upload will be disabled
175
+
133
176
  ### With Persistence
134
177
 
135
178
  ```tsx
package/dist/index.d.mts CHANGED
@@ -4,8 +4,10 @@ import { LexicalEditor } from 'lexical';
4
4
  interface CMSBlockEditorProps {
5
5
  value?: string;
6
6
  onChange?: (state: any) => void;
7
+ onImageAdded?: (file: File) => Promise<string>;
8
+ useBase64Url?: boolean;
7
9
  }
8
- declare function CMSBlockEditor({ value, onChange }: CMSBlockEditorProps): react_jsx_runtime.JSX.Element;
10
+ declare function CMSBlockEditor({ value, onChange, onImageAdded, useBase64Url }: CMSBlockEditorProps): react_jsx_runtime.JSX.Element;
9
11
 
10
12
  interface CMSRendererProps {
11
13
  content: string;
package/dist/index.mjs CHANGED
@@ -4152,7 +4152,10 @@ function ToolbarPlugin() {
4152
4152
  import { useLexicalComposerContext as useLexicalComposerContext8 } from "@lexical/react/LexicalComposerContext";
4153
4153
  import { useEffect as useEffect9 } from "react";
4154
4154
  import { $getSelection as $getSelection7, $isRangeSelection as $isRangeSelection7, COMMAND_PRIORITY_LOW as COMMAND_PRIORITY_LOW2, DRAGOVER_COMMAND, DROP_COMMAND } from "lexical";
4155
- function ImageUploadPlugin() {
4155
+ function ImageUploadPlugin({
4156
+ onImageAdded,
4157
+ useBase64Url = true
4158
+ }) {
4156
4159
  const [editor] = useLexicalComposerContext8();
4157
4160
  useEffect9(() => {
4158
4161
  const removeDragOverListener = editor.registerCommand(
@@ -4165,25 +4168,41 @@ function ImageUploadPlugin() {
4165
4168
  );
4166
4169
  const removeDropListener = editor.registerCommand(
4167
4170
  DROP_COMMAND,
4168
- (event) => {
4171
+ //@ts-ignore
4172
+ async (event) => {
4169
4173
  event.preventDefault();
4170
4174
  const files = event.dataTransfer?.files;
4171
4175
  if (files && files.length > 0) {
4172
4176
  const file = files[0];
4173
4177
  if (file.type.startsWith("image/")) {
4174
- const reader = new FileReader();
4175
- reader.onload = (e) => {
4176
- const url = e.target?.result;
4177
- const alt = file.name.replace(/\.[^/.]+$/, "");
4178
- editor.update(() => {
4179
- const selection = $getSelection7();
4180
- if ($isRangeSelection7(selection)) {
4181
- const imageNode = new ImageNode(url, alt);
4182
- selection.insertNodes([imageNode]);
4183
- }
4178
+ let url;
4179
+ const alt = file.name.replace(/\.[^/.]+$/, "");
4180
+ if (onImageAdded) {
4181
+ try {
4182
+ url = await onImageAdded(file);
4183
+ } catch (error) {
4184
+ console.error("Error uploading image:", error);
4185
+ return false;
4186
+ }
4187
+ } else if (useBase64Url) {
4188
+ url = await new Promise((resolve) => {
4189
+ const reader = new FileReader();
4190
+ reader.onload = (e) => {
4191
+ resolve(e.target?.result);
4192
+ };
4193
+ reader.readAsDataURL(file);
4184
4194
  });
4185
- };
4186
- reader.readAsDataURL(file);
4195
+ } else {
4196
+ console.warn("No image upload handler provided and useBase64Url is false");
4197
+ return false;
4198
+ }
4199
+ editor.update(() => {
4200
+ const selection = $getSelection7();
4201
+ if ($isRangeSelection7(selection)) {
4202
+ const imageNode = new ImageNode(url, alt);
4203
+ selection.insertNodes([imageNode]);
4204
+ }
4205
+ });
4187
4206
  return true;
4188
4207
  }
4189
4208
  }
@@ -4195,7 +4214,7 @@ function ImageUploadPlugin() {
4195
4214
  removeDragOverListener();
4196
4215
  removeDropListener();
4197
4216
  };
4198
- }, [editor]);
4217
+ }, [editor, onImageAdded, useBase64Url]);
4199
4218
  return null;
4200
4219
  }
4201
4220
 
@@ -5532,7 +5551,11 @@ function EmbedPlugin() {
5532
5551
 
5533
5552
  // src/core/EditorShell.tsx
5534
5553
  import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
5535
- function EditorShell({ onChange }) {
5554
+ function EditorShell({
5555
+ onChange,
5556
+ onImageAdded,
5557
+ useBase64Url
5558
+ }) {
5536
5559
  return /* @__PURE__ */ jsxs14("div", { className: "cms-editor-shell", children: [
5537
5560
  /* @__PURE__ */ jsx14(ToolbarPlugin, {}),
5538
5561
  /* @__PURE__ */ jsx14(
@@ -5548,7 +5571,7 @@ function EditorShell({ onChange }) {
5548
5571
  /* @__PURE__ */ jsx14(LexicalLinkPlugin, {}),
5549
5572
  /* @__PURE__ */ jsx14(LexicalTablePlugin, {}),
5550
5573
  /* @__PURE__ */ jsx14(SlashCommandPlugin, {}),
5551
- /* @__PURE__ */ jsx14(ImageUploadPlugin, {}),
5574
+ /* @__PURE__ */ jsx14(ImageUploadPlugin, { onImageAdded, useBase64Url }),
5552
5575
  /* @__PURE__ */ jsx14(LinkPlugin, {}),
5553
5576
  /* @__PURE__ */ jsx14(SectionEditorPlugin, {}),
5554
5577
  /* @__PURE__ */ jsx14(EmbedPlugin, {}),
@@ -5613,8 +5636,20 @@ function createEditorConfig(value) {
5613
5636
 
5614
5637
  // src/core/CMSBlockEditor.tsx
5615
5638
  import { jsx as jsx15 } from "react/jsx-runtime";
5616
- function CMSBlockEditor({ value, onChange }) {
5617
- return /* @__PURE__ */ jsx15(LexicalComposer, { initialConfig: createEditorConfig(value), children: /* @__PURE__ */ jsx15(EditorShell, { onChange }) });
5639
+ function CMSBlockEditor({
5640
+ value,
5641
+ onChange,
5642
+ onImageAdded,
5643
+ useBase64Url = true
5644
+ }) {
5645
+ return /* @__PURE__ */ jsx15(LexicalComposer, { initialConfig: createEditorConfig(value), children: /* @__PURE__ */ jsx15(
5646
+ EditorShell,
5647
+ {
5648
+ onChange,
5649
+ onImageAdded,
5650
+ useBase64Url
5651
+ }
5652
+ ) });
5618
5653
  }
5619
5654
 
5620
5655
  // src/core/CMSRenderer.tsx