@flexiui/svelte-rich-text 0.0.60 → 0.0.62

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 (88) hide show
  1. package/README.md +402 -185
  2. package/dist/RichText.svelte +389 -2084
  3. package/dist/RichText.svelte.d.ts +10 -55
  4. package/dist/Toolbar/RenderToolbarButton.svelte +147 -0
  5. package/dist/Toolbar/RenderToolbarButton.svelte.d.ts +14 -0
  6. package/dist/Toolbar/action-buttons/ClearFormatting.svelte +31 -0
  7. package/dist/Toolbar/action-buttons/ClearFormatting.svelte.d.ts +14 -0
  8. package/dist/Toolbar/action-buttons/ClearNodes.svelte +15 -0
  9. package/dist/Toolbar/action-buttons/ClearNodes.svelte.d.ts +14 -0
  10. package/dist/Toolbar/action-buttons/MergeCellsBtn.svelte +31 -0
  11. package/dist/Toolbar/action-buttons/MergeCellsBtn.svelte.d.ts +14 -0
  12. package/dist/Toolbar/action-buttons/Redo.svelte +26 -0
  13. package/dist/Toolbar/action-buttons/Redo.svelte.d.ts +14 -0
  14. package/dist/Toolbar/action-buttons/SplitCellBtn.svelte +31 -0
  15. package/dist/Toolbar/action-buttons/SplitCellBtn.svelte.d.ts +14 -0
  16. package/dist/Toolbar/action-buttons/Undo.svelte +30 -0
  17. package/dist/Toolbar/action-buttons/Undo.svelte.d.ts +14 -0
  18. package/dist/Toolbar/action-buttons/marks/Bold.svelte +29 -0
  19. package/dist/Toolbar/action-buttons/marks/Bold.svelte.d.ts +14 -0
  20. package/dist/Toolbar/action-buttons/marks/CodeMarkBtn.svelte +33 -0
  21. package/dist/Toolbar/action-buttons/marks/CodeMarkBtn.svelte.d.ts +14 -0
  22. package/dist/Toolbar/action-buttons/marks/FontSize.svelte +99 -0
  23. package/dist/Toolbar/action-buttons/marks/FontSize.svelte.d.ts +14 -0
  24. package/dist/Toolbar/action-buttons/marks/Italic.svelte +27 -0
  25. package/dist/Toolbar/action-buttons/marks/Italic.svelte.d.ts +14 -0
  26. package/dist/Toolbar/action-buttons/marks/LinkBtn.svelte +64 -0
  27. package/dist/Toolbar/action-buttons/marks/LinkBtn.svelte.d.ts +14 -0
  28. package/dist/Toolbar/action-buttons/marks/SpecialBox.svelte +21 -0
  29. package/dist/Toolbar/action-buttons/marks/SpecialBox.svelte.d.ts +14 -0
  30. package/dist/Toolbar/action-buttons/marks/Strike.svelte +30 -0
  31. package/dist/Toolbar/action-buttons/marks/Strike.svelte.d.ts +14 -0
  32. package/dist/Toolbar/action-buttons/marks/TextAlign.svelte +66 -0
  33. package/dist/Toolbar/action-buttons/marks/TextAlign.svelte.d.ts +14 -0
  34. package/dist/Toolbar/action-buttons/marks/Underline.svelte +29 -0
  35. package/dist/Toolbar/action-buttons/marks/Underline.svelte.d.ts +14 -0
  36. package/dist/Toolbar/action-buttons/nodes/Audio.svelte +60 -0
  37. package/dist/Toolbar/action-buttons/nodes/Audio.svelte.d.ts +14 -0
  38. package/dist/Toolbar/action-buttons/nodes/Blockquote.svelte +25 -0
  39. package/dist/Toolbar/action-buttons/nodes/Blockquote.svelte.d.ts +14 -0
  40. package/dist/Toolbar/action-buttons/nodes/CodeBlock.svelte +37 -0
  41. package/dist/Toolbar/action-buttons/nodes/CodeBlock.svelte.d.ts +14 -0
  42. package/dist/Toolbar/action-buttons/nodes/HardBreakBtn.svelte +26 -0
  43. package/dist/Toolbar/action-buttons/nodes/HardBreakBtn.svelte.d.ts +14 -0
  44. package/dist/Toolbar/action-buttons/nodes/HeadingBtn.svelte +78 -0
  45. package/dist/Toolbar/action-buttons/nodes/HeadingBtn.svelte.d.ts +14 -0
  46. package/dist/Toolbar/action-buttons/nodes/HorizontalRule.svelte +24 -0
  47. package/dist/Toolbar/action-buttons/nodes/HorizontalRule.svelte.d.ts +14 -0
  48. package/dist/Toolbar/action-buttons/nodes/Image.svelte +60 -0
  49. package/dist/Toolbar/action-buttons/nodes/Image.svelte.d.ts +14 -0
  50. package/dist/Toolbar/action-buttons/nodes/InlineMath.svelte +50 -0
  51. package/dist/Toolbar/action-buttons/nodes/InlineMath.svelte.d.ts +14 -0
  52. package/dist/Toolbar/action-buttons/nodes/ListBtn.svelte +43 -0
  53. package/dist/Toolbar/action-buttons/nodes/ListBtn.svelte.d.ts +14 -0
  54. package/dist/Toolbar/action-buttons/nodes/MediaGridBtn.svelte +58 -0
  55. package/dist/Toolbar/action-buttons/nodes/MediaGridBtn.svelte.d.ts +14 -0
  56. package/dist/Toolbar/action-buttons/nodes/Table.svelte +60 -0
  57. package/dist/Toolbar/action-buttons/nodes/Table.svelte.d.ts +14 -0
  58. package/dist/Toolbar/bubble-menus/BubbleMenuImage.svelte +139 -0
  59. package/dist/Toolbar/bubble-menus/BubbleMenuImage.svelte.d.ts +14 -0
  60. package/dist/Toolbar/dropdown-buttons/HeadingsDropdownBtn.svelte +64 -0
  61. package/dist/Toolbar/dropdown-buttons/HeadingsDropdownBtn.svelte.d.ts +14 -0
  62. package/dist/Toolbar/dropdown-buttons/HighlightDropdownBtn.svelte +45 -0
  63. package/dist/Toolbar/dropdown-buttons/HighlightDropdownBtn.svelte.d.ts +14 -0
  64. package/dist/Toolbar/dropdown-buttons/LineHeightDropdownBtn.svelte +18 -0
  65. package/dist/Toolbar/dropdown-buttons/LineHeightDropdownBtn.svelte.d.ts +14 -0
  66. package/dist/Toolbar/dropdown-buttons/ListsDropdownBtn.svelte +188 -0
  67. package/dist/Toolbar/dropdown-buttons/ListsDropdownBtn.svelte.d.ts +14 -0
  68. package/dist/Toolbar/dropdown-buttons/TextColorDropdownBtn.svelte +37 -0
  69. package/dist/Toolbar/dropdown-buttons/TextColorDropdownBtn.svelte.d.ts +14 -0
  70. package/dist/Toolbar/dropdowns/LineHeightDropdown.svelte +26 -0
  71. package/dist/Toolbar/dropdowns/LineHeightDropdown.svelte.d.ts +14 -0
  72. package/dist/Toolbar/toolbar-utils.d.ts +1 -0
  73. package/dist/Toolbar/toolbar-utils.js +15 -0
  74. package/dist/extensions/NodeFontSize.d.ts +10 -0
  75. package/dist/extensions/NodeFontSize.js +53 -0
  76. package/dist/extensions/SemanticHeadings.d.ts +10 -0
  77. package/dist/extensions/SemanticHeadings.js +124 -0
  78. package/dist/extensions/Table/TableCellNodeView.svelte +0 -4
  79. package/dist/getExtensions.d.ts +7 -0
  80. package/dist/getExtensions.js +13 -2
  81. package/dist/styles.css +58 -11
  82. package/dist/svelte-tiptap-extends/Editor.d.ts +4 -0
  83. package/dist/svelte-tiptap-extends/Editor.js +4 -0
  84. package/dist/svelte-tiptap-extends/EditorContent.svelte +62 -0
  85. package/dist/svelte-tiptap-extends/EditorContent.svelte.d.ts +15 -0
  86. package/dist/svelte-tiptap-extends/types.d.ts +10 -0
  87. package/dist/svelte-tiptap-extends/types.js +1 -0
  88. package/package.json +1 -1
package/README.md CHANGED
@@ -1,247 +1,464 @@
1
- A 'RichText' component for Svelte.
2
- ## Installation
1
+ # RichText Component
3
2
 
4
- To install the `RichText` component in your Svelte project, you can use npm or yarn.
3
+ A powerful rich text editor component for Svelte built on top of [Tiptap](https://tiptap.dev/).
5
4
 
6
- With npm:
5
+ ## Installation
7
6
 
8
7
  ```bash
9
8
  npm install @flexiui/svelte-rich-text
10
9
  ```
11
10
 
12
- With yarn:
13
-
14
- ```bash
15
- yarn add @flexiui/svelte-rich-text
16
- ```
17
-
18
11
  ## Usage
19
12
 
20
- Once installed, you can use the `RichText` component in your Svelte application.
13
+ ### Basic Usage
21
14
 
22
15
  ```svelte
23
16
  <script lang="ts">
24
17
  import { RichText } from '@flexiui/svelte-rich-text';
25
- import { SpecialBox } from './editor/custom-extensions/SpecialBox';
26
-
27
- let editor = $state(null);
28
18
 
29
- let html = $state(null);
30
19
  let json = $state(null);
20
+ let html = $state(null);
31
21
 
32
- let customExtensions = [
33
- SpecialBox
34
- ]
35
-
36
- let content = `
37
- <p>This is a simple and flexible "RichText" component designed to generate a WYSIWYG editor.</p>
38
- <p>It allows easy customization of styles, icons, colors, and more. Additionally, it includes an editable mode for use in forms, block editors, etc.</p>
39
- <p>This component is built on top of <a href="https://tiptap.dev/">Tiptap</a>, a powerful and flexible rich text editor framework for Svelte.</p>
40
- `
41
-
42
- // Editor events
43
- function handleEditorBeforeCreate(e: any) {
44
- console.log('beforeCreate');
45
- console.log(e);
22
+ function handleUpdate(e) {
23
+ const { editor, html: editorHtml, json: editorJson } = e;
24
+ json = editorJson;
25
+ html = editorHtml;
46
26
  }
27
+ </script>
47
28
 
48
- function handleEditorCreate(e: any) {
49
- editor = e.editor;
50
- html = editor.getHTML();
51
- json = editor.getJSON();
52
- }
53
-
54
- function handleEditorDestroy(e: any) {
55
- console.log('destroy');
56
- console.log(e);
57
- }
29
+ <RichText
30
+ editorEvents={{
31
+ onUpdate: handleUpdate
32
+ }}
33
+ />
34
+ ```
58
35
 
59
- function handleEditorUpdate(e: any) {
60
- console.log(e);
61
- const { editor } = e;
62
- html = editor.getHTML();
63
- json = editor.getJSON();
64
- }
36
+ ### With Initial Content
65
37
 
66
- function handleEditorTransaction(e: any) {
67
- console.log('transaction');
68
- console.log(e);
69
- }
38
+ ```svelte
39
+ <script lang="ts">
40
+ import { RichText } from '@flexiui/svelte-rich-text';
70
41
 
71
- function handleEditorFocus(e: any) {
72
- console.log('focus');
73
- console.log(e);
74
- }
42
+ let content = {
43
+ type: "doc",
44
+ content: [
45
+ {
46
+ type: "h1",
47
+ content: [{ type: "text", text: "Hello World" }]
48
+ },
49
+ {
50
+ type: "paragraph",
51
+ content: [{ type: "text", text: "This is a paragraph." }]
52
+ }
53
+ ]
54
+ };
55
+ </script>
75
56
 
76
- function handleEditorBlur(e: any) {
77
- console.log('blur');
78
- console.log(e);
79
- }
57
+ <RichText {content} />
58
+ ```
80
59
 
81
- function handleEditorDrop(e: any) {
82
- console.log('drop');
83
- console.log(e);
84
- }
60
+ ### Without Toolbar
85
61
 
86
- function handleEditorDelete(e: any) {
87
- console.log('delete');
88
- console.log(e);
89
- }
62
+ ```svelte
63
+ <RichText showToolbar={false} />
64
+ ```
90
65
 
91
- function handleEditorPaste(e: any) {
92
- console.log('paste');
93
- console.log(e);
94
- }
66
+ ### With Content Wrapper Element
95
67
 
96
- function handleEditorSelectionUpdate(e: any) {
97
- console.log('selectionUpdate');
98
- console.log(e);
99
- }
68
+ ```svelte
69
+ <RichText contentWrapperAs="h1" />
70
+ ```
100
71
 
101
- function handleEditorContentError(e: any) {
102
- console.log('contentError');
103
- console.log(e);
104
- }
105
- </script>
72
+ ### Inline Node Mode
106
73
 
107
- <RichText
108
- className="my-rich-text"
109
- id="flexi-rich-text"
110
- customExtensions={customExtensions}
111
- editorEvents={{
112
- onUpdate: handleEditorUpdate,
113
- onTransaction: handleEditorTransaction,
114
- onFocus: handleEditorFocus,
115
- onBlur: handleEditorBlur,
116
- onDestroy: handleEditorDestroy,
117
- onDrop: handleEditorDrop,
118
- onDelete: handleEditorDelete,
119
- onPaste: handleEditorPaste,
120
- onSelectionUpdate: handleEditorSelectionUpdate,
121
- onBeforeCreate: handleEditorBeforeCreate,
122
- onCreate: handleEditorCreate,
123
- onContentError: handleEditorContentError,
124
- }}
125
- >
126
- </RichText>
127
-
128
- <h2>JSON Output</h2>
129
- <pre>{JSON.stringify(json, null, 2)}</pre>
130
-
131
- <h2>HTML Output</h2>
132
- <pre>{html}</pre>
74
+ ```svelte
75
+ <RichText inlineNodeMode={true} />
76
+ ```
77
+
78
+ ### With Node Limit
133
79
 
80
+ Limita el número de nodos de primer nivel que puede tener el documento.
81
+
82
+ ```svelte
83
+ <RichText nodesLimit={5} />
134
84
  ```
135
85
 
136
- ## Props
86
+ ### With Unique H1
137
87
 
138
- | Prop name | Type | Default value | Description |
139
- | --- | --- | --- | --- |
140
- | className | string | '' | A string that sets the class attribute of the component.
141
- | editable | boolean | false | A boolean that determines whether the editor is editable or not.
142
- | content | any | null | The initial content of the editor.
143
- | customExtensions | any[] | [] | An array of custom extensions to be added to the editor.
144
- | editorEvents | object | {} | An object containing event handlers for various editor events.
88
+ Automáticamente convierte encabezados H1 adicionales en párrafos, permitiendo solo un H1 en el documento.
145
89
 
146
- ## Events
90
+ ```svelte
91
+ <RichText uniqueH1={true} />
92
+ ```
93
+
94
+ ### With Semantic Headings
95
+
96
+ ```svelte
97
+ <RichText semanticHeadings={true} />
98
+ ```
99
+
100
+ ### Custom Toolbar Configuration
101
+
102
+ ```svelte
103
+ <RichText
104
+ toolbarConfig={[
105
+ [{ type: "undo" }, "redo"],
106
+ [{ type: "headings" }, { type: "lists" }],
107
+ ["codeBlock", "blockquote"],
108
+ ["fontSize", "lineHeight"],
109
+ ["textAlignLeft", "textAlignCenter", "textAlignRight", "clearFormatting"],
110
+ ]}
111
+ />
112
+ ```
147
113
 
148
- | Event name | Parameters | Description |
149
- | --- | --- | --- |
150
- | onTransaction | { editor, transaction } | Triggered when a transaction is executed on the editor.
151
- | onBeforeCreate | { editor } | Triggered before the editor is created.
152
- | onCreate | { editor } | Triggered after the editor is created.
153
- | onUpdate | { editor, html, json } | Triggered when the editor content is updated.
154
- | onFocus | { editor, event } | Triggered when the editor is focused.
155
- | onBlur | { editor, event } | Triggered when the editor is blurred.
156
- | onDestroy | { editor, message } | Triggered when the editor is destroyed.
157
- | onDrop | { editor, event, slice, moved } | Triggered when the editor is dropped into the editor.
158
- | onDelete | { editor, type, deletedRange, newRange, partial, from, to } | Triggered when content is deleted from the editor.
159
- | onContentError | { editor, error, disableCollaboration } | Triggered when the editor content does not match the schema.
160
- | onSelectionUpdate | { editor } | Triggered when the selection in the editor is updated.
161
- | onPaste | { event, slice } | Triggered when the editor is pasted into.
114
+ ### With Custom Styling
162
115
 
163
- ## Custom Extensions
116
+ ```svelte
117
+ <RichText
118
+ config={{
119
+ editorAccentColor: "#22c55e",
120
+ editorBgColor: "#242424",
121
+ toolbarBgColor: "#1a1a1a",
122
+ docBg: "#2a2a2a",
123
+ buttonStyle: "accent-soft"
124
+ }}
125
+ />
126
+ ```
164
127
 
165
- You can add custom extensions to the editor by passing them as an array to the `customExtensions` prop. Here's an example of how to add the `SpecialBox` extension:
128
+ ### With Custom Extensions
166
129
 
167
130
  ```svelte
168
131
  <script lang="ts">
169
- import { SpecialBox } from './editor/custom-extensions/SpecialBox';
132
+ import { RichText } from '@flexiui/svelte-rich-text';
133
+ import { SpecialBox } from './extensions/SpecialBox';
134
+ import { PlaceholderExt } from '@flexiui/svelte-rich-text';
170
135
 
171
136
  let customExtensions = [
172
- SpecialBox
173
- ]
137
+ SpecialBox,
138
+ PlaceholderExt.configure({
139
+ placeholder: ({ node }) => {
140
+ if (node.type.name === "h1") {
141
+ return "Introduce un título";
142
+ } else if (node.type.name === "paragraph") {
143
+ return "Escribe algo...";
144
+ }
145
+ }
146
+ })
147
+ ];
148
+ </script>
149
+
150
+ <RichText {customExtensions} />
151
+ ```
152
+
153
+ ### Complete Example
154
+
155
+ ```svelte
156
+ <script lang="ts">
157
+ import { RichText } from '@flexiui/svelte-rich-text';
158
+ import { SpecialBox, PlaceholderExt } from '@flexiui/svelte-rich-text';
159
+
160
+ let editor = $state(null);
161
+ let json = $state(null);
162
+ let html = $state(null);
163
+
164
+ let customExtensions = [
165
+ SpecialBox,
166
+ PlaceholderExt.configure({
167
+ placeholder: ({ node }) => {
168
+ if (node.type.name === "h1") {
169
+ return "Introduce un título";
170
+ } else if (node.type.name === "paragraph") {
171
+ return "Escribe algo...";
172
+ }
173
+ }
174
+ })
175
+ ];
176
+
177
+ function handleEditorCreate(e) {
178
+ editor = e.editor;
179
+ }
180
+
181
+ function handleEditorUpdate(e) {
182
+ const { editor, html: editorHtml, json: editorJson } = e;
183
+ json = editorJson;
184
+ html = editorHtml;
185
+ }
174
186
  </script>
175
187
 
176
188
  <RichText
177
- customExtensions={customExtensions}
178
- ...
189
+ nodesLimit={10}
190
+ uniqueH1={true}
191
+ semanticHeadings={true}
192
+ config={{
193
+ editorAccentColor: "#6366f1",
194
+ editorBgColor: "#1e1e1e",
195
+ toolbarBgColor: "#2d2d2d",
196
+ buttonStyle: "accent-solid"
197
+ }}
198
+ toolbarConfig={[
199
+ [{ type: "undo" }, "redo"],
200
+ [{ type: "headings" }, { type: "lists" }],
201
+ ["codeBlock", "blockquote"],
202
+ ["fontSize", "lineHeight"],
203
+ ["textAlignLeft", "textAlignCenter", "textAlignRight"],
204
+ ]}
205
+ {customExtensions}
206
+ editorEvents={{
207
+ onCreate: handleEditorCreate,
208
+ onUpdate: handleEditorUpdate
209
+ }}
179
210
  />
180
211
  ```
181
212
 
182
- In this example, the `SpecialBox` extension is imported from a file called `SpecialBox.ts` in the `editor/custom-extensions` directory.
213
+ ## Props
183
214
 
184
- In this case, the `SpecialBox` extension is a custom "Mark" that adds a special box inline node to the editor.
215
+ | Prop | Type | Default | Description |
216
+ |------|------|---------|-------------|
217
+ | `id` | `string` | `'fl-rich-text-editor'` | Unique identifier for the editor |
218
+ | `className` | `string` | `''` | CSS class for the component container |
219
+ | `editable` | `boolean` | `true` | Whether the editor is editable |
220
+ | `content` | `string \| { type: string; content: any[] } \| null` | `null` | Initial content (HTML string or Tiptap JSON) |
221
+ | `nodesLimit` | `number` | `undefined` | Maximum number of top-level nodes allowed |
222
+ | `limitWarningMessage` | `string` | `undefined` | Custom warning message when limit is reached |
223
+ | `showToolbar` | `boolean` | `true` | Whether to show the toolbar |
224
+ | `semanticHeadings` | `boolean` | `false` | Use semantic heading structure |
225
+ | `uniqueH1` | `boolean` | `false` | Allow only one H1 heading (converts extras to paragraphs) |
226
+ | `toolbarConfig` | `ToolbarConfig` | `undefined` | Custom toolbar configuration |
227
+ | `customExtensions` | `any[]` | `[]` | Custom Tiptap extensions |
228
+ | `editorEvents` | `EditorEvents` | `{}` | Event handlers for editor events |
229
+ | `config` | `EditorConfig` | `{}` | Visual configuration options |
230
+ | `contentWrapperAs` | `T extends keyof SvelteHTMLElements` | `'div'` | HTML element type for content wrapper |
231
+ | `inlineNodeMode` | `boolean` | `false` | Enable inline node mode (uses inline document) |
232
+
233
+ ## Editor Events
234
+
235
+ | Event | Parameters | Description |
236
+ |-------|------------|-------------|
237
+ | `onTransaction` | `{ editor, transaction }` | Triggered on any editor transaction |
238
+ | `onBeforeCreate` | `{ editor }` | Triggered before editor initialization |
239
+ | `onCreate` | `{ editor }` | Triggered after editor is created |
240
+ | `onUpdate` | `{ editor, html, json }` | Triggered when content changes |
241
+ | `onFocus` | `{ editor, event }` | Triggered when editor receives focus |
242
+ | `onBlur` | `{ editor, event }` | Triggered when editor loses focus |
243
+ | `onDestroy` | `{ editor, message }` | Triggered when editor is destroyed |
244
+ | `onDrop` | `{ editor, event, slice, moved }` | Triggered when content is dropped |
245
+ | `onDelete` | `{ editor, type, deletedRange, newRange, partial, from, to }` | Triggered when content is deleted |
246
+ | `onContentError` | `{ editor, error, disableCollaboration }` | Triggered on content schema error |
247
+ | `onSelectionUpdate` | `{ editor }` | Triggered when selection changes |
248
+ | `onPaste` | `{ event, slice }` | Triggered when content is pasted |
249
+
250
+ ## Config Options
251
+
252
+ | Option | Type | Default | Description |
253
+ |--------|------|---------|-------------|
254
+ | `editorAccentColor` | `string` | `'var(--purple)'` | Primary accent color for UI elements |
255
+ | `editorBgColor` | `string` | `'transparent'` | Editor background color |
256
+ | `editorRadius` | `string` | `'12px'` | Border radius for editor container |
257
+ | `toolbarStickyPosition` | `number` | `0` | CSS `top` value for sticky toolbar |
258
+ | `toolbarZIndex` | `number` | `10` | Z-index of the toolbar |
259
+ | `toolbarBgColor` | `string` | `'#242424'` | Toolbar background color |
260
+ | `toolbarTextColor` | `string` | `'currentColor'` | Toolbar text color |
261
+ | `toolbarPadding` | `string` | `'8px'` | Toolbar padding |
262
+ | `toolbarGap` | `string` | `'5px'` | Gap between toolbar buttons |
263
+ | `docMaxWidth` | `string` | `'1032px'` | Maximum width of document content |
264
+ | `docPadding` | `string` | `'2rem'` | Document padding |
265
+ | `docBg` | `string` | `'transparent'` | Document background |
266
+ | `docMarginInline` | `string` | `'auto'` | Horizontal margin |
267
+ | `docMarginBlock` | `string` | `'2rem'` | Vertical margin |
268
+ | `docRadius` | `string` | `'0'` | Document border radius |
269
+ | `docTextColor` | `string` | `'currentColor'` | Document text color |
270
+ | `buttonStyle` | `'accent-soft' \| 'accent-solid'` | `'accent-solid'` | Button style variant |
271
+
272
+ ## Toolbar Configuration
273
+
274
+ ### Available Button Types
275
+
276
+ - **Navigation**: `undo`, `redo`
277
+ - **Headings**: `headings` (dropdown), `lists` (dropdown)
278
+ - **Text Formatting**: `codeBlock`, `blockquote`
279
+ - **Text Style**: `fontSize`, `lineHeight`
280
+ - **Block Elements**: `horizontalRule`, `hardBreak`
281
+ - **Media**: `inlineMath`, `image`, `audio`, `mediaGrid`, `table`
282
+ - **Alignment**: `textAlignLeft`, `textAlignCenter`, `textAlignRight`, `clearFormatting`, `clearNodes`
283
+
284
+ ### Toolbar Types
285
+
286
+ #### Button (string)
287
+
288
+ Simple button represented as a string:
185
289
 
186
290
  ```ts
187
- import { Mark } from "@tiptap/core";
188
-
189
- declare module '@tiptap/core' {
190
- interface Commands<ReturnType> {
191
- specialBox: {
192
- specialBox: () => ReturnType
193
- isActive: (options: any) => ReturnType
194
- }
195
- }
291
+ "undo"
292
+ "redo"
293
+ "codeBlock"
294
+ ```
295
+
296
+ #### Button with Options (object)
297
+
298
+ Button with custom configuration:
299
+
300
+ ```ts
301
+ { type: "undo" }
302
+ { type: "redo", tooltip: "Custom tooltip" }
303
+ ```
304
+
305
+ #### Dropdown (select)
306
+
307
+ Dropdown menu with multiple options:
308
+
309
+ ```ts
310
+ {
311
+ select: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
312
+ name: 'headings-dropdown'
196
313
  }
314
+ ```
197
315
 
198
- export const SpecialBox = Mark.create({
199
- name: "specialBox",
200
- excludes: 'code highlight',
316
+ ### ToolbarConfig Type
201
317
 
202
- parseHTML() {
203
- return [
204
- {
205
- tag: "span[data-special-box]",
206
- },
207
- ];
208
- },
318
+ ```ts
319
+ type ToolbarButton = string | {
320
+ type?: string;
321
+ tooltip?: string;
322
+ icon?: string;
323
+ name?: string;
324
+ };
325
+
326
+ type ToolbarSelect = {
327
+ select: ToolbarButton[];
328
+ name?: string;
329
+ tooltip?: string;
330
+ icon?: string;
331
+ type?: string;
332
+ };
333
+
334
+ type ToolbarItem = ToolbarButton | ToolbarSelect;
335
+ type ToolbarConfig = ToolbarItem[] | ToolbarItem[][];
336
+ ```
209
337
 
210
- renderHTML({ HTMLAttributes }) {
211
- return [
212
- "span",
213
- {
214
- "class": "special-box",
215
- "data-special-box": "true",
216
- style: "line-height: 1.5;",
217
- },
218
- 0,
219
- ];
220
- },
221
-
222
- addCommands(): any {
223
- return {
224
- specialBox: () => ({ commands }: any) => {
225
- return commands.toggleMark(this.name);
226
- },
227
- isActive: (options: any) => {
228
- return options.type === this.name;
229
- },
230
- };
231
- },
232
- });
338
+ ### Examples
339
+
340
+ #### Simple Toolbar
341
+
342
+ ```svelte
343
+ <RichText
344
+ toolbarConfig={[
345
+ ["undo", "redo"],
346
+ ["bold", "italic", "underline"]
347
+ ]}
348
+ />
349
+ ```
350
+
351
+ #### Grouped Toolbar
352
+
353
+ ```svelte
354
+ <RichText
355
+ toolbarConfig={[
356
+ [{ type: "undo" }, "redo"], // Group 1
357
+ [{ type: "headings" }], // Group 2
358
+ ["codeBlock", "blockquote"], // Group 3
359
+ ["bold", "italic", "underline"] // Group 4
360
+ ]}
361
+ />
362
+ ```
363
+
364
+ #### Full Custom Toolbar
365
+
366
+ ```svelte
367
+ <RichText
368
+ toolbarConfig={[
369
+ [{ type: "undo" }, "redo"],
370
+ [{ type: "headings" }, { type: "lists" }],
371
+ ["codeBlock", "blockquote"],
372
+ ["fontSize", "lineHeight"],
373
+ ["horizontalRule", "hardBreak"],
374
+ ["inlineMath"],
375
+ ["image", "audio"],
376
+ ["mediaGrid", "table"],
377
+ ["textAlignLeft", "textAlignCenter", "textAlignRight", "clearFormatting", "clearNodes"],
378
+ ]}
379
+ />
380
+ ```
381
+
382
+ ## Node Limit Feature
383
+
384
+ When `nodesLimit` is set, the editor:
385
+
386
+ 1. Shows a warning message when the user tries to add more nodes than allowed
387
+ 2. Displays a bottom bar with current node count and limit
388
+ 3. Prevents adding new nodes via Enter key when limit is reached
389
+
390
+ ### Custom Warning Message
391
+
392
+ ```svelte
393
+ <RichText
394
+ nodesLimit={5}
395
+ limitWarningMessage="Has alcanzado el límite máximo de 5 elementos."
396
+ />
397
+ ```
398
+
399
+ ## Unique H1 Feature
400
+
401
+ When `uniqueH1` is enabled:
402
+
403
+ 1. The first H1 heading remains as H1
404
+ 2. Any additional H1 headings are automatically converted to paragraphs
405
+ 3. This ensures semantic HTML structure with only one H1 per document
406
+
407
+ ## Default Toolbar
408
+
409
+ If no `toolbarConfig` is provided, the default toolbar is used:
410
+
411
+ ```svelte
412
+ [
413
+ [{ type: "undo" }, "redo"],
414
+ [{ type: "headings" }, { type: "lists" }],
415
+ ["codeBlock", "blockquote"],
416
+ ["fontSize", "lineHeight"],
417
+ ["horizontalRule", "hardBreak"],
418
+ ["inlineMath"],
419
+ ["image", "audio"],
420
+ ["mediaGrid", "table"],
421
+ ["textAlignLeft", "textAlignCenter", "textAlignRight", "clearFormatting", "clearNodes"],
422
+ ]
233
423
  ```
234
424
 
235
- In this example, the `SpecialBox` extension defines a custom "Mark" that adds a special box inline node to the editor.
425
+ ## Output
236
426
 
237
- The `parseHTML` method defines the HTML structure of the special box node. In this case, the node is a `<span>` element with a `data-special-box` attribute.
427
+ The editor provides two output formats:
238
428
 
239
- The `renderHTML` method defines the HTML structure of the special box node. In this case, the node is a `<span>` element with a `data-special-box` attribute and a `special-box` class.
429
+ ### HTML Output
430
+
431
+ ```svelte
432
+ function handleUpdate(e) {
433
+ const { html } = e;
434
+ // html: "<h1>Hello</h1><p>World</p>"
435
+ }
436
+ ```
240
437
 
241
- The `addCommands` method defines the commands for the special box node. In this case, the `specialBox` command toggles the mark on the selected text.
438
+ ### JSON Output
242
439
 
243
- The `isActive` method defines the logic for determining whether the special box node is active or not. In this case, the node is active if the selected text has the `specialBox` mark.
440
+ ```svelte
441
+ function handleUpdate(e) {
442
+ const { json } = e;
443
+ // json: { type: "doc", content: [...] }
444
+ }
445
+ ```
446
+
447
+ ## Static Rendering
448
+
449
+ You can also render the content statically using `renderHTMLFromJSON`:
450
+
451
+ ```svelte
452
+ <script lang="ts">
453
+ import { renderHTMLFromJSON } from '@flexiui/svelte-rich-text';
454
+
455
+ let json = { type: "doc", content: [...] };
456
+ let html = renderHTMLFromJSON({ json });
457
+ </script>
458
+
459
+ {@html html}
460
+ ```
244
461
 
245
- You can customize the behavior of the special box node by modifying the `SpecialBox` extension as needed.
462
+ ## License
246
463
 
247
- More information about custom nodes, marks and extensions can be found in the [Tiptap documentation](https://tiptap.dev/docs/editor/extensions/custom-extensions/create-new).
464
+ MIT