tiptap-editor-custom-stg 1.0.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/README.md ADDED
@@ -0,0 +1,304 @@
1
+ # tiptap-editor-custom-stg
2
+
3
+ Custom Tiptap rich text editor with toolbar, table support, and file upload integration.
4
+
5
+ ## Features
6
+
7
+ - 📝 Rich text editing powered by Tiptap
8
+ - 🎨 Toolbar with font family, size, text/background colors
9
+ - 📊 Table support (insert, resize, merge/split cells)
10
+ - 🖼️ Image upload (click or paste screenshot)
11
+ - 📎 File attachment support
12
+ - 🔗 Link insert/edit
13
+ - 🎯 Read-only mode
14
+ - ⚡ Full TypeScript support
15
+
16
+ ---
17
+
18
+ ## For Users
19
+
20
+ ### Installation
21
+
22
+ ```bash
23
+ npm install tiptap-editor-custom-stg
24
+ ```
25
+
26
+ Then install the required peer dependencies:
27
+
28
+ ```bash
29
+ npm install react react-dom \
30
+ @tiptap/react @tiptap/core @tiptap/pm \
31
+ @tiptap/starter-kit \
32
+ @tiptap/extension-link \
33
+ @tiptap/extension-underline \
34
+ @tiptap/extension-image \
35
+ @tiptap/extension-text-style \
36
+ @tiptap/extension-color \
37
+ @tiptap/extension-font-family \
38
+ @tiptap/extension-superscript \
39
+ @tiptap/extension-subscript \
40
+ @tiptap/extension-text-align \
41
+ @tiptap/extension-placeholder \
42
+ @tiptap/extension-table \
43
+ @tiptap/extension-table-row \
44
+ @tiptap/extension-table-cell \
45
+ @tiptap/extension-table-header
46
+ ```
47
+
48
+ ### Basic Usage
49
+
50
+ ```tsx
51
+ import { TiptapEditor } from 'tiptap-editor-custom-stg';
52
+ import 'tiptap-editor-custom-stg/styles'; // required
53
+
54
+ function MyComponent() {
55
+ const [content, setContent] = React.useState('<p>Hello World!</p>');
56
+
57
+ return (
58
+ <TiptapEditor
59
+ elementId="my-editor"
60
+ content={content}
61
+ editMode={true}
62
+ docNum="DOC-001"
63
+ placeholder="Start typing..."
64
+ toolbarConfig={{
65
+ groups: ['history', 'font', 'fontSize', 'textColor', 'list', 'link', 'insert'],
66
+ showDividers: true,
67
+ }}
68
+ receiveData={(id, html) => setContent(html)}
69
+ onUploadFile={async (file, docNum) => {
70
+ const url = await uploadToYourStorage(file, docNum);
71
+ return url;
72
+ }}
73
+ onAlert={(msg) => alert(msg)}
74
+ onLoadingChange={(isLoading) => setLoading(isLoading)}
75
+ />
76
+ );
77
+ }
78
+ ```
79
+
80
+ ### Props
81
+
82
+ | Prop | Type | Required | Default | Description |
83
+ |------|------|----------|---------|-------------|
84
+ | `elementId` | `string` | ✅ | — | Unique ID for the editor instance |
85
+ | `content` | `string` | ✅ | — | HTML content |
86
+ | `editMode` | `boolean` | ✅ | — | `true` = editable, `false` = read-only |
87
+ | `docNum` | `string` | ✅ | — | Document number passed to `onUploadFile` |
88
+ | `receiveData` | `(id, html) => void` | — | — | Called on every content change |
89
+ | `receiveStatus` | `(id, loading) => void` | — | — | Called when per-editor upload status changes |
90
+ | `onUploadFile` | `(file, docNum) => Promise<string>` | — | — | Upload handler, must return the file URL |
91
+ | `onAlert` | `(message) => void` | — | `window.alert` | Custom alert/notification function |
92
+ | `onLoadingChange` | `(isLoading) => void` | — | — | Global loading state callback |
93
+ | `onRegisterReset` | `(callback) => () => void` | — | — | Register a reset callback, returns cleanup fn |
94
+ | `maxFileSizeMB` | `number` | — | `50` | Max upload file size in MB |
95
+ | `placeholder` | `string` | — | `'Start typing...'` | Editor placeholder text. This value is passed into Tiptap's `Placeholder` extension and is shown when the editor is empty |
96
+ | `toolbarConfig` | `{ groups?: ToolbarGroup[]; showDividers?: boolean }` | — | default toolbar config | Customize which toolbar groups are shown and whether dividers are rendered |
97
+
98
+ ### Styling
99
+
100
+ Styles are shipped as a separate CSS file. Import it once in your app:
101
+
102
+ ```tsx
103
+ import 'tiptap-editor-custom-stg/styles';
104
+ ```
105
+
106
+ To override default styles, target these CSS classes:
107
+
108
+ ```css
109
+ .tiptap-editor-wrapper { /* outer container */ }
110
+ .tiptap-toolbar { /* toolbar */ }
111
+ .ProseMirror { /* editor content area */ }
112
+ ```
113
+
114
+ ### Toolbar Configuration
115
+
116
+ Use `toolbarConfig` to control which toolbar groups are displayed and whether dividers appear between them.
117
+
118
+ ```tsx
119
+ <TiptapEditor
120
+ elementId="my-editor"
121
+ content={content}
122
+ editMode={true}
123
+ docNum="DOC-001"
124
+ toolbarConfig={{
125
+ groups: ['history', 'font', 'fontSize', 'textColor', 'list', 'link', 'insert'],
126
+ showDividers: true,
127
+ }}
128
+ />
129
+ ```
130
+
131
+ Available toolbar groups:
132
+
133
+ - `history`
134
+ - `font`
135
+ - `fontSize`
136
+ - `textColor`
137
+ - `highlight`
138
+ - `list`
139
+ - `alignment`
140
+ - `table`
141
+ - `inline`
142
+ - `link`
143
+ - `insert`
144
+
145
+ Default toolbar groups:
146
+
147
+ ```ts
148
+ [
149
+ 'history',
150
+ 'font',
151
+ 'fontSize',
152
+ 'textColor',
153
+ 'highlight',
154
+ 'list',
155
+ 'alignment',
156
+ 'table',
157
+ 'inline',
158
+ 'link',
159
+ 'insert',
160
+ ]
161
+ ```
162
+
163
+ Example: minimal toolbar without dividers
164
+
165
+ ```tsx
166
+ <TiptapEditor
167
+ elementId="my-editor"
168
+ content={content}
169
+ editMode={true}
170
+ docNum="DOC-001"
171
+ toolbarConfig={{
172
+ groups: ['history', 'inline', 'link'],
173
+ showDividers: false,
174
+ }}
175
+ />
176
+ ```
177
+
178
+ ### Placeholder
179
+
180
+ You can customize the empty-state placeholder text with the `placeholder` prop:
181
+
182
+ ```tsx
183
+ <TiptapEditor
184
+ elementId="my-editor"
185
+ content=""
186
+ editMode={true}
187
+ docNum="DOC-001"
188
+ placeholder="Start typing..."
189
+ />
190
+ ```
191
+
192
+ The placeholder is driven by Tiptap's `Placeholder` extension configuration, so the `placeholder` prop is the source of truth for the text shown in the editor.
193
+
194
+ ### Content Reset
195
+
196
+ Use `onRegisterReset` to let a parent component reset the editor content programmatically:
197
+
198
+ ```tsx
199
+ const resetRef = React.useRef<((content: string) => void) | null>(null);
200
+
201
+ <TiptapEditor
202
+ onRegisterReset={(callback) => {
203
+ resetRef.current = callback;
204
+ return () => { resetRef.current = null; };
205
+ }}
206
+ />
207
+
208
+ // Reset from anywhere:
209
+ resetRef.current?.('<p>New content</p>');
210
+ ```
211
+
212
+ ---
213
+
214
+ ## For Developers
215
+
216
+ ### Project Structure
217
+
218
+ ```
219
+ tiptap-editor-custom-stg/
220
+ ├── src/
221
+ │ ├── index.ts # public exports
222
+ │ ├── TiptapEditor.tsx # main component
223
+ │ ├── ToolbarGroups.tsx # toolbar sub-components
224
+ │ ├── Icons.tsx # SVG icons
225
+ │ ├── extensions.ts # Tiptap extension factory (exports createTiptapExtensions)
226
+ │ ├── fontSize.ts # custom FontSize extension
227
+ │ ├── backgroundColor.ts # custom BackgroundColor extension
228
+ │ ├── constants.ts # colors, fonts, sizes
229
+ │ ├── types.ts # TypeScript types
230
+ │ ├── utils.ts # upload helper
231
+ │ ├── tiptap.scss # editor styles
232
+ │ └── styles.d.ts # CSS type declaration
233
+ ├── dist/ # build output (generated)
234
+ ├── package.json
235
+ ├── tsconfig.json
236
+ └── tsup.config.ts
237
+ ```
238
+
239
+ ### Build
240
+
241
+ ```bash
242
+ npm install
243
+ npm run build
244
+ ```
245
+
246
+ This runs two steps:
247
+ 1. `build:js` — compiles TypeScript via tsup → `dist/index.js`, `dist/index.mjs`, `dist/index.d.ts`
248
+ 2. `build:css` — compiles SCSS via sass → `dist/index.css`, copies `dist/styles.d.ts`
249
+
250
+ ### Local Testing (without publishing)
251
+
252
+ Use `npm pack` to create a local tarball and install it directly into your project.
253
+
254
+ `npm pack` creates a local `.tgz` package archive using npm's publish rules. In practice, it lets you verify and install the same package contents that would be published to npm, without actually publishing.
255
+
256
+ For this project, because `package.json` includes `"files": ["dist"]`, the packed tarball mainly contains:
257
+
258
+ - `dist/**`
259
+ - `package.json`
260
+ - `README.md`
261
+ - `LICENSE` (if present)
262
+
263
+ So `npm pack` is not packing the entire repository by default. It is packing the publishable package contents.
264
+
265
+ ```bash
266
+ # 1. Build and pack
267
+ cd tiptap-editor-custom-stg
268
+ npm run build
269
+ npm pack
270
+ # Creates: tiptap-editor-custom-stg-1.0.0.tgz
271
+
272
+ # 2. Install into your project
273
+ cd ../your-project
274
+ npm install ../tiptap-editor-custom-stg/tiptap-editor-custom-stg-1.0.0.tgz
275
+ ```
276
+
277
+ After making code changes, rebuild and reinstall:
278
+
279
+ ```bash
280
+ cd tiptap-editor-custom-stg
281
+ npm run build && npm pack
282
+
283
+ cd ../your-project
284
+ npm install ../tiptap-editor-custom-stg/tiptap-editor-custom-stg-1.0.0.tgz --force
285
+ ```
286
+
287
+ ### Publishing to npm
288
+
289
+ ```bash
290
+ npm login
291
+ npm publish
292
+ ```
293
+
294
+ After publishing, install normally:
295
+
296
+ ```bash
297
+ npm install tiptap-editor-custom-stg
298
+ ```
299
+
300
+ ---
301
+
302
+ ## License
303
+
304
+ MIT
package/dist/index.css ADDED
@@ -0,0 +1 @@
1
+ .tiptap-editor-wrapper{border:1px solid #e5e7eb;border-radius:.75rem;overflow:hidden;font-size:15px;font-family:"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;background:#fff;box-shadow:0 1px 3px 0 rgba(0,0,0,.05),0 1px 2px -1px rgba(0,0,0,.05)}.tiptap-editor-wrapper .tiptap-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:.25rem;padding:.35rem .75rem;background:#fff;border-bottom:1px solid #f3f4f6}.tiptap-editor-wrapper .tiptap-toolbar button{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;border:none;border-radius:.375rem;background:rgba(0,0,0,0);cursor:pointer;color:#4b5563;font-size:14px;font-weight:500;transition:all .15s ease;line-height:1}.tiptap-editor-wrapper .tiptap-toolbar button:hover:not(:disabled){background:#f3f4f6;color:#111827}.tiptap-editor-wrapper .tiptap-toolbar button.is-active{background:#e5e7eb;color:#111827}.tiptap-editor-wrapper .tiptap-toolbar button:disabled{opacity:.4;cursor:not-allowed}.tiptap-editor-wrapper .tiptap-toolbar button.toolbar-button-dropdown{width:44px;padding:0 4px 0 6px;gap:2px}.tiptap-editor-wrapper .tiptap-toolbar button.toolbar-button-dropdown .dropdown-arrow{width:10px;height:10px;opacity:.6;margin-left:-1px}.tiptap-editor-wrapper .tiptap-toolbar button svg{width:18px;height:18px}.tiptap-editor-wrapper .tiptap-toolbar .toolbar-divider{width:1px;height:20px;background:#e5e7eb;margin:0 .5rem;flex-shrink:0}.tiptap-editor-wrapper .tiptap-toolbar .toolbar-select-wrapper{position:relative;display:inline-flex;align-items:center}.tiptap-editor-wrapper .tiptap-toolbar .toolbar-select{appearance:none;height:32px;border:none;border-radius:.375rem;background:rgba(0,0,0,0);font-size:14.5px;cursor:pointer;padding:0 1.5rem 0 .5rem;color:#4b5563;font-family:inherit;font-weight:500;transition:all .15s ease}.tiptap-editor-wrapper .tiptap-toolbar .toolbar-select:hover{background:#f3f4f6;color:#111827}.tiptap-editor-wrapper .tiptap-toolbar .toolbar-select:focus{outline:none;box-shadow:0 0 0 2px rgba(15,98,254,.2)}.tiptap-editor-wrapper .tiptap-toolbar .select-caret{position:absolute;right:.5rem;pointer-events:none;width:16px;height:16px;fill:#6b7280}.tiptap-editor-wrapper .tiptap-highlight-menu{position:absolute;top:110%;left:50%;transform:translateX(-50%);background:#fff;border:1px solid #e5e7eb;border-radius:9999px;padding:4px;display:flex;gap:6px;box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);z-index:100}.tiptap-editor-wrapper .tiptap-highlight-menu .color-swatch{width:18px !important;height:18px !important;min-width:18px !important;min-height:18px !important;border-radius:50% !important;border:1px solid rgba(0,0,0,.1) !important;cursor:pointer;padding:0 !important;background-color:#fff;display:flex;align-items:center;justify-content:center;transition:transform .1s ease}.tiptap-editor-wrapper .tiptap-highlight-menu .color-swatch:hover{transform:scale(1.2)}.tiptap-editor-wrapper .tiptap-highlight-menu .color-swatch.clear-swatch{background-color:rgba(0,0,0,0) !important;border:1px solid #d1d5db !important}.tiptap-editor-wrapper .tiptap-highlight-menu .color-swatch svg{width:12px;height:12px;color:#6b7280}.tiptap-editor-wrapper .tiptap-font-menu{position:absolute;top:110%;left:0;background:#fff;border:1px solid #e5e7eb;border-radius:8px;padding:4px;box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);z-index:100;min-width:180px;max-height:300px;overflow-y:auto}.tiptap-editor-wrapper .tiptap-font-menu .font-option{width:100%;text-align:left;padding:8px 12px;border-radius:4px;background:none;border:none;font-size:14px;color:#374151;cursor:pointer;transition:all .15s ease}.tiptap-editor-wrapper .tiptap-font-menu .font-option:hover:not(.is-active){background:#f3f4f6;color:#111827}.tiptap-editor-wrapper .tiptap-font-menu .font-option.is-active{background:#0062ff;color:#fff;font-weight:500}.tiptap-editor-wrapper .tiptap-heading-menu{position:absolute;top:110%;left:0;background:#fff;border:1px solid #e5e7eb;border-radius:8px;padding:4px;box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);z-index:100;min-width:140px}.tiptap-editor-wrapper .tiptap-heading-menu .heading-option{width:100%;text-align:left;padding:6px 12px;border-radius:4px;background:none;border:none;font-size:14px;color:#374151;cursor:pointer;transition:all .15s ease}.tiptap-editor-wrapper .tiptap-heading-menu .heading-option:hover{background:#f3f4f6;color:#111827}.tiptap-editor-wrapper .tiptap-heading-menu .heading-option.is-active{background:#eff6ff;color:#2563eb;font-weight:600}.tiptap-editor-wrapper .tiptap-heading-menu .heading-option.h1{font-size:1.35rem;font-weight:700}.tiptap-editor-wrapper .tiptap-heading-menu .heading-option.h2{font-size:1.25rem;font-weight:600}.tiptap-editor-wrapper .tiptap-heading-menu .heading-option.h3{font-size:1.15rem;font-weight:600}.tiptap-editor-wrapper .tiptap-heading-menu .heading-option.h4{font-size:1.05rem;font-weight:600}.tiptap-editor-wrapper .tiptap-heading-menu .heading-option.h5{font-size:1rem;font-weight:600}.tiptap-editor-wrapper .tiptap-heading-menu .heading-option.h6{font-size:.9rem;font-weight:600}.tiptap-editor-wrapper .tiptap-color-picker{position:absolute;top:110%;left:50%;transform:translateX(-50%);background:#fff;border:1px solid #e5e7eb;border-radius:10px;padding:10px;box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);z-index:100;width:160px}.tiptap-editor-wrapper .tiptap-color-picker .color-remove-btn{width:100%;display:flex;align-items:center;justify-content:center;gap:8px;padding:8px;margin-bottom:8px;background:#fdfdfd;border:1px solid #e5e7eb;border-radius:6px;font-size:13px;color:#4b5563;cursor:pointer;transition:all .15s ease}.tiptap-editor-wrapper .tiptap-color-picker .color-remove-btn:hover{background:#f3f4f6;border-color:#d1d5db;color:#111827}.tiptap-editor-wrapper .tiptap-color-picker .color-remove-btn svg{width:14px;height:14px}.tiptap-editor-wrapper .tiptap-color-picker .color-grid{display:grid;grid-template-columns:repeat(5, 1fr);gap:4px}.tiptap-editor-wrapper .tiptap-color-picker .color-grid .color-swatch{width:24px !important;height:24px !important;min-width:24px !important;min-height:24px !important;border-radius:4px !important;border:1px solid rgba(0,0,0,.08) !important;padding:0 !important;cursor:pointer;transition:transform .15s ease,border-color .15s ease}.tiptap-editor-wrapper .tiptap-color-picker .color-grid .color-swatch:hover{transform:scale(1.15);border-color:rgba(0,0,0,.2) !important;z-index:2}.tiptap-editor-wrapper .tiptap-link-menu{position:absolute;top:110%;left:50%;transform:translateX(-50%);background:#fff;border:1px solid #e5e7eb;border-radius:8px;padding:4px;display:flex;align-items:center;gap:2px;box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);z-index:100;width:300px}.tiptap-editor-wrapper .tiptap-link-menu input{flex:1;border:1px solid #d1d5db;border-radius:4px;padding:4px 8px;font-size:14px;outline:none;transition:border-color .15s ease}.tiptap-editor-wrapper .tiptap-link-menu input:focus{border-color:#3b82f6;box-shadow:0 0 0 1px #3b82f6}.tiptap-editor-wrapper .tiptap-link-menu button{width:28px !important;height:28px !important;padding:0 !important;min-width:28px !important;border-radius:4px !important;display:flex;align-items:center;justify-content:center}.tiptap-editor-wrapper .tiptap-link-menu button svg{width:14px;height:14px}.tiptap-editor-wrapper .tiptap-link-menu button.link-submit-btn{color:#22c55e}.tiptap-editor-wrapper .tiptap-link-menu button.link-submit-btn:hover{background:#dcfce7}.tiptap-editor-wrapper .tiptap-link-menu button.link-clear-btn{color:#ef4444}.tiptap-editor-wrapper .tiptap-link-menu button.link-clear-btn:hover{background:#fee2e2}.tiptap-editor-wrapper .tiptap-table-menu{position:absolute;top:110%;left:0;background:#fff;border:1px solid #e5e7eb;border-radius:8px;padding:8px;box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);z-index:100;min-width:200px}.tiptap-editor-wrapper .tiptap-table-menu .table-grid-picker-wrapper{padding:4px;background:#fff}.tiptap-editor-wrapper .tiptap-table-menu .table-grid-picker-wrapper .table-grid-picker{display:flex;flex-direction:column;gap:2px;padding-bottom:8px}.tiptap-editor-wrapper .tiptap-table-menu .table-grid-picker-wrapper .grid-row{display:flex;gap:2px}.tiptap-editor-wrapper .tiptap-table-menu .table-grid-picker-wrapper .grid-cell{width:16px;height:16px;border:1px solid #d1d5db;border-radius:1px;cursor:pointer;transition:background-color .1s,border-color .1s}.tiptap-editor-wrapper .tiptap-table-menu .table-grid-picker-wrapper .grid-cell:hover{border-color:#3b82f6}.tiptap-editor-wrapper .tiptap-table-menu .table-grid-picker-wrapper .grid-cell.is-active{background-color:#bfdbfe;border-color:#3b82f6}.tiptap-editor-wrapper .tiptap-table-menu .table-grid-picker-wrapper .table-grid-label{text-align:center;font-size:13px;color:#4b5563;font-weight:500;border-top:1px solid #f3f4f6;padding-top:8px;margin-top:2px}.tiptap-editor-wrapper .tiptap-table-menu .table-menu-item{width:100%;display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:4px;background:none;border:none;font-size:13px;color:#374151;transition:background .15s ease;white-space:nowrap;cursor:pointer}.tiptap-editor-wrapper .tiptap-table-menu .table-menu-item:hover{background:#f3f4f6}.tiptap-editor-wrapper .tiptap-table-menu .table-menu-item svg{width:16px;height:16px;color:#6b7280}.tiptap-editor-wrapper .tiptap-table-menu .table-menu-grid{display:grid;grid-template-columns:repeat(3, 1fr);gap:6px}.tiptap-editor-wrapper .tiptap-table-menu .table-menu-grid button{width:32px !important;height:32px !important;padding:0 !important;min-width:32px !important;display:flex;align-items:center;justify-content:center;border-radius:4px;background:#f9fafb !important;border:1px solid #e5e7eb !important;color:#4b5563 !important;cursor:pointer}.tiptap-editor-wrapper .tiptap-table-menu .table-menu-grid button:hover{background:#f3f4f6 !important;border-color:#d1d5db !important}.tiptap-editor-wrapper .tiptap-table-menu .table-menu-grid button.danger{color:#ef4444 !important}.tiptap-editor-wrapper .tiptap-table-menu .table-menu-grid button.danger:hover{background:#fee2e2 !important;border-color:#fca5a5 !important}.tiptap-editor-wrapper .tiptap-table-menu .table-menu-grid button svg{width:16px;height:16px}.tiptap-editor-wrapper .ProseMirror{min-height:300px;padding:1.5rem;color:#1f2937;outline:none;line-height:1.7}.tiptap-editor-wrapper .ProseMirror p.is-editor-empty:first-child::before{color:#9ca3af;content:attr(data-placeholder);float:left;height:0;pointer-events:none}.tiptap-editor-wrapper .ProseMirror h1,.tiptap-editor-wrapper .ProseMirror h2,.tiptap-editor-wrapper .ProseMirror h3,.tiptap-editor-wrapper .ProseMirror h4{line-height:1.2;color:#111827}.tiptap-editor-wrapper .ProseMirror h1{font-size:2.25rem;font-weight:700;margin:1em 0 .5em}.tiptap-editor-wrapper .ProseMirror h2{font-size:1.875rem;font-weight:600;margin:1em 0 .5em}.tiptap-editor-wrapper .ProseMirror h3{font-size:1.5rem;font-weight:600;margin:1em 0 .5em}.tiptap-editor-wrapper .ProseMirror h4{font-size:1.25rem;font-weight:600;margin:1em 0 .5em}.tiptap-editor-wrapper .ProseMirror [style*="font-size: 0.7em"],.tiptap-editor-wrapper .ProseMirror .text-tiny{font-size:.7em}.tiptap-editor-wrapper .ProseMirror [style*="font-size: 0.85em"],.tiptap-editor-wrapper .ProseMirror .text-small{font-size:.85em}.tiptap-editor-wrapper .ProseMirror [style*="font-size: 1.4em"],.tiptap-editor-wrapper .ProseMirror .text-big{font-size:1.4em}.tiptap-editor-wrapper .ProseMirror [style*="font-size: 1.8em"],.tiptap-editor-wrapper .ProseMirror .text-huge{font-size:1.8em}.tiptap-editor-wrapper .ProseMirror p{margin:.5em 0}.tiptap-editor-wrapper .ProseMirror ul{list-style-type:disc;padding-left:1.5rem;margin:.5em 0}.tiptap-editor-wrapper .ProseMirror ol{list-style-type:decimal;padding-left:1.5rem;margin:.5em 0}.tiptap-editor-wrapper .ProseMirror blockquote{border-left:4px solid #e5e7eb;padding-left:1rem;margin:1em 0;color:#4b5563;font-style:italic}.tiptap-editor-wrapper .ProseMirror code{background:#f3f4f6;border-radius:4px;padding:.2rem .4rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:.875em}.tiptap-editor-wrapper .ProseMirror pre{background:#111827;color:#f3f4f6;border-radius:.5rem;padding:1rem;overflow-x:auto;margin:1em 0}.tiptap-editor-wrapper .ProseMirror pre code{background:none;padding:0;color:inherit}.tiptap-editor-wrapper .ProseMirror img{max-width:100%;height:auto;display:block;margin:1rem 0;border-radius:.375rem;box-shadow:0 1px 3px 0 rgba(0,0,0,.1)}.tiptap-editor-wrapper .ProseMirror a{color:#2563eb;text-decoration:underline;text-underline-offset:2px;font-weight:500;cursor:pointer}.tiptap-editor-wrapper .ProseMirror a:hover{color:#1d4ed8}.tiptap-editor-wrapper .ProseMirror a[data-attachment=true]{display:inline-flex;align-items:center;gap:.375rem;padding:.25rem .6rem;background:#f3f4f6;border:1px solid #e5e7eb;border-radius:.375rem;font-size:14px;text-decoration:none;color:#111827;font-weight:500;transition:all .15s ease}.tiptap-editor-wrapper .ProseMirror a[data-attachment=true]::before{content:"📎";font-size:13px;opacity:.7}.tiptap-editor-wrapper .ProseMirror a[data-attachment=true]:hover{background:#e5e7eb;border-color:#d1d5db}.tiptap-editor-wrapper .ProseMirror mark{background-color:#fde047;border-radius:.125rem;padding:.125rem .25rem;color:#854d0e}.tiptap-editor-wrapper .ProseMirror sup{vertical-align:super;font-size:.75em}.tiptap-editor-wrapper .ProseMirror sub{vertical-align:sub;font-size:.75em}.tiptap-editor-wrapper .ProseMirror table{border-collapse:collapse;table-layout:fixed;width:100%;margin:1.5rem 0;overflow:hidden}.tiptap-editor-wrapper .ProseMirror table td,.tiptap-editor-wrapper .ProseMirror table th{min-width:1em;border:1px solid #ced4da;padding:8px 12px;vertical-align:top;box-sizing:border-box;position:relative}.tiptap-editor-wrapper .ProseMirror table td>*,.tiptap-editor-wrapper .ProseMirror table th>*{margin-bottom:0}.tiptap-editor-wrapper .ProseMirror table th{font-weight:bold;text-align:left;background-color:#f8f9fa}.tiptap-editor-wrapper .ProseMirror table .selectedCell:after{z-index:2;position:absolute;content:"";left:0;right:0;top:0;bottom:0;background:rgba(200,200,255,.4);pointer-events:none}.tiptap-editor-wrapper .ProseMirror table .column-resize-handle{position:absolute;right:-2px;top:0;bottom:-2px;width:4px;background-color:#adf;pointer-events:none}.tiptap-editor-wrapper .ProseMirror .tableWrapper{overflow-x:auto;margin:1.5rem 0}.tiptap-editor-wrapper.read-only .tiptap-toolbar{background:#f3f3f3;pointer-events:none}.tiptap-editor-wrapper.read-only .tiptap-toolbar button,.tiptap-editor-wrapper.read-only .tiptap-toolbar .toolbar-select{opacity:.5;filter:grayscale(1)}.tiptap-editor-wrapper.read-only .ProseMirror{background:#f3f3f3;color:#6b7280;cursor:default;min-height:100px}.tiptap-editor-wrapper .tiptap-toolbar.toolbar-disabled{background:#f3f3f3;border-bottom-color:#e5e7eb}.tiptap-editor-wrapper .tiptap-toolbar.toolbar-disabled *{cursor:not-allowed !important}.tiptap-editor-wrapper .tiptap-loading-bar{height:3px;background:linear-gradient(90deg, #0f62fe 0%, #4589ff 50%, #0f62fe 100%);background-size:200% 100%;animation:tiptap-loading-anim 1.2s linear infinite;border-radius:0}@keyframes tiptap-loading-anim{0%{background-position:200% 0}100%{background-position:-200% 0}}.tiptap-hidden-input{display:none !important}
@@ -0,0 +1,79 @@
1
+ import React from 'react';
2
+ import * as _tiptap_extension_table_row from '@tiptap/extension-table-row';
3
+ import * as _tiptap_extension_underline from '@tiptap/extension-underline';
4
+ import * as _tiptap_core from '@tiptap/core';
5
+ import { Extension } from '@tiptap/core';
6
+
7
+ type ToolbarGroup = 'history' | 'font' | 'fontSize' | 'textColor' | 'highlight' | 'list' | 'alignment' | 'table' | 'inline' | 'link' | 'insert';
8
+ interface ToolbarConfig {
9
+ groups?: ToolbarGroup[];
10
+ showDividers?: boolean;
11
+ }
12
+ interface TiptapEditorProps {
13
+ elementId: string;
14
+ content: string;
15
+ editMode: boolean;
16
+ docNum: string;
17
+ receiveData?: (elementId: string, data: string) => void;
18
+ receiveStatus?: (elementId: string, data: boolean) => void;
19
+ /** Actual file upload function. Returns the uploaded file URL. */
20
+ onUploadFile?: (file: File, docNum: string) => Promise<string>;
21
+ /** Custom alert/notification function (defaults to window.alert) */
22
+ onAlert?: (message: string) => void;
23
+ /** Callback for external loading state changes */
24
+ onLoadingChange?: (isLoading: boolean) => void;
25
+ /** Register a content reset callback */
26
+ onRegisterReset?: (resetCallback: (newContent: string) => void) => (() => void);
27
+ maxFileSizeMB?: number;
28
+ placeholder?: string;
29
+ toolbarConfig?: ToolbarConfig;
30
+ }
31
+
32
+ declare const TiptapEditor: React.FC<TiptapEditorProps>;
33
+
34
+ declare const createTiptapExtensions: (placeholder?: string) => (_tiptap_core.Extension<any, any> | _tiptap_core.Mark<_tiptap_extension_underline.UnderlineOptions, any> | _tiptap_core.Node<_tiptap_extension_table_row.TableRowOptions, any>)[];
35
+
36
+ declare module '@tiptap/core' {
37
+ interface Commands<ReturnType> {
38
+ fontSize: {
39
+ /**
40
+ * Set the font size
41
+ */
42
+ setFontSize: (size: string) => ReturnType;
43
+ /**
44
+ * Unset the font size
45
+ */
46
+ unsetFontSize: () => ReturnType;
47
+ };
48
+ }
49
+ }
50
+ declare const FontSize: Extension<any, any>;
51
+
52
+ declare module '@tiptap/core' {
53
+ interface Commands<ReturnType> {
54
+ backgroundColor: {
55
+ /**
56
+ * Set the background color
57
+ */
58
+ setBackgroundColor: (color: string) => ReturnType;
59
+ /**
60
+ * Unset the background color
61
+ */
62
+ unsetBackgroundColor: () => ReturnType;
63
+ };
64
+ }
65
+ }
66
+ declare const BackgroundColor: Extension<any, any>;
67
+
68
+ declare const TIPTAP_COLORS: string[];
69
+ declare const FONT_FAMILIES: {
70
+ label: string;
71
+ value: string;
72
+ }[];
73
+ declare const FONT_SIZES: {
74
+ label: string;
75
+ value: string;
76
+ }[];
77
+ declare const IMAGE_MIME_TYPES: string[];
78
+
79
+ export { BackgroundColor, FONT_FAMILIES, FONT_SIZES, FontSize, IMAGE_MIME_TYPES, TIPTAP_COLORS, TiptapEditor, type TiptapEditorProps, createTiptapExtensions };
@@ -0,0 +1,79 @@
1
+ import React from 'react';
2
+ import * as _tiptap_extension_table_row from '@tiptap/extension-table-row';
3
+ import * as _tiptap_extension_underline from '@tiptap/extension-underline';
4
+ import * as _tiptap_core from '@tiptap/core';
5
+ import { Extension } from '@tiptap/core';
6
+
7
+ type ToolbarGroup = 'history' | 'font' | 'fontSize' | 'textColor' | 'highlight' | 'list' | 'alignment' | 'table' | 'inline' | 'link' | 'insert';
8
+ interface ToolbarConfig {
9
+ groups?: ToolbarGroup[];
10
+ showDividers?: boolean;
11
+ }
12
+ interface TiptapEditorProps {
13
+ elementId: string;
14
+ content: string;
15
+ editMode: boolean;
16
+ docNum: string;
17
+ receiveData?: (elementId: string, data: string) => void;
18
+ receiveStatus?: (elementId: string, data: boolean) => void;
19
+ /** Actual file upload function. Returns the uploaded file URL. */
20
+ onUploadFile?: (file: File, docNum: string) => Promise<string>;
21
+ /** Custom alert/notification function (defaults to window.alert) */
22
+ onAlert?: (message: string) => void;
23
+ /** Callback for external loading state changes */
24
+ onLoadingChange?: (isLoading: boolean) => void;
25
+ /** Register a content reset callback */
26
+ onRegisterReset?: (resetCallback: (newContent: string) => void) => (() => void);
27
+ maxFileSizeMB?: number;
28
+ placeholder?: string;
29
+ toolbarConfig?: ToolbarConfig;
30
+ }
31
+
32
+ declare const TiptapEditor: React.FC<TiptapEditorProps>;
33
+
34
+ declare const createTiptapExtensions: (placeholder?: string) => (_tiptap_core.Extension<any, any> | _tiptap_core.Mark<_tiptap_extension_underline.UnderlineOptions, any> | _tiptap_core.Node<_tiptap_extension_table_row.TableRowOptions, any>)[];
35
+
36
+ declare module '@tiptap/core' {
37
+ interface Commands<ReturnType> {
38
+ fontSize: {
39
+ /**
40
+ * Set the font size
41
+ */
42
+ setFontSize: (size: string) => ReturnType;
43
+ /**
44
+ * Unset the font size
45
+ */
46
+ unsetFontSize: () => ReturnType;
47
+ };
48
+ }
49
+ }
50
+ declare const FontSize: Extension<any, any>;
51
+
52
+ declare module '@tiptap/core' {
53
+ interface Commands<ReturnType> {
54
+ backgroundColor: {
55
+ /**
56
+ * Set the background color
57
+ */
58
+ setBackgroundColor: (color: string) => ReturnType;
59
+ /**
60
+ * Unset the background color
61
+ */
62
+ unsetBackgroundColor: () => ReturnType;
63
+ };
64
+ }
65
+ }
66
+ declare const BackgroundColor: Extension<any, any>;
67
+
68
+ declare const TIPTAP_COLORS: string[];
69
+ declare const FONT_FAMILIES: {
70
+ label: string;
71
+ value: string;
72
+ }[];
73
+ declare const FONT_SIZES: {
74
+ label: string;
75
+ value: string;
76
+ }[];
77
+ declare const IMAGE_MIME_TYPES: string[];
78
+
79
+ export { BackgroundColor, FONT_FAMILIES, FONT_SIZES, FontSize, IMAGE_MIME_TYPES, TIPTAP_COLORS, TiptapEditor, type TiptapEditorProps, createTiptapExtensions };