customise-text-editor 1.0.2 → 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.
- package/LICENSE +21 -0
- package/README.md +153 -86
- package/dist/customise-text-editor.es.js +100 -58
- package/dist/customise-text-editor.umd.js +15 -5
- package/dist/index.d.ts +6 -2
- package/package.json +4 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 kanhaiya-dct
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,108 +1,164 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# 💎 Customise-Text-Editor
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/customise-text-editor)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://bundlephobia.com/package/customise-text-editor)
|
|
8
|
+
|
|
9
|
+
**A highly customizable, production-ready Rich Text Editor for React, built on the solid foundation of Tiptap.**
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
## ✨ Features at a Glance
|
|
15
|
+
|
|
16
|
+
| Feature | Description |
|
|
17
|
+
| :--- | :--- |
|
|
18
|
+
| 🎨 **Premium UI** | Modern, sleek design with smooth transitions and glassmorphism support. |
|
|
19
|
+
| 🔢 **Real-time Stats** | Automatic footer with character counting when `maxLength` is enabled. |
|
|
20
|
+
| 📝 **Dual Output** | Seamlessly switch between `HTML` and clean `Plain Text` exports. |
|
|
21
|
+
| 🔗 **Hooks-First** | First-class support for `react-hook-form` via standard `Controller` APIs. |
|
|
22
|
+
| 💅 **Total Control** | Custom width, alignment, margins, and branding-specific themes. |
|
|
23
|
+
| ⚡ **Ultra-Light** | Meticulously optimized bundle (only **~11KB**) with zero bloated dependencies. |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 📦 Installation
|
|
28
|
+
|
|
29
|
+
Get started in seconds:
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
32
|
npm install customise-text-editor
|
|
33
|
-
# or
|
|
34
|
-
yarn add customise-text-editor
|
|
35
33
|
```
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
> [!IMPORTANT]
|
|
36
|
+
> Since this is a library, ensure you import the CSS in your main entry file (e.g., `App.tsx` or `main.tsx`) to enable the premium aesthetics.
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import 'customise-text-editor/style.css';
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 🚀 Quick Start
|
|
45
|
+
|
|
46
|
+
Creating a powerful editor has never been easier:
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
import { CustomEditor } from 'customise-text-editor';
|
|
50
|
+
import 'customise-text-editor/style.css';
|
|
51
|
+
|
|
52
|
+
function App() {
|
|
53
|
+
const handleSave = (content) => {
|
|
54
|
+
console.log('Editor Content:', content);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<div className="container">
|
|
59
|
+
<CustomEditor
|
|
60
|
+
config={{
|
|
61
|
+
width: '800px',
|
|
62
|
+
align: 'center',
|
|
63
|
+
placeholder: 'Start writing your story...',
|
|
64
|
+
maxLength: 1000,
|
|
65
|
+
outputFormat: 'html',
|
|
66
|
+
onChange: handleSave,
|
|
67
|
+
theme: {
|
|
68
|
+
primaryColor: '#6366f1',
|
|
69
|
+
borderRadius: '12px'
|
|
70
|
+
}
|
|
71
|
+
}}
|
|
72
|
+
/>
|
|
73
|
+
</div>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 🏗️ Advanced Integration: React Hook Form
|
|
81
|
+
|
|
82
|
+
We built this editor with form libraries in mind. It integrates perfectly with `Controller` and validation rules.
|
|
38
83
|
|
|
39
84
|
```tsx
|
|
85
|
+
import { useForm, Controller } from 'react-hook-form';
|
|
40
86
|
import { CustomEditor } from 'customise-text-editor';
|
|
41
|
-
import 'customise-text-editor/style.css'; // Don't forget to import styles!
|
|
42
87
|
|
|
43
|
-
|
|
88
|
+
const BlogEditor = () => {
|
|
89
|
+
const { control, handleSubmit, formState: { errors } } = useForm({
|
|
90
|
+
defaultValues: { postContent: '' }
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const onSubmit = (data) => console.log('Payload:', data);
|
|
94
|
+
|
|
44
95
|
return (
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
96
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
97
|
+
<Controller
|
|
98
|
+
name="postContent"
|
|
99
|
+
control={control}
|
|
100
|
+
rules={{
|
|
101
|
+
required: 'Please write something before publishing',
|
|
102
|
+
minLength: { value: 50, message: 'Your post is too short (min 50 chars)' }
|
|
103
|
+
}}
|
|
104
|
+
render={({ field }) => (
|
|
105
|
+
<CustomEditor
|
|
106
|
+
config={{
|
|
107
|
+
initialContent: field.value,
|
|
108
|
+
onChange: (val) => field.onChange(val),
|
|
109
|
+
maxLength: 5000,
|
|
110
|
+
placeholder: 'Write your masterpiece...'
|
|
111
|
+
}}
|
|
112
|
+
/>
|
|
113
|
+
)}
|
|
114
|
+
/>
|
|
115
|
+
{errors.postContent && <p className="error">{errors.postContent.message}</p>}
|
|
116
|
+
<button type="submit">Publish Masterpiece</button>
|
|
117
|
+
</form>
|
|
59
118
|
);
|
|
119
|
+
};
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 📑 Detailed API Configuration
|
|
125
|
+
|
|
126
|
+
### `EditorConfig` Props
|
|
127
|
+
|
|
128
|
+
| Prop | Type | Default | Description |
|
|
129
|
+
| :--- | :--- | :--- | :--- |
|
|
130
|
+
| `width` | `string \| number` | `'100%'` | Width of the editor (e.g., `'800px'`, `'100%'`). |
|
|
131
|
+
| `align` | `'left' \| 'center' \| 'right'` | `'left'` | Alignment of the editor container. |
|
|
132
|
+
| `outputFormat` | `'html' \| 'text'` | `'html'` | Content format sent to the `onChange` callback. |
|
|
133
|
+
| `maxLength` | `number` | - | Character limit. Enables the live-counter footer auto-magically. |
|
|
134
|
+
| `placeholder` | `string` | `'Write here...'` | Placeholder text when the editor is empty. |
|
|
135
|
+
| `theme` | `ThemeConfig` | - | Custom theme object for colors and styling (see below). |
|
|
136
|
+
| `features` | `string[]` | All | Array of enabled toolbar features (bold, italic, etc.). |
|
|
137
|
+
|
|
138
|
+
### `ThemeConfig` Options
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
{
|
|
142
|
+
primaryColor: string; // Accent color for icons & progress
|
|
143
|
+
borderRadius: string; // Control the "roundness" (e.g., '16px')
|
|
144
|
+
backgroundColor: string; // Background of the editor area
|
|
145
|
+
textColor: string; // Color of the content text
|
|
60
146
|
}
|
|
61
147
|
```
|
|
62
148
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
| Property | Type | Description |
|
|
69
|
-
| :--- | :--- | :--- |
|
|
70
|
-
| `layout` | `'top-bar' \| 'bottom-bar'` | Position of the toolbar. |
|
|
71
|
-
| `features` | `string[]` | Array of tools to display (e.g., `['bold', 'italic', 'link']`). |
|
|
72
|
-
| `theme` | `ThemeConfig` | Custom theme object (see section below). |
|
|
73
|
-
| `title` | `string` | Optional editor title. |
|
|
74
|
-
| `showTitle` | `boolean` | Toggle title visibility. |
|
|
75
|
-
| `placeholder` | `string` | Custom placeholder text. |
|
|
76
|
-
| `width` | `string \| number` | Number or string (e.g., `800` or `'100%'`). |
|
|
77
|
-
| `maxLength` | `number` | Maximum character limit. |
|
|
78
|
-
| `initialContent` | `string` | Initial HTML content for the editor. |
|
|
79
|
-
| `onChange` | `(content: string) => void` | Callback when content changes (returns HTML). |
|
|
80
|
-
| `onCharacterCountChange` | `(count: number) => void` | Callback when character count changes. |
|
|
81
|
-
|
|
82
|
-
### 🎨 Theme Configuration
|
|
83
|
-
| Property | Description | Default |
|
|
84
|
-
| :--- | :--- | :--- |
|
|
85
|
-
| `primaryColor` | Brand color for active states & borders | `#3b82f6` |
|
|
86
|
-
| `secondaryColor` | Secondary brand color | - |
|
|
87
|
-
| `backgroundColor` | Editor and toolbar background | `#ffffff` |
|
|
88
|
-
| `textColor` | Main text color | `#0f172a` |
|
|
89
|
-
| `accentColor` | Background for hovered buttons | `#f8fafc` |
|
|
90
|
-
| `borderColor` | Border color for the container | `#e2e8f0` |
|
|
91
|
-
| `borderRadius` | Main corner radius | `0.75rem` |
|
|
92
|
-
| `fontFamily` | Custom font family | `'Inter', sans-serif` |
|
|
93
|
-
|
|
94
|
-
## 🛠️ Troubleshooting
|
|
95
|
-
|
|
96
|
-
### "Invalid hook call" or "Double React"
|
|
97
|
-
If you encounter an "Invalid hook call" error while using `npm link`, it's likely because React is being loaded twice (once from your project and once from the library's `node_modules`).
|
|
98
|
-
|
|
99
|
-
**Fix:** Update your project's `vite.config.ts` to alias React to your local version:
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 🛠️ Troubleshooting: Vite Configuration
|
|
152
|
+
|
|
153
|
+
If you encounter issues like **"Outdated Optimize Dep"** or React version mismatches while using this package, you must add the following aliases to your **consumer project's** `vite.config.ts`. This ensures that both your project and the editor use the same instance of React.
|
|
100
154
|
|
|
101
155
|
```typescript
|
|
102
|
-
|
|
156
|
+
import { defineConfig } from 'vite';
|
|
157
|
+
import react from '@vitejs/plugin-react';
|
|
103
158
|
import path from 'path';
|
|
104
159
|
|
|
105
160
|
export default defineConfig({
|
|
161
|
+
plugins: [react()],
|
|
106
162
|
resolve: {
|
|
107
163
|
alias: {
|
|
108
164
|
'react': path.resolve(__dirname, 'node_modules/react'),
|
|
@@ -112,3 +168,14 @@ export default defineConfig({
|
|
|
112
168
|
});
|
|
113
169
|
```
|
|
114
170
|
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 📄 License
|
|
174
|
+
Proudly open-source under the **MIT License**. Created by [kanhaiya-dct](https://github.com/kanhaiya-dct).
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
<div align="center">
|
|
179
|
+
<h3>Show your support! ⭐</h3>
|
|
180
|
+
<p>If you find this editor useful, please consider giving it a star on GitHub!</p>
|
|
181
|
+
</div>
|
|
@@ -8,91 +8,92 @@ import { TextStyle as s } from "@tiptap/extension-text-style";
|
|
|
8
8
|
import c from "@tiptap/extension-color";
|
|
9
9
|
import l from "@tiptap/extension-placeholder";
|
|
10
10
|
import u from "@tiptap/extension-font-family";
|
|
11
|
-
import
|
|
12
|
-
import {
|
|
11
|
+
import d from "@tiptap/extension-character-count";
|
|
12
|
+
import { Bold as f, Code as p, Heading1 as m, Heading2 as h, Heading3 as g, Highlighter as _, Italic as v, Link as y, List as b, ListOrdered as x, Minus as S, Palette as C, Quote as w, Redo as T, Strikethrough as E, Terminal as D, Underline as O, Undo as k } from "lucide-react";
|
|
13
|
+
import { jsx as A, jsxs as j } from "react/jsx-runtime";
|
|
13
14
|
//#region src/lib/constants/toolbarConfig.tsx
|
|
14
|
-
var
|
|
15
|
+
var M = (e) => [
|
|
15
16
|
{
|
|
16
17
|
name: "bold",
|
|
17
|
-
icon: /* @__PURE__ */
|
|
18
|
+
icon: /* @__PURE__ */ A(f, { size: 18 }),
|
|
18
19
|
action: (e) => e.chain().focus().toggleBold().run(),
|
|
19
20
|
isActive: (e) => e.isActive("bold")
|
|
20
21
|
},
|
|
21
22
|
{
|
|
22
23
|
name: "italic",
|
|
23
|
-
icon: /* @__PURE__ */
|
|
24
|
+
icon: /* @__PURE__ */ A(v, { size: 18 }),
|
|
24
25
|
action: (e) => e.chain().focus().toggleItalic().run(),
|
|
25
26
|
isActive: (e) => e.isActive("italic")
|
|
26
27
|
},
|
|
27
28
|
{
|
|
28
29
|
name: "underline",
|
|
29
|
-
icon: /* @__PURE__ */
|
|
30
|
+
icon: /* @__PURE__ */ A(O, { size: 18 }),
|
|
30
31
|
action: (e) => e.chain().focus().toggleUnderline().run(),
|
|
31
32
|
isActive: (e) => e.isActive("underline")
|
|
32
33
|
},
|
|
33
34
|
{
|
|
34
35
|
name: "strike",
|
|
35
|
-
icon: /* @__PURE__ */
|
|
36
|
+
icon: /* @__PURE__ */ A(E, { size: 18 }),
|
|
36
37
|
action: (e) => e.chain().focus().toggleStrike().run(),
|
|
37
38
|
isActive: (e) => e.isActive("strike")
|
|
38
39
|
},
|
|
39
40
|
{
|
|
40
41
|
name: "heading1",
|
|
41
|
-
icon: /* @__PURE__ */
|
|
42
|
+
icon: /* @__PURE__ */ A(m, { size: 18 }),
|
|
42
43
|
action: (e) => e.chain().focus().toggleHeading({ level: 1 }).run(),
|
|
43
44
|
isActive: (e) => e.isActive("heading", { level: 1 })
|
|
44
45
|
},
|
|
45
46
|
{
|
|
46
47
|
name: "heading2",
|
|
47
|
-
icon: /* @__PURE__ */
|
|
48
|
+
icon: /* @__PURE__ */ A(h, { size: 18 }),
|
|
48
49
|
action: (e) => e.chain().focus().toggleHeading({ level: 2 }).run(),
|
|
49
50
|
isActive: (e) => e.isActive("heading", { level: 2 })
|
|
50
51
|
},
|
|
51
52
|
{
|
|
52
53
|
name: "heading3",
|
|
53
|
-
icon: /* @__PURE__ */
|
|
54
|
+
icon: /* @__PURE__ */ A(g, { size: 18 }),
|
|
54
55
|
action: (e) => e.chain().focus().toggleHeading({ level: 3 }).run(),
|
|
55
56
|
isActive: (e) => e.isActive("heading", { level: 3 })
|
|
56
57
|
},
|
|
57
58
|
{
|
|
58
59
|
name: "bulletList",
|
|
59
|
-
icon: /* @__PURE__ */
|
|
60
|
+
icon: /* @__PURE__ */ A(b, { size: 18 }),
|
|
60
61
|
action: (e) => e.chain().focus().toggleBulletList().run(),
|
|
61
62
|
isActive: (e) => e.isActive("bulletList")
|
|
62
63
|
},
|
|
63
64
|
{
|
|
64
65
|
name: "orderedList",
|
|
65
|
-
icon: /* @__PURE__ */
|
|
66
|
+
icon: /* @__PURE__ */ A(x, { size: 18 }),
|
|
66
67
|
action: (e) => e.chain().focus().toggleOrderedList().run(),
|
|
67
68
|
isActive: (e) => e.isActive("orderedList")
|
|
68
69
|
},
|
|
69
70
|
{
|
|
70
71
|
name: "blockquote",
|
|
71
|
-
icon: /* @__PURE__ */
|
|
72
|
+
icon: /* @__PURE__ */ A(w, { size: 18 }),
|
|
72
73
|
action: (e) => e.chain().focus().toggleBlockquote().run(),
|
|
73
74
|
isActive: (e) => e.isActive("blockquote")
|
|
74
75
|
},
|
|
75
76
|
{
|
|
76
77
|
name: "code",
|
|
77
|
-
icon: /* @__PURE__ */
|
|
78
|
+
icon: /* @__PURE__ */ A(p, { size: 18 }),
|
|
78
79
|
action: (e) => e.chain().focus().toggleCode().run(),
|
|
79
80
|
isActive: (e) => e.isActive("code")
|
|
80
81
|
},
|
|
81
82
|
{
|
|
82
83
|
name: "codeBlock",
|
|
83
|
-
icon: /* @__PURE__ */
|
|
84
|
+
icon: /* @__PURE__ */ A(D, { size: 18 }),
|
|
84
85
|
action: (e) => e.chain().focus().toggleCodeBlock().run(),
|
|
85
86
|
isActive: (e) => e.isActive("codeBlock")
|
|
86
87
|
},
|
|
87
88
|
{
|
|
88
89
|
name: "color",
|
|
89
|
-
icon: /* @__PURE__ */
|
|
90
|
+
icon: /* @__PURE__ */ j("div", {
|
|
90
91
|
style: {
|
|
91
92
|
position: "relative",
|
|
92
93
|
display: "flex",
|
|
93
94
|
alignItems: "center"
|
|
94
95
|
},
|
|
95
|
-
children: [/* @__PURE__ */
|
|
96
|
+
children: [/* @__PURE__ */ A(C, { size: 18 }), /* @__PURE__ */ A("input", {
|
|
96
97
|
type: "color",
|
|
97
98
|
onInput: (t) => {
|
|
98
99
|
let n = t.target.value;
|
|
@@ -113,13 +114,13 @@ var j = (e) => [
|
|
|
113
114
|
},
|
|
114
115
|
{
|
|
115
116
|
name: "highlight",
|
|
116
|
-
icon: /* @__PURE__ */
|
|
117
|
+
icon: /* @__PURE__ */ j("div", {
|
|
117
118
|
style: {
|
|
118
119
|
position: "relative",
|
|
119
120
|
display: "flex",
|
|
120
121
|
alignItems: "center"
|
|
121
122
|
},
|
|
122
|
-
children: [/* @__PURE__ */
|
|
123
|
+
children: [/* @__PURE__ */ A(_, { size: 18 }), /* @__PURE__ */ A("input", {
|
|
123
124
|
type: "color",
|
|
124
125
|
onInput: (t) => {
|
|
125
126
|
let n = t.target.value;
|
|
@@ -140,7 +141,7 @@ var j = (e) => [
|
|
|
140
141
|
},
|
|
141
142
|
{
|
|
142
143
|
name: "link",
|
|
143
|
-
icon: /* @__PURE__ */
|
|
144
|
+
icon: /* @__PURE__ */ A(y, { size: 18 }),
|
|
144
145
|
action: (e) => {
|
|
145
146
|
if (e.isActive("link")) {
|
|
146
147
|
e.chain().focus().unsetLink().run();
|
|
@@ -153,27 +154,27 @@ var j = (e) => [
|
|
|
153
154
|
},
|
|
154
155
|
{
|
|
155
156
|
name: "horizontalRule",
|
|
156
|
-
icon: /* @__PURE__ */
|
|
157
|
+
icon: /* @__PURE__ */ A(S, { size: 18 }),
|
|
157
158
|
action: (e) => e.chain().focus().setHorizontalRule().run(),
|
|
158
159
|
isActive: () => !1
|
|
159
160
|
},
|
|
160
161
|
{
|
|
161
162
|
name: "undo",
|
|
162
|
-
icon: /* @__PURE__ */ k
|
|
163
|
+
icon: /* @__PURE__ */ A(k, { size: 18 }),
|
|
163
164
|
action: (e) => e.chain().focus().undo().run(),
|
|
164
165
|
isActive: () => !1,
|
|
165
166
|
disabled: (e) => !e.can().undo()
|
|
166
167
|
},
|
|
167
168
|
{
|
|
168
169
|
name: "redo",
|
|
169
|
-
icon: /* @__PURE__ */
|
|
170
|
+
icon: /* @__PURE__ */ A(T, { size: 18 }),
|
|
170
171
|
action: (e) => e.chain().focus().redo().run(),
|
|
171
172
|
isActive: () => !1,
|
|
172
173
|
disabled: (e) => !e.can().redo()
|
|
173
174
|
}
|
|
174
|
-
],
|
|
175
|
+
], N = ({ editor: e, config: t }) => {
|
|
175
176
|
let n = t.isActive(e);
|
|
176
|
-
return /* @__PURE__ */
|
|
177
|
+
return /* @__PURE__ */ A("button", {
|
|
177
178
|
type: "button",
|
|
178
179
|
onMouseDown: (e) => e.preventDefault(),
|
|
179
180
|
onClick: () => t.action(e),
|
|
@@ -182,7 +183,7 @@ var j = (e) => [
|
|
|
182
183
|
title: t.name.charAt(0).toUpperCase() + t.name.slice(1),
|
|
183
184
|
children: t.icon
|
|
184
185
|
});
|
|
185
|
-
},
|
|
186
|
+
}, P = ({ editor: t, features: n = [
|
|
186
187
|
"bold",
|
|
187
188
|
"italic",
|
|
188
189
|
"underline",
|
|
@@ -197,8 +198,8 @@ var j = (e) => [
|
|
|
197
198
|
t.off("transaction", e);
|
|
198
199
|
};
|
|
199
200
|
}, [t]), !t) return null;
|
|
200
|
-
let a =
|
|
201
|
-
return /* @__PURE__ */
|
|
201
|
+
let a = M(t);
|
|
202
|
+
return /* @__PURE__ */ A("div", {
|
|
202
203
|
className: `cte-toolbar ${r}`,
|
|
203
204
|
children: [
|
|
204
205
|
{
|
|
@@ -235,16 +236,16 @@ var j = (e) => [
|
|
|
235
236
|
}
|
|
236
237
|
].map((e) => {
|
|
237
238
|
let r = a.filter((t) => e.features.includes(t.name) && n.includes(t.name));
|
|
238
|
-
return r.length === 0 ? null : /* @__PURE__ */
|
|
239
|
+
return r.length === 0 ? null : /* @__PURE__ */ A("div", {
|
|
239
240
|
className: "cte-toolbar-group",
|
|
240
|
-
children: r.map((e) => /* @__PURE__ */
|
|
241
|
+
children: r.map((e) => /* @__PURE__ */ A(N, {
|
|
241
242
|
editor: t,
|
|
242
243
|
config: e
|
|
243
244
|
}, e.name))
|
|
244
245
|
}, e.name);
|
|
245
246
|
})
|
|
246
247
|
});
|
|
247
|
-
},
|
|
248
|
+
}, F = (t, n) => {
|
|
248
249
|
e.useEffect(() => {
|
|
249
250
|
if (!t.current || !n?.theme) return;
|
|
250
251
|
let { theme: e } = n, r = t.current, i = {
|
|
@@ -255,14 +256,13 @@ var j = (e) => [
|
|
|
255
256
|
"--cte-accent": e.accentColor,
|
|
256
257
|
"--cte-toolbar-btn-bg": e.toolbarButtonBackgroundColor,
|
|
257
258
|
"--cte-border": e.borderColor,
|
|
258
|
-
"--cte-radius": e.borderRadius
|
|
259
|
-
"--cte-width": typeof n.width == "number" ? `${n.width}px` : n.width || "100%"
|
|
259
|
+
"--cte-radius": e.borderRadius
|
|
260
260
|
};
|
|
261
261
|
Object.entries(i).forEach(([e, t]) => {
|
|
262
262
|
t && r.style.setProperty(e, t);
|
|
263
263
|
});
|
|
264
264
|
}, [n, t]);
|
|
265
|
-
},
|
|
265
|
+
}, I = [
|
|
266
266
|
"bold",
|
|
267
267
|
"italic",
|
|
268
268
|
"underline",
|
|
@@ -281,15 +281,15 @@ var j = (e) => [
|
|
|
281
281
|
"horizontalRule",
|
|
282
282
|
"undo",
|
|
283
283
|
"redo"
|
|
284
|
-
],
|
|
285
|
-
let
|
|
286
|
-
e.useLayoutEffect(() => {
|
|
284
|
+
], L = e.forwardRef(({ config: f }, p) => {
|
|
285
|
+
let m = e.useRef(null), [h, g] = e.useState(f?.initialContent?.length || 0);
|
|
286
|
+
e.useImperativeHandle(p, () => m.current), e.useLayoutEffect(() => {
|
|
287
287
|
if (typeof document < "u" && !document.getElementById("cte-styles")) {
|
|
288
288
|
let e = document.createElement("style");
|
|
289
|
-
e.id = "cte-styles", e.textContent = "\n:root {\n --cte-primary: #3b82f6;\n --cte-primary-foreground: #ffffff;\n --cte-background: #ffffff;\n --cte-foreground: #0f172a;\n --cte-muted: #f1f5f9;\n --cte-muted-foreground: #64748b;\n --cte-border: #e2e8f0;\n --cte-accent: #f8fafc;\n --cte-accent-foreground: #0f172a;\n --cte-radius: 0.75rem;\n --cte-font-family: 'Inter', system-ui, sans-serif;\n}\n.cte-editor-container {\n display: flex;\n flex-direction: column;\n background-color: var(--cte-background);\n color: var(--cte-foreground);\n border: 1px solid var(--cte-border);\n border-radius: var(--cte-radius);\n font-family: var(--cte-font-family);\n
|
|
289
|
+
e.id = "cte-styles", e.textContent = "\n:root {\n --cte-primary: #3b82f6;\n --cte-primary-foreground: #ffffff;\n --cte-background: #ffffff;\n --cte-foreground: #0f172a;\n --cte-muted: #f1f5f9;\n --cte-muted-foreground: #64748b;\n --cte-border: #e2e8f0;\n --cte-accent: #f8fafc;\n --cte-accent-foreground: #0f172a;\n --cte-radius: 0.75rem;\n --cte-font-family: 'Inter', system-ui, sans-serif;\n}\n.cte-editor-container {\n display: flex;\n flex-direction: column;\n background-color: var(--cte-background);\n color: var(--cte-foreground);\n border: 1px solid var(--cte-border);\n border-radius: var(--cte-radius);\n font-family: var(--cte-font-family);\n overflow: hidden;\n transition: all 0.3s ease;\n box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);\n}\n.cte-toolbar {\n display: flex;\n align-items: center;\n padding: 0.5rem;\n border-bottom: 1px solid var(--cte-border);\n background-color: var(--cte-background);\n gap: 0.25rem;\n overflow-x: auto;\n}\n.cte-toolbar-group {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n padding-right: 0.5rem;\n border-right: 1px solid var(--cte-border);\n}\n.cte-toolbar-group:last-child { border-right: none; }\n.cte-toolbar-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n border-radius: 0.375rem;\n border: none;\n background: transparent;\n color: var(--cte-foreground);\n cursor: pointer;\n transition: all 0.2s;\n}\n.cte-toolbar-btn:hover { background-color: var(--cte-accent); }\n.cte-toolbar-btn.is-active {\n background-color: var(--cte-primary);\n color: var(--cte-primary-foreground);\n}\n.cte-content-area {\n padding: 1rem;\n min-height: 150px;\n outline: none;\n}\n.ProseMirror { outline: none; }\n.cte-footer {\n display: flex;\n justify-content: flex-end;\n padding: 0.5rem 1rem;\n border-top: 1px solid var(--cte-border);\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--cte-muted-foreground);\n background-color: #f8fafc;\n border-bottom-left-radius: var(--cte-radius);\n border-bottom-right-radius: var(--cte-radius);\n z-index: 10;\n}\n ", document.head.appendChild(e);
|
|
290
290
|
}
|
|
291
|
-
}, []),
|
|
292
|
-
let
|
|
291
|
+
}, []), F(m, f);
|
|
292
|
+
let _ = n({
|
|
293
293
|
extensions: [
|
|
294
294
|
r,
|
|
295
295
|
i,
|
|
@@ -298,33 +298,75 @@ var j = (e) => [
|
|
|
298
298
|
s,
|
|
299
299
|
c,
|
|
300
300
|
u,
|
|
301
|
-
l.configure({ placeholder:
|
|
301
|
+
l.configure({ placeholder: f?.placeholder || "Write here..." }),
|
|
302
|
+
d.configure({ limit: f?.maxLength })
|
|
302
303
|
],
|
|
303
|
-
content:
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
304
|
+
content: f?.initialContent || "",
|
|
305
|
+
onUpdate: ({ editor: e }) => {
|
|
306
|
+
let t = f?.outputFormat == "text" ? e.getText() : e.getHTML();
|
|
307
|
+
f?.onChange?.(t);
|
|
308
|
+
let n = t.length;
|
|
309
|
+
g(n), f?.onCharacterCountChange?.(n);
|
|
310
|
+
}
|
|
311
|
+
}), v = f?.layout === "bottom-bar", y = f?.features || I, b = {
|
|
312
|
+
width: typeof f?.width == "number" ? `${f.width}px` : f?.width || "100%",
|
|
313
|
+
margin: f?.margin || "0 auto",
|
|
314
|
+
...(() => {
|
|
315
|
+
if (!f?.align) return {};
|
|
316
|
+
switch (f.align) {
|
|
317
|
+
case "left": return {
|
|
318
|
+
marginLeft: "0",
|
|
319
|
+
marginRight: "auto"
|
|
320
|
+
};
|
|
321
|
+
case "center": return {
|
|
322
|
+
marginLeft: "auto",
|
|
323
|
+
marginRight: "auto"
|
|
324
|
+
};
|
|
325
|
+
case "right": return {
|
|
326
|
+
marginLeft: "auto",
|
|
327
|
+
marginRight: "0"
|
|
328
|
+
};
|
|
329
|
+
default: return {};
|
|
330
|
+
}
|
|
331
|
+
})()
|
|
332
|
+
};
|
|
333
|
+
return /* @__PURE__ */ j("div", {
|
|
334
|
+
...f?.containerProps,
|
|
335
|
+
className: `cte-editor-container ${f?.containerProps?.className || ""}`,
|
|
336
|
+
ref: m,
|
|
337
|
+
style: {
|
|
338
|
+
...b,
|
|
339
|
+
...f?.containerProps?.style
|
|
340
|
+
},
|
|
308
341
|
children: [
|
|
309
|
-
|
|
342
|
+
f?.showTitle && f.title && /* @__PURE__ */ A("div", {
|
|
310
343
|
className: "cte-title-bar",
|
|
311
|
-
children:
|
|
344
|
+
children: f.title
|
|
312
345
|
}),
|
|
313
|
-
!
|
|
314
|
-
editor:
|
|
315
|
-
features:
|
|
346
|
+
!v && /* @__PURE__ */ A(P, {
|
|
347
|
+
editor: _,
|
|
348
|
+
features: y
|
|
316
349
|
}),
|
|
317
|
-
/* @__PURE__ */
|
|
318
|
-
editor:
|
|
350
|
+
/* @__PURE__ */ A(t, {
|
|
351
|
+
editor: _,
|
|
319
352
|
className: "cte-content-area"
|
|
320
353
|
}),
|
|
321
|
-
|
|
322
|
-
editor:
|
|
323
|
-
features:
|
|
354
|
+
v && /* @__PURE__ */ A(P, {
|
|
355
|
+
editor: _,
|
|
356
|
+
features: y,
|
|
324
357
|
className: "cte-bottom"
|
|
358
|
+
}),
|
|
359
|
+
f?.maxLength && /* @__PURE__ */ j("div", {
|
|
360
|
+
className: "cte-footer",
|
|
361
|
+
children: [
|
|
362
|
+
h,
|
|
363
|
+
" / ",
|
|
364
|
+
f.maxLength,
|
|
365
|
+
" characters"
|
|
366
|
+
]
|
|
325
367
|
})
|
|
326
368
|
]
|
|
327
369
|
});
|
|
328
|
-
};
|
|
370
|
+
});
|
|
329
371
|
//#endregion
|
|
330
|
-
export {
|
|
372
|
+
export { L as CustomEditor };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require(`react`),require(`@tiptap/react`),require(`@tiptap/starter-kit`),require(`@tiptap/extension-underline`),require(`@tiptap/extension-link`),require(`@tiptap/extension-highlight`),require(`@tiptap/extension-text-style`),require(`@tiptap/extension-color`),require(`@tiptap/extension-placeholder`),require(`@tiptap/extension-font-family`),require(`lucide-react`),require(`react/jsx-runtime`)):typeof define==`function`&&define.amd?define([`exports`,`react`,`@tiptap/react`,`@tiptap/starter-kit`,`@tiptap/extension-underline`,`@tiptap/extension-link`,`@tiptap/extension-highlight`,`@tiptap/extension-text-style`,`@tiptap/extension-color`,`@tiptap/extension-placeholder`,`@tiptap/extension-font-family`,`lucide-react`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.CustomiseTextEditor={},e.React,e.TiptapReact,e.TiptapStarterKit,e._tiptap_extension_underline,e._tiptap_extension_link,e._tiptap_extension_highlight,e._tiptap_extension_text_style,e._tiptap_extension_color,e._tiptap_extension_placeholder,e._tiptap_extension_font_family,e.LucideReact,e.react_jsx_runtime))})(this,function(e,t,n,r,i,a,o,s,c,l,u,d,f){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var
|
|
1
|
+
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require(`react`),require(`@tiptap/react`),require(`@tiptap/starter-kit`),require(`@tiptap/extension-underline`),require(`@tiptap/extension-link`),require(`@tiptap/extension-highlight`),require(`@tiptap/extension-text-style`),require(`@tiptap/extension-color`),require(`@tiptap/extension-placeholder`),require(`@tiptap/extension-font-family`),require(`@tiptap/extension-character-count`),require(`lucide-react`),require(`react/jsx-runtime`)):typeof define==`function`&&define.amd?define([`exports`,`react`,`@tiptap/react`,`@tiptap/starter-kit`,`@tiptap/extension-underline`,`@tiptap/extension-link`,`@tiptap/extension-highlight`,`@tiptap/extension-text-style`,`@tiptap/extension-color`,`@tiptap/extension-placeholder`,`@tiptap/extension-font-family`,`@tiptap/extension-character-count`,`lucide-react`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.CustomiseTextEditor={},e.React,e.TiptapReact,e.TiptapStarterKit,e._tiptap_extension_underline,e._tiptap_extension_link,e._tiptap_extension_highlight,e._tiptap_extension_text_style,e._tiptap_extension_color,e._tiptap_extension_placeholder,e._tiptap_extension_font_family,e._tiptap_extension_character_count,e.LucideReact,e.react_jsx_runtime))})(this,function(e,t,n,r,i,a,o,s,c,l,u,d,f,p){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var m=Object.create,h=Object.defineProperty,g=Object.getOwnPropertyDescriptor,_=Object.getOwnPropertyNames,v=Object.getPrototypeOf,y=Object.prototype.hasOwnProperty,b=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=_(t),a=0,o=i.length,s;a<o;a++)s=i[a],!y.call(e,s)&&s!==n&&h(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=g(t,s))||r.enumerable});return e},x=(e,t,n)=>(n=e==null?{}:m(v(e)),b(t||!e||!e.__esModule?h(n,`default`,{value:e,enumerable:!0}):n,e));t=x(t),r=x(r),i=x(i),a=x(a),o=x(o),c=x(c),l=x(l),u=x(u),d=x(d);var S=e=>[{name:`bold`,icon:(0,p.jsx)(f.Bold,{size:18}),action:e=>e.chain().focus().toggleBold().run(),isActive:e=>e.isActive(`bold`)},{name:`italic`,icon:(0,p.jsx)(f.Italic,{size:18}),action:e=>e.chain().focus().toggleItalic().run(),isActive:e=>e.isActive(`italic`)},{name:`underline`,icon:(0,p.jsx)(f.Underline,{size:18}),action:e=>e.chain().focus().toggleUnderline().run(),isActive:e=>e.isActive(`underline`)},{name:`strike`,icon:(0,p.jsx)(f.Strikethrough,{size:18}),action:e=>e.chain().focus().toggleStrike().run(),isActive:e=>e.isActive(`strike`)},{name:`heading1`,icon:(0,p.jsx)(f.Heading1,{size:18}),action:e=>e.chain().focus().toggleHeading({level:1}).run(),isActive:e=>e.isActive(`heading`,{level:1})},{name:`heading2`,icon:(0,p.jsx)(f.Heading2,{size:18}),action:e=>e.chain().focus().toggleHeading({level:2}).run(),isActive:e=>e.isActive(`heading`,{level:2})},{name:`heading3`,icon:(0,p.jsx)(f.Heading3,{size:18}),action:e=>e.chain().focus().toggleHeading({level:3}).run(),isActive:e=>e.isActive(`heading`,{level:3})},{name:`bulletList`,icon:(0,p.jsx)(f.List,{size:18}),action:e=>e.chain().focus().toggleBulletList().run(),isActive:e=>e.isActive(`bulletList`)},{name:`orderedList`,icon:(0,p.jsx)(f.ListOrdered,{size:18}),action:e=>e.chain().focus().toggleOrderedList().run(),isActive:e=>e.isActive(`orderedList`)},{name:`blockquote`,icon:(0,p.jsx)(f.Quote,{size:18}),action:e=>e.chain().focus().toggleBlockquote().run(),isActive:e=>e.isActive(`blockquote`)},{name:`code`,icon:(0,p.jsx)(f.Code,{size:18}),action:e=>e.chain().focus().toggleCode().run(),isActive:e=>e.isActive(`code`)},{name:`codeBlock`,icon:(0,p.jsx)(f.Terminal,{size:18}),action:e=>e.chain().focus().toggleCodeBlock().run(),isActive:e=>e.isActive(`codeBlock`)},{name:`color`,icon:(0,p.jsxs)(`div`,{style:{position:`relative`,display:`flex`,alignItems:`center`},children:[(0,p.jsx)(f.Palette,{size:18}),(0,p.jsx)(`input`,{type:`color`,onInput:t=>{let n=t.target.value;e.chain().focus().setColor(n).run()},style:{position:`absolute`,inset:0,opacity:0,cursor:`pointer`,width:`100%`,height:`100%`}})]}),action:()=>{},isActive:e=>e.isActive(`textStyle`)},{name:`highlight`,icon:(0,p.jsxs)(`div`,{style:{position:`relative`,display:`flex`,alignItems:`center`},children:[(0,p.jsx)(f.Highlighter,{size:18}),(0,p.jsx)(`input`,{type:`color`,onInput:t=>{let n=t.target.value;e.chain().focus().toggleHighlight({color:n}).run()},style:{position:`absolute`,inset:0,opacity:0,cursor:`pointer`,width:`100%`,height:`100%`}})]}),action:()=>{},isActive:e=>e.isActive(`highlight`)},{name:`link`,icon:(0,p.jsx)(f.Link,{size:18}),action:e=>{if(e.isActive(`link`)){e.chain().focus().unsetLink().run();return}let t=window.prompt(`Enter URL`);t&&(!t.startsWith(`http://`)&&!t.startsWith(`https://`)&&!t.startsWith(`mailto:`)&&(t=`https://`+t),e.chain().focus().setLink({href:t}).run())},isActive:e=>e.isActive(`link`)},{name:`horizontalRule`,icon:(0,p.jsx)(f.Minus,{size:18}),action:e=>e.chain().focus().setHorizontalRule().run(),isActive:()=>!1},{name:`undo`,icon:(0,p.jsx)(f.Undo,{size:18}),action:e=>e.chain().focus().undo().run(),isActive:()=>!1,disabled:e=>!e.can().undo()},{name:`redo`,icon:(0,p.jsx)(f.Redo,{size:18}),action:e=>e.chain().focus().redo().run(),isActive:()=>!1,disabled:e=>!e.can().redo()}],C=({editor:e,config:t})=>{let n=t.isActive(e);return(0,p.jsx)(`button`,{type:`button`,onMouseDown:e=>e.preventDefault(),onClick:()=>t.action(e),disabled:t.disabled?t.disabled(e):!1,className:`cte-toolbar-btn ${n?`is-active`:``}`,title:t.name.charAt(0).toUpperCase()+t.name.slice(1),children:t.icon})},w=({editor:e,features:n=[`bold`,`italic`,`underline`,`undo`,`redo`],className:r=``})=>{let[,i]=t.default.useState(0);if(t.default.useEffect(()=>{if(!e)return;let t=()=>i(e=>e+1);return e.on(`transaction`,t),()=>{e.off(`transaction`,t)}},[e]),!e)return null;let a=S(e);return(0,p.jsx)(`div`,{className:`cte-toolbar ${r}`,children:[{name:`formatting`,features:[`bold`,`italic`,`underline`,`strike`,`color`,`highlight`]},{name:`blocks`,features:[`heading1`,`heading2`,`heading3`,`bulletList`,`orderedList`,`blockquote`,`code`,`codeBlock`]},{name:`actions`,features:[`link`,`horizontalRule`]},{name:`history`,features:[`undo`,`redo`]}].map(t=>{let r=a.filter(e=>t.features.includes(e.name)&&n.includes(e.name));return r.length===0?null:(0,p.jsx)(`div`,{className:`cte-toolbar-group`,children:r.map(t=>(0,p.jsx)(C,{editor:e,config:t},t.name))},t.name)})})},T=(e,n)=>{t.default.useEffect(()=>{if(!e.current||!n?.theme)return;let{theme:t}=n,r=e.current,i={"--cte-primary":t.primaryColor,"--cte-primary-foreground":t.primaryForegroundColor,"--cte-background":t.backgroundColor,"--cte-text":t.textColor,"--cte-accent":t.accentColor,"--cte-toolbar-btn-bg":t.toolbarButtonBackgroundColor,"--cte-border":t.borderColor,"--cte-radius":t.borderRadius};Object.entries(i).forEach(([e,t])=>{t&&r.style.setProperty(e,t)})},[n,e])},E=[`bold`,`italic`,`underline`,`strike`,`heading1`,`heading2`,`heading3`,`bulletList`,`orderedList`,`blockquote`,`code`,`codeBlock`,`link`,`color`,`highlight`,`horizontalRule`,`undo`,`redo`];e.CustomEditor=t.default.forwardRef(({config:e},f)=>{let m=t.default.useRef(null),[h,g]=t.default.useState(e?.initialContent?.length||0);t.default.useImperativeHandle(f,()=>m.current),t.default.useLayoutEffect(()=>{if(typeof document<`u`&&!document.getElementById(`cte-styles`)){let e=document.createElement(`style`);e.id=`cte-styles`,e.textContent=`
|
|
2
2
|
:root {
|
|
3
3
|
--cte-primary: #3b82f6;
|
|
4
4
|
--cte-primary-foreground: #ffffff;
|
|
@@ -20,9 +20,6 @@
|
|
|
20
20
|
border: 1px solid var(--cte-border);
|
|
21
21
|
border-radius: var(--cte-radius);
|
|
22
22
|
font-family: var(--cte-font-family);
|
|
23
|
-
width: var(--cte-width, 100%);
|
|
24
|
-
max-width: 100%;
|
|
25
|
-
margin: 0 auto;
|
|
26
23
|
overflow: hidden;
|
|
27
24
|
transition: all 0.3s ease;
|
|
28
25
|
box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);
|
|
@@ -68,4 +65,17 @@
|
|
|
68
65
|
outline: none;
|
|
69
66
|
}
|
|
70
67
|
.ProseMirror { outline: none; }
|
|
71
|
-
|
|
68
|
+
.cte-footer {
|
|
69
|
+
display: flex;
|
|
70
|
+
justify-content: flex-end;
|
|
71
|
+
padding: 0.5rem 1rem;
|
|
72
|
+
border-top: 1px solid var(--cte-border);
|
|
73
|
+
font-size: 0.75rem;
|
|
74
|
+
font-weight: 500;
|
|
75
|
+
color: var(--cte-muted-foreground);
|
|
76
|
+
background-color: #f8fafc;
|
|
77
|
+
border-bottom-left-radius: var(--cte-radius);
|
|
78
|
+
border-bottom-right-radius: var(--cte-radius);
|
|
79
|
+
z-index: 10;
|
|
80
|
+
}
|
|
81
|
+
`,document.head.appendChild(e)}},[]),T(m,e);let _=(0,n.useEditor)({extensions:[r.default,i.default,a.default.configure({openOnClick:!1}),o.default.configure({multicolor:!0}),s.TextStyle,c.default,u.default,l.default.configure({placeholder:e?.placeholder||`Write here...`}),d.default.configure({limit:e?.maxLength})],content:e?.initialContent||``,onUpdate:({editor:t})=>{let n=e?.outputFormat==`text`?t.getText():t.getHTML();e?.onChange?.(n);let r=n.length;g(r),e?.onCharacterCountChange?.(r)}}),v=e?.layout===`bottom-bar`,y=e?.features||E,b={width:typeof e?.width==`number`?`${e.width}px`:e?.width||`100%`,margin:e?.margin||`0 auto`,...(()=>{if(!e?.align)return{};switch(e.align){case`left`:return{marginLeft:`0`,marginRight:`auto`};case`center`:return{marginLeft:`auto`,marginRight:`auto`};case`right`:return{marginLeft:`auto`,marginRight:`0`};default:return{}}})()};return(0,p.jsxs)(`div`,{...e?.containerProps,className:`cte-editor-container ${e?.containerProps?.className||``}`,ref:m,style:{...b,...e?.containerProps?.style},children:[e?.showTitle&&e.title&&(0,p.jsx)(`div`,{className:`cte-title-bar`,children:e.title}),!v&&(0,p.jsx)(w,{editor:_,features:y}),(0,p.jsx)(n.EditorContent,{editor:_,className:`cte-content-area`}),v&&(0,p.jsx)(w,{editor:_,features:y,className:`cte-bottom`}),e?.maxLength&&(0,p.jsxs)(`div`,{className:`cte-footer`,children:[h,` / `,e.maxLength,` characters`]})]})})});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
import { default as default_2 } from 'react';
|
|
2
2
|
|
|
3
|
-
export declare const CustomEditor: default_2.
|
|
3
|
+
export declare const CustomEditor: default_2.ForwardRefExoticComponent<{
|
|
4
4
|
config?: EditorConfig;
|
|
5
|
-
}
|
|
5
|
+
} & default_2.RefAttributes<HTMLDivElement>>;
|
|
6
6
|
|
|
7
7
|
export declare interface EditorConfig {
|
|
8
8
|
theme?: ThemeConfig;
|
|
9
9
|
layout?: 'top-bar' | 'bottom-bar';
|
|
10
10
|
width?: string | number;
|
|
11
|
+
align?: 'left' | 'center' | 'right';
|
|
12
|
+
margin?: string;
|
|
11
13
|
placeholder?: string;
|
|
12
14
|
title?: string;
|
|
13
15
|
showTitle?: boolean;
|
|
14
16
|
maxLength?: number;
|
|
15
17
|
initialContent?: string;
|
|
18
|
+
outputFormat?: 'html' | 'text';
|
|
16
19
|
onChange?: (content: string) => void;
|
|
17
20
|
onCharacterCountChange?: (count: number) => void;
|
|
18
21
|
features?: string[];
|
|
22
|
+
containerProps?: default_2.HTMLAttributes<HTMLDivElement>;
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
export declare interface ThemeConfig {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "customise-text-editor",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "A highly customizable, production-ready Rich Text Editor for React, powered by Tiptap.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/customise-text-editor.umd.js",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"@tiptap/starter-kit": "^3.22.0",
|
|
45
45
|
"clsx": "^2.1.1",
|
|
46
46
|
"lucide-react": "^1.7.0",
|
|
47
|
+
"react-hook-form": "^7.72.0",
|
|
47
48
|
"tailwind-merge": "^3.5.0"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
@@ -56,6 +57,8 @@
|
|
|
56
57
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
57
58
|
"eslint-plugin-react-refresh": "^0.5.2",
|
|
58
59
|
"globals": "^17.4.0",
|
|
60
|
+
"react": "^19.0.0",
|
|
61
|
+
"react-dom": "^19.0.0",
|
|
59
62
|
"typescript": "~5.9.3",
|
|
60
63
|
"typescript-eslint": "^8.57.0",
|
|
61
64
|
"vite": "^8.0.1",
|