@voilabs/mark 0.0.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.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +728 -0
  3. package/dist/components/Editor.d.ts +31 -0
  4. package/dist/components/Editor.d.ts.map +1 -0
  5. package/dist/components/editor/EditorContext.d.ts +16 -0
  6. package/dist/components/editor/EditorContext.d.ts.map +1 -0
  7. package/dist/components/editor/GlobalDragHandleMenu.d.ts +8 -0
  8. package/dist/components/editor/GlobalDragHandleMenu.d.ts.map +1 -0
  9. package/dist/components/editor/StyleBar.d.ts +26 -0
  10. package/dist/components/editor/StyleBar.d.ts.map +1 -0
  11. package/dist/components/editor/StyleEditPopover.d.ts +19 -0
  12. package/dist/components/editor/StyleEditPopover.d.ts.map +1 -0
  13. package/dist/components/editor/Toolbar.d.ts +21 -0
  14. package/dist/components/editor/Toolbar.d.ts.map +1 -0
  15. package/dist/components/editor/classNames.d.ts +136 -0
  16. package/dist/components/editor/classNames.d.ts.map +1 -0
  17. package/dist/components/editor/extensions/AdvancedImage.d.ts +22 -0
  18. package/dist/components/editor/extensions/AdvancedImage.d.ts.map +1 -0
  19. package/dist/components/editor/extensions/FontFamily.d.ts +14 -0
  20. package/dist/components/editor/extensions/FontFamily.d.ts.map +1 -0
  21. package/dist/components/editor/extensions/FontSize.d.ts +14 -0
  22. package/dist/components/editor/extensions/FontSize.d.ts.map +1 -0
  23. package/dist/components/editor/extensions/ImageNodeView.d.ts +2 -0
  24. package/dist/components/editor/extensions/ImageNodeView.d.ts.map +1 -0
  25. package/dist/components/editor/extensions/TextStyleAttributes.d.ts +10 -0
  26. package/dist/components/editor/extensions/TextStyleAttributes.d.ts.map +1 -0
  27. package/dist/components/editor/extensions/Video.d.ts +21 -0
  28. package/dist/components/editor/extensions/Video.d.ts.map +1 -0
  29. package/dist/components/editor/paragraphStyles.d.ts +42 -0
  30. package/dist/components/editor/paragraphStyles.d.ts.map +1 -0
  31. package/dist/components/editor/slash-command/commands-list.d.ts +27 -0
  32. package/dist/components/editor/slash-command/commands-list.d.ts.map +1 -0
  33. package/dist/components/editor/slash-command/commands.d.ts +15 -0
  34. package/dist/components/editor/slash-command/commands.d.ts.map +1 -0
  35. package/dist/components/editor/slash-command/suggestion.d.ts +38 -0
  36. package/dist/components/editor/slash-command/suggestion.d.ts.map +1 -0
  37. package/dist/components/editor/translations.d.ts +151 -0
  38. package/dist/components/editor/translations.d.ts.map +1 -0
  39. package/dist/components/editor/useStyleStorage.d.ts +19 -0
  40. package/dist/components/editor/useStyleStorage.d.ts.map +1 -0
  41. package/dist/components/editor/utils/upload.d.ts +5 -0
  42. package/dist/components/editor/utils/upload.d.ts.map +1 -0
  43. package/dist/components/ui/Dropdown.d.ts +16 -0
  44. package/dist/components/ui/Dropdown.d.ts.map +1 -0
  45. package/dist/components/ui/DropdownMenu.d.ts +28 -0
  46. package/dist/components/ui/DropdownMenu.d.ts.map +1 -0
  47. package/dist/components/ui/Popover.d.ts +11 -0
  48. package/dist/components/ui/Popover.d.ts.map +1 -0
  49. package/dist/components/ui/Tooltip.d.ts +7 -0
  50. package/dist/components/ui/Tooltip.d.ts.map +1 -0
  51. package/dist/index.cjs.js +151 -0
  52. package/dist/index.d.ts +7 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.es.js +22724 -0
  55. package/dist/lib/utils.d.ts +3 -0
  56. package/dist/lib/utils.d.ts.map +1 -0
  57. package/dist/plugin.cjs.js +10 -0
  58. package/dist/plugin.d.ts +4 -0
  59. package/dist/plugin.d.ts.map +1 -0
  60. package/dist/plugin.es.js +575 -0
  61. package/dist/translations/en-US.cjs.js +1 -0
  62. package/dist/translations/en-US.d.ts +4 -0
  63. package/dist/translations/en-US.d.ts.map +1 -0
  64. package/dist/translations/en-US.es.js +153 -0
  65. package/dist/translations/tr-TR.cjs.js +1 -0
  66. package/dist/translations/tr-TR.d.ts +4 -0
  67. package/dist/translations/tr-TR.d.ts.map +1 -0
  68. package/dist/translations/tr-TR.es.js +153 -0
  69. package/package.json +121 -0
package/README.md ADDED
@@ -0,0 +1,728 @@
1
+ # @voilabs/mark
2
+
3
+ A modern React rich text editor library built on top of Tiptap, Tailwind CSS, Radix UI, and TypeScript.
4
+
5
+ It is designed as a reusable package rather than a demo application, and ships a polished editing shell with a formatting toolbar, slash commands, media support, paragraph styles, theme switching, translations, and a Tailwind integration helper.
6
+
7
+ ## Table of Contents
8
+
9
+ - [Overview](#overview)
10
+ - [Quick Start](#quick-start)
11
+ - [Highlights](#highlights)
12
+ - [Prerequisites](#prerequisites)
13
+ - [Installation](#installation)
14
+ - [Tailwind Integration](#tailwind-integration)
15
+ - [API Reference](#api-reference)
16
+ - [Development Workflow](#development-workflow)
17
+ - [Build and Distribution](#build-and-distribution)
18
+ - [Dependency Management](#dependency-management)
19
+ - [Architecture](#architecture)
20
+ - [Project Structure](#project-structure)
21
+ - [Tech Stack and Dependencies](#tech-stack-and-dependencies)
22
+ - [Contributing](#contributing)
23
+ - [License](#license)
24
+
25
+ ## Overview
26
+
27
+ `@voilabs/mark` is a library-first editor package that exposes a ready-to-use `Editor` component and several supporting exports for advanced integration scenarios.
28
+
29
+ The package focuses on:
30
+
31
+ - rich text authoring with Tiptap
32
+ - consistent, modern UI primitives using Radix UI
33
+ - Tailwind-friendly styling and host-project theming
34
+ - configurable typography and named paragraph styles
35
+ - image and video insertion workflows
36
+ - English and Turkish localization support
37
+ - distribution as a typed library with multiple entry points
38
+
39
+ The editor accepts initial content as HTML or Markdown, can auto-detect the incoming format, and emits content updates as Markdown through `onChange`.
40
+
41
+ ## Quick Start
42
+
43
+ ```ts
44
+ import { Editor } from "@voilabs/mark";
45
+ ```
46
+
47
+ ### Basic Usage
48
+
49
+ ```tsx
50
+ import { useState } from "react";
51
+ import { Editor } from "@voilabs/mark";
52
+ import translations from "@voilabs/mark/translations/en-US";
53
+
54
+ export function ArticleEditor() {
55
+ const [value, setValue] = useState("# Hello world");
56
+
57
+ return (
58
+ <Editor
59
+ value={value}
60
+ format="auto"
61
+ theme="auto"
62
+ translations={translations}
63
+ onChange={setValue}
64
+ />
65
+ );
66
+ }
67
+ ```
68
+
69
+ ### With Upload Support
70
+
71
+ ```tsx
72
+ import { Editor } from "@voilabs/mark";
73
+
74
+ async function uploadFile(file: File): Promise<{ url: string }> {
75
+ const formData = new FormData();
76
+ formData.append("file", file);
77
+
78
+ const response = await fetch("/api/upload", {
79
+ method: "POST",
80
+ body: formData,
81
+ });
82
+
83
+ if (!response.ok) {
84
+ throw new Error("Upload failed");
85
+ }
86
+
87
+ return response.json();
88
+ }
89
+
90
+ export function MediaEnabledEditor() {
91
+ return (
92
+ <Editor
93
+ value="Start writing..."
94
+ onUpload={uploadFile}
95
+ onChange={(markdown) => {
96
+ console.log(markdown);
97
+ }}
98
+ />
99
+ );
100
+ }
101
+ ```
102
+
103
+ ### With Custom Paragraph Styles
104
+
105
+ ```tsx
106
+ import {
107
+ Editor,
108
+ DEFAULT_PARAGRAPH_STYLES,
109
+ type ParagraphStyle,
110
+ } from "@voilabs/mark";
111
+
112
+ const customStyles: ParagraphStyle[] = [
113
+ ...DEFAULT_PARAGRAPH_STYLES,
114
+ {
115
+ id: "callout",
116
+ label: "Callout",
117
+ preview: "Callout",
118
+ type: "blockquote",
119
+ fontSize: "18px",
120
+ fontWeight: "600",
121
+ color: "#0f172a",
122
+ },
123
+ ];
124
+
125
+ export function StyledEditor() {
126
+ return <Editor styles={customStyles} />;
127
+ }
128
+ ```
129
+
130
+ ### With Translation Overrides
131
+
132
+ ```tsx
133
+ import { Editor } from "@voilabs/mark";
134
+ import trTR from "@voilabs/mark/translations/tr-TR";
135
+
136
+ export function TurkishEditor() {
137
+ return (
138
+ <Editor
139
+ translations={{
140
+ ...trTR,
141
+ placeholder: "Yazmaya baslayin",
142
+ }}
143
+ />
144
+ );
145
+ }
146
+ ```
147
+
148
+ ## Highlights
149
+
150
+ ### Editing Experience
151
+
152
+ - Toolbar with undo/redo, headings, lists, quote, code block, inline marks, text alignment, links, highlight colors, font family, and font size controls
153
+ - Slash command menu triggered by `/` for quick insertion of text blocks, headings, lists, images, tables, quotes, and code blocks
154
+ - Word count footer with zoom controls and fullscreen toggle
155
+ - Global drag handle for block insertion, duplication, reordering, anchor-link copying, color actions, and deletion
156
+
157
+ ### Media Support
158
+
159
+ - Custom image node implementation with resize handles, crop mode, rotation, object-fit frame mode, pan controls, upload state, and alt text editing
160
+ - Video node support for uploaded video insertion
161
+ - Drag-and-drop and paste image upload handling when an `onUpload` callback is provided
162
+ - Slash-command image insertion with file picker support or URL prompt fallback
163
+
164
+ ### Styling and Customization
165
+
166
+ - Tailwind-based UI with overridable class slots via `EditorClassNames`
167
+ - Built-in light and dark themes with persisted theme preference in cookie/localStorage when `theme="auto"`
168
+ - Named paragraph styles with a Word-like quick style gallery
169
+ - Right-click style editing with local persistence in `localStorage`
170
+ - Translation override support through `translations`
171
+
172
+ ### Packaging
173
+
174
+ - Typed library output generated by Vite and `vite-plugin-dts`
175
+ - ESM, UMD, and declaration outputs under `dist`
176
+
177
+ ## Prerequisites
178
+
179
+ Before using or developing this package, make sure you have:
180
+
181
+ - Node.js 20 or newer recommended
182
+ - npm 10 or newer recommended
183
+ - a React application using React 19
184
+ - TypeScript 5 if you want full type support
185
+
186
+ If you plan to use the Tailwind helper export, your host application should also be configured for Tailwind CSS.
187
+
188
+ ## Installation
189
+
190
+ ### Library Consumers
191
+
192
+ Install the package and its peer dependencies:
193
+
194
+ ```bash
195
+ npm install @voilabs/mark react react-dom typescript
196
+ ```
197
+
198
+ ### Tailwind Plugin Consumers
199
+
200
+ If you use the exported Tailwind plugin helper, also ensure your project has the typography plugin available:
201
+
202
+ ```bash
203
+ npm install @tailwindcss/typography
204
+ ```
205
+
206
+ ### Repository Setup
207
+
208
+ To work on the library itself:
209
+
210
+ ```bash
211
+ bun install
212
+ ```
213
+
214
+ ## Tailwind Integration
215
+
216
+ The editor UI is built with Tailwind utility classes. In host projects, the package export `@voilabs/mark/plugin` can help Tailwind discover the library's compiled class usage.
217
+
218
+ Example configuration:
219
+
220
+ ```ts
221
+ import editorTailwindPlugin from "@voilabs/mark/plugin";
222
+
223
+ export default {
224
+ plugins: [editorTailwindPlugin],
225
+ };
226
+ ```
227
+
228
+ What the plugin does:
229
+
230
+ - resolves the installed package path
231
+ - points Tailwind content scanning to the package `dist` files
232
+ - enables `tailwindcss-animate`
233
+ - enables `@tailwindcss/typography`
234
+
235
+ ## API Reference
236
+
237
+ ### `Editor`
238
+
239
+ ```ts
240
+ import { Editor } from "@voilabs/mark";
241
+ ```
242
+
243
+ ### `EditorProps`
244
+
245
+ | Prop | Type | Description |
246
+ | -------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------ |
247
+ | `value` | `string` | Initial editor content. Supports HTML or Markdown depending on `format`. |
248
+ | `onChange` | `(value: string) => void` | Receives Markdown output whenever the editor updates. |
249
+ | `format` | `"html" \| "markdown" \| "auto"` | Controls how the initial value is interpreted. `auto` detects Markdown-like input. |
250
+ | `theme` | `"light" \| "dark" \| "auto"` | Forces a theme or enables persisted user switching. |
251
+ | `onUpload` | `(file: File) => Promise<{ url: string }>` | Upload handler used by toolbar uploads, slash-command image insertion, paste uploads, and drag/drop uploads. |
252
+ | `disableVideoUpload` | `boolean` | Disables video upload actions in the toolbar. |
253
+ | `disableImageUpload` | `boolean` | Disables image upload actions and image upload-driven insertion flows. |
254
+ | `classNames` | `EditorClassNames` | Fine-grained class slot overrides for editor shell, toolbar, menus, footer, drag handle, and image UI. |
255
+ | `translations` | `Partial<EditorTranslations>` | Partial translation override merged over built-in English strings. |
256
+ | `styles` | `ParagraphStyle[]` | Replaces the default quick style set shown in the toolbar style gallery. |
257
+
258
+ ### `ParagraphStyle`
259
+
260
+ Each paragraph style can define:
261
+
262
+ - `id`
263
+ - `label`
264
+ - `preview`
265
+ - `type`
266
+ - `level`
267
+ - `fontFamily`
268
+ - `fontSize`
269
+ - `fontWeight`
270
+ - `fontStyle`
271
+ - `color`
272
+ - `letterSpacing`
273
+ - `lineHeight`
274
+ - `textTransform`
275
+
276
+ ### `EditorClassNames`
277
+
278
+ `EditorClassNames` exposes slot-level styling hooks for nearly every visible part of the editor.
279
+
280
+ ### Shell and Content Slots
281
+
282
+ | Slot | Purpose |
283
+ | ----------------- | ------------------------------ |
284
+ | `root` | Outer editor wrapper |
285
+ | `content` | Main scrollable content region |
286
+ | `contentScroller` | Content scrolling container |
287
+ | `contentInner` | Inner centered content wrapper |
288
+ | `editorContent` | `EditorContent` host container |
289
+ | `prose` | Tiptap prose typography layer |
290
+
291
+ ### Footer Slots
292
+
293
+ | Slot | Purpose |
294
+ | ------------------------ | ------------------------------------ |
295
+ | `footer` | Footer root container |
296
+ | `footerWordCount` | Word count label area |
297
+ | `footerControls` | Footer controls wrapper |
298
+ | `footerButton` | Shared footer button styling |
299
+ | `footerButtonDisabled` | Disabled footer button state |
300
+ | `footerZoomGroup` | Zoom controls group |
301
+ | `footerZoomButton` | Zoom increment and decrement buttons |
302
+ | `footerZoomValue` | Zoom percentage button |
303
+ | `footerFullscreenButton` | Fullscreen toggle button |
304
+
305
+ ### Toolbar Slots
306
+
307
+ | Slot | Purpose |
308
+ | ----------------------- | -------------------------------- |
309
+ | `toolbar` | Toolbar root container |
310
+ | `toolbarInner` | Toolbar scroll container |
311
+ | `toolbarGroup` | Toolbar button group wrapper |
312
+ | `toolbarButton` | Shared toolbar button styling |
313
+ | `toolbarButtonActive` | Active toolbar button state |
314
+ | `toolbarButtonDisabled` | Disabled toolbar button state |
315
+ | `toolbarButtonIcon` | Toolbar button icon wrapper |
316
+ | `toolbarTrigger` | Dropdown trigger buttons |
317
+ | `toolbarTriggerActive` | Active dropdown trigger state |
318
+ | `toolbarTriggerIcon` | Dropdown trigger icon wrapper |
319
+ | `toolbarTriggerLabel` | Dropdown trigger label text |
320
+ | `toolbarTriggerChevron` | Dropdown trigger chevron |
321
+ | `toolbarSeparator` | Separator between toolbar groups |
322
+ | `toolbarFileInput` | Hidden media file input |
323
+ | `toolbarUploadButton` | Upload button |
324
+ | `toolbarUploadIcon` | Upload button icon |
325
+ | `toolbarUploadLabel` | Upload button label |
326
+
327
+ ### Style Bar Slots
328
+
329
+ | Slot | Purpose |
330
+ | -------------------- | ----------------------------- |
331
+ | `styleBar` | Quick style gallery container |
332
+ | `styleBarItem` | Individual style card |
333
+ | `styleBarItemActive` | Active style card |
334
+
335
+ ### Style Editor Slots
336
+
337
+ | Slot | Purpose |
338
+ | ---------------------- | ------------------------------------ |
339
+ | `styleEditPopover` | Right-click style edit popover |
340
+ | `styleEditInput` | Inputs inside the style editor |
341
+ | `styleEditSaveButton` | Save button inside the style editor |
342
+ | `styleEditResetButton` | Reset button inside the style editor |
343
+
344
+ ### Font Family Slots
345
+
346
+ | Slot | Purpose |
347
+ | ----------------------------- | ---------------------------- |
348
+ | `toolbarFontFamilyTrigger` | Font family combobox trigger |
349
+ | `toolbarFontFamilyPopover` | Font family popover body |
350
+ | `toolbarFontFamilySearch` | Font family search input |
351
+ | `toolbarFontFamilyList` | Font family list container |
352
+ | `toolbarFontFamilyItem` | Individual font option |
353
+ | `toolbarFontFamilyItemActive` | Active font option |
354
+
355
+ ### Font Size Slots
356
+
357
+ | Slot | Purpose |
358
+ | ------------------------------ | ------------------------------ |
359
+ | `toolbarFontSizeControl` | Font size control wrapper |
360
+ | `toolbarFontSizeControlActive` | Active font size control state |
361
+ | `toolbarFontSizeIcon` | Font size icon wrapper |
362
+ | `toolbarFontSizeInput` | Font size text input |
363
+ | `toolbarFontSizeUnit` | Font size unit label |
364
+ | `toolbarFontSizeStepButton` | Increase and decrease buttons |
365
+ | `toolbarFontSizeResetButton` | Reset font size button |
366
+
367
+ ### Link Popover Slots
368
+
369
+ | Slot | Purpose |
370
+ | ------------------------- | ---------------------------- |
371
+ | `toolbarLinkButton` | Link toolbar button |
372
+ | `toolbarLinkPopoverBody` | Link popover content wrapper |
373
+ | `toolbarLinkPopoverLabel` | Link popover heading |
374
+ | `toolbarLinkInput` | Link URL input |
375
+ | `toolbarLinkActions` | Link action buttons wrapper |
376
+ | `toolbarLinkApplyButton` | Apply link button |
377
+ | `toolbarLinkUnlinkButton` | Remove link button |
378
+
379
+ ### Highlight Slots
380
+
381
+ | Slot | Purpose |
382
+ | ------------------------------ | -------------------------------- |
383
+ | `toolbarHighlightButton` | Highlight toolbar button |
384
+ | `toolbarHighlightIndicator` | Color indicator under the button |
385
+ | `toolbarHighlightPopoverBody` | Highlight palette popover body |
386
+ | `toolbarHighlightPopoverLabel` | Highlight palette label |
387
+ | `toolbarHighlightGrid` | Highlight swatch grid |
388
+ | `toolbarHighlightSwatch` | Individual highlight swatch |
389
+ | `toolbarHighlightSwatchActive` | Active highlight swatch |
390
+ | `toolbarHighlightClearButton` | Clear highlight button |
391
+
392
+ ### Shared Overlay Slots
393
+
394
+ | Slot | Purpose |
395
+ | --------------------------- | --------------------------------- |
396
+ | `tooltipContent` | Tooltip content container |
397
+ | `tooltipArrow` | Tooltip arrow |
398
+ | `popoverContent` | Shared popover content container |
399
+ | `dropdownContent` | Main dropdown menu content |
400
+ | `dropdownSubContent` | Nested dropdown menu content |
401
+ | `dropdownSubTrigger` | Nested dropdown trigger item |
402
+ | `dropdownSubTriggerChevron` | Nested dropdown chevron |
403
+ | `dropdownItem` | Standard dropdown item |
404
+ | `dropdownItemActive` | Active dropdown item state |
405
+ | `dropdownItemIcon` | Dropdown item icon |
406
+ | `dropdownItemLabel` | Dropdown item label |
407
+ | `dropdownItemCheck` | Dropdown selected-state checkmark |
408
+ | `dropdownCheckboxItem` | Checkbox dropdown item |
409
+ | `dropdownRadioItem` | Radio dropdown item |
410
+ | `dropdownIndicator` | Dropdown indicator wrapper |
411
+ | `dropdownLabel` | Dropdown section label |
412
+ | `dropdownSeparator` | Dropdown separator |
413
+ | `dropdownShortcut` | Dropdown shortcut hint text |
414
+
415
+ ### Slash Command Slots
416
+
417
+ | Slot | Purpose |
418
+ | ------------------------ | ---------------------------- |
419
+ | `slashCommandMenu` | Slash command menu container |
420
+ | `slashCommandItem` | Slash command item |
421
+ | `slashCommandItemActive` | Active slash command item |
422
+ | `slashCommandIcon` | Slash command icon wrapper |
423
+ | `slashCommandTitle` | Slash command item label |
424
+ | `slashCommandEmpty` | Empty state wrapper |
425
+ | `slashCommandEmptyIcon` | Empty state icon |
426
+
427
+ ### Drag Handle Slots
428
+
429
+ | Slot | Purpose |
430
+ | ----------------------------- | ----------------------------------- |
431
+ | `dragHandleRoot` | Floating drag handle root |
432
+ | `dragHandleAddButton` | Add-block button |
433
+ | `dragHandleMenuButton` | Grip/menu button |
434
+ | `dragHandleMenuContent` | Drag handle dropdown content |
435
+ | `dragHandleSubContent` | Nested drag handle dropdown content |
436
+ | `dragHandleColorSectionLabel` | Text/background color section label |
437
+ | `dragHandleColorTextPreview` | Text color preview glyph |
438
+ | `dragHandleColorSwatch` | Background color swatch |
439
+ | `dragHandleCheckIcon` | Selected-state check icon |
440
+ | `dragHandleDeleteItem` | Delete item styling |
441
+
442
+ ### Image Node Slots
443
+
444
+ | Slot | Purpose |
445
+ | ------------------------------ | ---------------------------- |
446
+ | `imageNodeWrapper` | Outer image node wrapper |
447
+ | `imageContainer` | Image selection frame |
448
+ | `imageCropArea` | Crop area wrapper |
449
+ | `imageCropToolbar` | Crop mode toolbar |
450
+ | `imageCropButton` | Shared crop toolbar button |
451
+ | `imageCropCancelButton` | Cancel crop button |
452
+ | `imageCropApplyButton` | Apply crop button |
453
+ | `imageFrame` | Image frame container |
454
+ | `imageElement` | Rendered `<img>` element |
455
+ | `imageLoadingOverlay` | Upload/loading overlay |
456
+ | `imageLoadingBox` | Loader badge container |
457
+ | `imageLoadingIcon` | Loader icon |
458
+ | `imagePanHintOverlay` | Pan hint overlay |
459
+ | `imagePanHint` | Pan hint text |
460
+ | `imageToolbar` | Image hover toolbar |
461
+ | `imageToolbarButton` | Shared image toolbar button |
462
+ | `imageToolbarSeparator` | Divider inside image toolbar |
463
+ | `imageDeleteButton` | Image delete button |
464
+ | `imageAltButton` | Alt text button |
465
+ | `imageAltPopover` | Alt text popover body |
466
+ | `imageAltLabel` | Alt text popover label |
467
+ | `imageAltInput` | Alt text input |
468
+ | `imageAltActions` | Alt text action row |
469
+ | `imageAltApplyButton` | Apply alt text button |
470
+ | `imageAltClearButton` | Clear alt text button |
471
+ | `imageResizeHandle` | Shared resize handle styling |
472
+ | `imageResizeHandleRight` | Right resize handle |
473
+ | `imageResizeHandleBottom` | Bottom resize handle |
474
+ | `imageResizeHandleBottomRight` | Bottom-right resize handle |
475
+ | `imageModeBadge` | Mode hint wrapper |
476
+ | `imageModeText` | Mode hint label |
477
+
478
+ This API is intended for design system integration without forcing a fork of the editor internals.
479
+
480
+ ### Translations
481
+
482
+ The library ships with:
483
+
484
+ - `en-US`
485
+ - `tr-TR`
486
+
487
+ You can either import a full locale object or pass a partial object to override selected labels.
488
+
489
+ ## Development Workflow
490
+
491
+ This repository is configured as a library project, not as a local preview app.
492
+
493
+ ### Install Dependencies
494
+
495
+ ```bash
496
+ bun install
497
+ ```
498
+
499
+ ### Development Build Watch
500
+
501
+ ```bash
502
+ bun run dev
503
+ ```
504
+
505
+ This runs:
506
+
507
+ ```bash
508
+ vite build --watch
509
+ ```
510
+
511
+ Use this mode when you want incremental rebuilds of the library output while developing the package.
512
+
513
+ ### Production Build
514
+
515
+ ```bash
516
+ bun run build
517
+ ```
518
+
519
+ This runs:
520
+
521
+ ```bash
522
+ vite build && tsc -p tsconfig.build.json
523
+ ```
524
+
525
+ The command generates JavaScript bundles and declaration files into `dist/`.
526
+
527
+ ## Build and Distribution
528
+
529
+ The Vite configuration builds multiple library entry points:
530
+
531
+ - `src/index.ts`
532
+ - `src/plugin.ts`
533
+ - `src/translations/en-US.ts`
534
+ - `src/translations/tr-TR.ts`
535
+
536
+ The package metadata exposes:
537
+
538
+ - main editor entry
539
+ - Tailwind plugin entry
540
+ - locale entries
541
+
542
+ Distributed assets include:
543
+
544
+ - ESM bundles
545
+ - UMD bundles
546
+ - `.d.ts` type declarations
547
+
548
+ The package is configured to publish:
549
+
550
+ - `dist`
551
+ - `README.md`
552
+ - `LICENSE`
553
+ - `package.json`
554
+
555
+ ## Dependency Management
556
+
557
+ ### Peer Dependencies
558
+
559
+ The package declares the following peers:
560
+
561
+ - `react`
562
+ - `react-dom`
563
+ - `typescript`
564
+
565
+ ### Runtime Dependencies
566
+
567
+ The runtime layer relies heavily on:
568
+
569
+ - Tiptap extensions and editor packages
570
+ - Radix UI primitives
571
+ - Tailwind merge helpers
572
+ - icon and motion libraries
573
+ - media and popup utilities such as `react-easy-crop` and `tippy.js`
574
+
575
+ ### Development Dependencies
576
+
577
+ Development and build-time tooling includes:
578
+
579
+ - Babel and Rollup-related packages
580
+ - Vite and React integration tooling
581
+ - TypeScript
582
+ - declaration generation plugins
583
+
584
+ ### Lockfiles
585
+
586
+ The repository currently includes both `package-lock.json` and `bun.lock`, which suggests npm and Bun have both been used during development. This README uses Bun for repository workflows and npm for consumer installation examples.
587
+
588
+ ## Architecture
589
+
590
+ The codebase is organized as a reusable component library with a single primary editor shell and a set of supporting modules.
591
+
592
+ ### High-Level Design
593
+
594
+ 1. `src/components/Editor.tsx` creates the Tiptap editor instance and composes the full editor shell.
595
+ 2. `src/components/editor/Toolbar.tsx` provides the main authoring controls and style management UI.
596
+ 3. `src/components/editor/GlobalDragHandleMenu.tsx` adds block-level actions beside the editing surface.
597
+ 4. `src/components/editor/extensions/*` defines custom Tiptap extensions for images, video, font size, font family, and extra text-style attributes.
598
+ 5. `src/components/editor/slash-command/*` implements the `/` suggestion system.
599
+ 6. `src/components/editor/EditorContext.tsx` shares theme, translations, class names, and styles with nested UI primitives.
600
+ 7. `src/plugin.ts` exports a Tailwind helper plugin intended to help host apps include the editor's utility classes.
601
+
602
+ ### Content Flow
603
+
604
+ The editor follows this runtime flow:
605
+
606
+ 1. Initial `value` is read as HTML, Markdown, or auto-detected content.
607
+ 2. Tiptap extensions are registered, including the custom image/video and typography extensions.
608
+ 3. User actions update the internal ProseMirror document.
609
+ 4. `onChange` is called with `editor.getMarkdown()`.
610
+
611
+ Important behavior:
612
+
613
+ - Input supports HTML, Markdown, or auto-detection via the `format` prop.
614
+ - Output is Markdown on every update, regardless of the original input format.
615
+ - Auto theme mode persists the chosen theme using the `VOILABS_REACT_EDITOR_THEME` key.
616
+ - Style overrides are stored locally using the `voilabs-editor-style-overrides` key.
617
+
618
+ ### Extensibility Points
619
+
620
+ - `onUpload` for custom media upload pipelines
621
+ - `styles` for custom paragraph style sets
622
+ - `classNames` for granular visual overrides
623
+ - `translations` for partial locale overrides
624
+ - exported Tiptap extensions such as `AdvancedImage`, `FontSize`, and `Video`
625
+
626
+ ## Project Structure
627
+
628
+ ```text
629
+ editor/
630
+ |- src/
631
+ | |- components/
632
+ | | |- Editor.tsx
633
+ | | |- editor/
634
+ | | | |- EditorContext.tsx
635
+ | | | |- Toolbar.tsx
636
+ | | | |- StyleBar.tsx
637
+ | | | |- StyleEditPopover.tsx
638
+ | | | |- GlobalDragHandleMenu.tsx
639
+ | | | |- classNames.ts
640
+ | | | |- paragraphStyles.ts
641
+ | | | |- translations.ts
642
+ | | | |- useStyleStorage.ts
643
+ | | | |- extensions/
644
+ | | | | |- AdvancedImage.tsx
645
+ | | | | |- ImageNodeView.tsx
646
+ | | | | |- FontFamily.ts
647
+ | | | | |- FontSize.ts
648
+ | | | | |- TextStyleAttributes.ts
649
+ | | | | `- Video.tsx
650
+ | | | `- slash-command/
651
+ | | | |- commands.ts
652
+ | | | |- commands-list.tsx
653
+ | | | `- suggestion.tsx
654
+ | | `- ui/
655
+ | | |- Dropdown.tsx
656
+ | | |- DropdownMenu.tsx
657
+ | | |- Popover.tsx
658
+ | | `- Tooltip.tsx
659
+ | |- lib/
660
+ | | `- utils.ts
661
+ | |- translations/
662
+ | | |- en-US.ts
663
+ | | `- tr-TR.ts
664
+ | |- index.ts
665
+ | `- plugin.ts
666
+ |- package.json
667
+ |- vite.config.ts
668
+ |- tsconfig.json
669
+ `- tsconfig.build.json
670
+ ```
671
+
672
+ ## Tech Stack and Dependencies
673
+
674
+ ### Core Runtime
675
+
676
+ - React 19
677
+ - Tiptap 3 ecosystem
678
+ - ProseMirror through `@tiptap/pm`
679
+ - Tailwind CSS 4
680
+ - Radix UI popover, dropdown menu, and tooltip primitives
681
+ - `lucide-react` for editor icons
682
+ - `react-easy-crop` for image cropping
683
+ - `tippy.js` for slash command popup positioning
684
+
685
+ ### Build Tooling
686
+
687
+ - Vite library mode
688
+ - TypeScript 5
689
+ - `vite-plugin-dts` for declaration generation
690
+ - `@vitejs/plugin-react`
691
+ - `@tailwindcss/vite`
692
+
693
+ ### Noteworthy Implementation Details
694
+
695
+ - The editor uses a custom `image` node implementation instead of the default Tiptap image extension.
696
+ - The `Video` extension renders native HTML `<video>` nodes with controls enabled.
697
+ - The toolbar uses context-aware command selection so inline formatting can apply to the current word even when no explicit range is selected.
698
+ - The drag handle menu performs block-level actions by resolving the top-level node under the cursor.
699
+ - The Tailwind helper plugin tries to resolve the installed package path dynamically and scans the built `dist` files for content extraction.
700
+
701
+ ## Contributing
702
+
703
+ Contributions should preserve the package's library-first design, typed public API, and editor usability.
704
+
705
+ Recommended contribution process:
706
+
707
+ 1. Fork or branch from the latest mainline source.
708
+ 2. Install dependencies with `npm install`.
709
+ 3. Make focused changes with clear intent.
710
+ 4. Verify the package builds successfully with `npm run build`.
711
+ 5. Update documentation when behavior or public API changes.
712
+ 6. Open a pull request with a concise explanation of the change.
713
+
714
+ Suggested contribution guidelines:
715
+
716
+ - keep public API changes intentional and documented
717
+ - avoid breaking translation keys without updating shipped locales
718
+ - preserve Markdown output behavior unless a deliberate API change is introduced
719
+ - keep Tailwind class slot compatibility in mind when changing UI structure
720
+ - prefer incremental, reviewable pull requests
721
+
722
+ At the moment, the repository does not define dedicated lint or test scripts in `package.json`, so build validation is the primary verification step.
723
+
724
+ ## License
725
+
726
+ This project is licensed under the MIT License.
727
+
728
+ See [LICENSE](./LICENSE) for the full text.