@flexiui/svelte-rich-text 0.0.59 → 0.0.61

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 (82) hide show
  1. package/README.md +388 -185
  2. package/dist/RichText.svelte +389 -2075
  3. package/dist/RichText.svelte.d.ts +29 -0
  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 +71 -27
  82. package/package.json +1 -1
package/README.md CHANGED
@@ -1,247 +1,450 @@
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 Node Limit
95
67
 
96
- function handleEditorSelectionUpdate(e: any) {
97
- console.log('selectionUpdate');
98
- console.log(e);
99
- }
68
+ Limita el número de nodos de primer nivel que puede tener el documento.
100
69
 
101
- function handleEditorContentError(e: any) {
102
- console.log('contentError');
103
- console.log(e);
104
- }
105
- </script>
70
+ ```svelte
71
+ <RichText nodesLimit={5} />
72
+ ```
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
+ ### With Unique H1
75
+
76
+ Automáticamente convierte encabezados H1 adicionales en párrafos, permitiendo solo un H1 en el documento.
133
77
 
78
+ ```svelte
79
+ <RichText uniqueH1={true} />
134
80
  ```
135
81
 
136
- ## Props
82
+ ### With Semantic Headings
83
+
84
+ ```svelte
85
+ <RichText semanticHeadings={true} />
86
+ ```
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
+ ### Custom Toolbar Configuration
145
89
 
146
- ## Events
90
+ ```svelte
91
+ <RichText
92
+ toolbarConfig={[
93
+ [{ type: "undo" }, "redo"],
94
+ [{ type: "headings" }, { type: "lists" }],
95
+ ["codeBlock", "blockquote"],
96
+ ["fontSize", "lineHeight"],
97
+ ["textAlignLeft", "textAlignCenter", "textAlignRight", "clearFormatting"],
98
+ ]}
99
+ />
100
+ ```
147
101
 
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.
102
+ ### With Custom Styling
162
103
 
163
- ## Custom Extensions
104
+ ```svelte
105
+ <RichText
106
+ config={{
107
+ editorAccentColor: "#22c55e",
108
+ editorBgColor: "#242424",
109
+ toolbarBgColor: "#1a1a1a",
110
+ docBg: "#2a2a2a",
111
+ buttonStyle: "accent-soft"
112
+ }}
113
+ />
114
+ ```
164
115
 
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:
116
+ ### With Custom Extensions
166
117
 
167
118
  ```svelte
168
119
  <script lang="ts">
169
- import { SpecialBox } from './editor/custom-extensions/SpecialBox';
120
+ import { RichText } from '@flexiui/svelte-rich-text';
121
+ import { SpecialBox } from './extensions/SpecialBox';
122
+ import { PlaceholderExt } from '@flexiui/svelte-rich-text';
170
123
 
171
124
  let customExtensions = [
172
- SpecialBox
173
- ]
125
+ SpecialBox,
126
+ PlaceholderExt.configure({
127
+ placeholder: ({ node }) => {
128
+ if (node.type.name === "h1") {
129
+ return "Introduce un título";
130
+ } else if (node.type.name === "paragraph") {
131
+ return "Escribe algo...";
132
+ }
133
+ }
134
+ })
135
+ ];
136
+ </script>
137
+
138
+ <RichText {customExtensions} />
139
+ ```
140
+
141
+ ### Complete Example
142
+
143
+ ```svelte
144
+ <script lang="ts">
145
+ import { RichText } from '@flexiui/svelte-rich-text';
146
+ import { SpecialBox, PlaceholderExt } from '@flexiui/svelte-rich-text';
147
+
148
+ let editor = $state(null);
149
+ let json = $state(null);
150
+ let html = $state(null);
151
+
152
+ let customExtensions = [
153
+ SpecialBox,
154
+ PlaceholderExt.configure({
155
+ placeholder: ({ node }) => {
156
+ if (node.type.name === "h1") {
157
+ return "Introduce un título";
158
+ } else if (node.type.name === "paragraph") {
159
+ return "Escribe algo...";
160
+ }
161
+ }
162
+ })
163
+ ];
164
+
165
+ function handleEditorCreate(e) {
166
+ editor = e.editor;
167
+ }
168
+
169
+ function handleEditorUpdate(e) {
170
+ const { editor, html: editorHtml, json: editorJson } = e;
171
+ json = editorJson;
172
+ html = editorHtml;
173
+ }
174
174
  </script>
175
175
 
176
176
  <RichText
177
- customExtensions={customExtensions}
178
- ...
177
+ nodesLimit={10}
178
+ uniqueH1={true}
179
+ semanticHeadings={true}
180
+ config={{
181
+ editorAccentColor: "#6366f1",
182
+ editorBgColor: "#1e1e1e",
183
+ toolbarBgColor: "#2d2d2d",
184
+ buttonStyle: "accent-solid"
185
+ }}
186
+ toolbarConfig={[
187
+ [{ type: "undo" }, "redo"],
188
+ [{ type: "headings" }, { type: "lists" }],
189
+ ["codeBlock", "blockquote"],
190
+ ["fontSize", "lineHeight"],
191
+ ["textAlignLeft", "textAlignCenter", "textAlignRight"],
192
+ ]}
193
+ {customExtensions}
194
+ editorEvents={{
195
+ onCreate: handleEditorCreate,
196
+ onUpdate: handleEditorUpdate
197
+ }}
179
198
  />
180
199
  ```
181
200
 
182
- In this example, the `SpecialBox` extension is imported from a file called `SpecialBox.ts` in the `editor/custom-extensions` directory.
201
+ ## Props
183
202
 
184
- In this case, the `SpecialBox` extension is a custom "Mark" that adds a special box inline node to the editor.
203
+ | Prop | Type | Default | Description |
204
+ |------|------|---------|-------------|
205
+ | `id` | `string` | `'fl-rich-text-editor'` | Unique identifier for the editor |
206
+ | `className` | `string` | `''` | CSS class for the component container |
207
+ | `editable` | `boolean` | `true` | Whether the editor is editable |
208
+ | `content` | `string \| { type: string; content: any[] } \| null` | `null` | Initial content (HTML string or Tiptap JSON) |
209
+ | `nodesLimit` | `number` | `undefined` | Maximum number of top-level nodes allowed |
210
+ | `limitWarningMessage` | `string` | `undefined` | Custom warning message when limit is reached |
211
+ | `showToolbar` | `boolean` | `true` | Whether to show the toolbar |
212
+ | `semanticHeadings` | `boolean` | `false` | Use semantic heading structure |
213
+ | `uniqueH1` | `boolean` | `false` | Allow only one H1 heading (converts extras to paragraphs) |
214
+ | `toolbarConfig` | `ToolbarConfig` | `undefined` | Custom toolbar configuration |
215
+ | `customExtensions` | `any[]` | `[]` | Custom Tiptap extensions |
216
+ | `editorEvents` | `EditorEvents` | `{}` | Event handlers for editor events |
217
+ | `config` | `EditorConfig` | `{}` | Visual configuration options |
218
+
219
+ ## Editor Events
220
+
221
+ | Event | Parameters | Description |
222
+ |-------|------------|-------------|
223
+ | `onTransaction` | `{ editor, transaction }` | Triggered on any editor transaction |
224
+ | `onBeforeCreate` | `{ editor }` | Triggered before editor initialization |
225
+ | `onCreate` | `{ editor }` | Triggered after editor is created |
226
+ | `onUpdate` | `{ editor, html, json }` | Triggered when content changes |
227
+ | `onFocus` | `{ editor, event }` | Triggered when editor receives focus |
228
+ | `onBlur` | `{ editor, event }` | Triggered when editor loses focus |
229
+ | `onDestroy` | `{ editor, message }` | Triggered when editor is destroyed |
230
+ | `onDrop` | `{ editor, event, slice, moved }` | Triggered when content is dropped |
231
+ | `onDelete` | `{ editor, type, deletedRange, newRange, partial, from, to }` | Triggered when content is deleted |
232
+ | `onContentError` | `{ editor, error, disableCollaboration }` | Triggered on content schema error |
233
+ | `onSelectionUpdate` | `{ editor }` | Triggered when selection changes |
234
+ | `onPaste` | `{ event, slice }` | Triggered when content is pasted |
235
+
236
+ ## Config Options
237
+
238
+ | Option | Type | Default | Description |
239
+ |--------|------|---------|-------------|
240
+ | `editorAccentColor` | `string` | `'var(--purple)'` | Primary accent color for UI elements |
241
+ | `editorBgColor` | `string` | `'transparent'` | Editor background color |
242
+ | `editorRadius` | `string` | `'12px'` | Border radius for editor container |
243
+ | `toolbarStickyPosition` | `number` | `0` | CSS `top` value for sticky toolbar |
244
+ | `toolbarZIndex` | `number` | `10` | Z-index of the toolbar |
245
+ | `toolbarBgColor` | `string` | `'#242424'` | Toolbar background color |
246
+ | `toolbarTextColor` | `string` | `'currentColor'` | Toolbar text color |
247
+ | `toolbarPadding` | `string` | `'8px'` | Toolbar padding |
248
+ | `toolbarGap` | `string` | `'5px'` | Gap between toolbar buttons |
249
+ | `docMaxWidth` | `string` | `'1032px'` | Maximum width of document content |
250
+ | `docPadding` | `string` | `'2rem'` | Document padding |
251
+ | `docBg` | `string` | `'transparent'` | Document background |
252
+ | `docMarginInline` | `string` | `'auto'` | Horizontal margin |
253
+ | `docMarginBlock` | `string` | `'2rem'` | Vertical margin |
254
+ | `docRadius` | `string` | `'0'` | Document border radius |
255
+ | `docTextColor` | `string` | `'currentColor'` | Document text color |
256
+ | `buttonStyle` | `'accent-soft' \| 'accent-solid'` | `'accent-solid'` | Button style variant |
257
+
258
+ ## Toolbar Configuration
259
+
260
+ ### Available Button Types
261
+
262
+ - **Navigation**: `undo`, `redo`
263
+ - **Headings**: `headings` (dropdown), `lists` (dropdown)
264
+ - **Text Formatting**: `codeBlock`, `blockquote`
265
+ - **Text Style**: `fontSize`, `lineHeight`
266
+ - **Block Elements**: `horizontalRule`, `hardBreak`
267
+ - **Media**: `inlineMath`, `image`, `audio`, `mediaGrid`, `table`
268
+ - **Alignment**: `textAlignLeft`, `textAlignCenter`, `textAlignRight`, `clearFormatting`, `clearNodes`
269
+
270
+ ### Toolbar Types
271
+
272
+ #### Button (string)
273
+
274
+ Simple button represented as a string:
185
275
 
186
276
  ```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
- }
277
+ "undo"
278
+ "redo"
279
+ "codeBlock"
280
+ ```
281
+
282
+ #### Button with Options (object)
283
+
284
+ Button with custom configuration:
285
+
286
+ ```ts
287
+ { type: "undo" }
288
+ { type: "redo", tooltip: "Custom tooltip" }
289
+ ```
290
+
291
+ #### Dropdown (select)
292
+
293
+ Dropdown menu with multiple options:
294
+
295
+ ```ts
296
+ {
297
+ select: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
298
+ name: 'headings-dropdown'
196
299
  }
300
+ ```
197
301
 
198
- export const SpecialBox = Mark.create({
199
- name: "specialBox",
200
- excludes: 'code highlight',
302
+ ### ToolbarConfig Type
201
303
 
202
- parseHTML() {
203
- return [
204
- {
205
- tag: "span[data-special-box]",
206
- },
207
- ];
208
- },
304
+ ```ts
305
+ type ToolbarButton = string | {
306
+ type?: string;
307
+ tooltip?: string;
308
+ icon?: string;
309
+ name?: string;
310
+ };
311
+
312
+ type ToolbarSelect = {
313
+ select: ToolbarButton[];
314
+ name?: string;
315
+ tooltip?: string;
316
+ icon?: string;
317
+ type?: string;
318
+ };
319
+
320
+ type ToolbarItem = ToolbarButton | ToolbarSelect;
321
+ type ToolbarConfig = ToolbarItem[] | ToolbarItem[][];
322
+ ```
209
323
 
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
- });
324
+ ### Examples
325
+
326
+ #### Simple Toolbar
327
+
328
+ ```svelte
329
+ <RichText
330
+ toolbarConfig={[
331
+ ["undo", "redo"],
332
+ ["bold", "italic", "underline"]
333
+ ]}
334
+ />
335
+ ```
336
+
337
+ #### Grouped Toolbar
338
+
339
+ ```svelte
340
+ <RichText
341
+ toolbarConfig={[
342
+ [{ type: "undo" }, "redo"], // Group 1
343
+ [{ type: "headings" }], // Group 2
344
+ ["codeBlock", "blockquote"], // Group 3
345
+ ["bold", "italic", "underline"] // Group 4
346
+ ]}
347
+ />
348
+ ```
349
+
350
+ #### Full Custom Toolbar
351
+
352
+ ```svelte
353
+ <RichText
354
+ toolbarConfig={[
355
+ [{ type: "undo" }, "redo"],
356
+ [{ type: "headings" }, { type: "lists" }],
357
+ ["codeBlock", "blockquote"],
358
+ ["fontSize", "lineHeight"],
359
+ ["horizontalRule", "hardBreak"],
360
+ ["inlineMath"],
361
+ ["image", "audio"],
362
+ ["mediaGrid", "table"],
363
+ ["textAlignLeft", "textAlignCenter", "textAlignRight", "clearFormatting", "clearNodes"],
364
+ ]}
365
+ />
366
+ ```
367
+
368
+ ## Node Limit Feature
369
+
370
+ When `nodesLimit` is set, the editor:
371
+
372
+ 1. Shows a warning message when the user tries to add more nodes than allowed
373
+ 2. Displays a bottom bar with current node count and limit
374
+ 3. Prevents adding new nodes via Enter key when limit is reached
375
+
376
+ ### Custom Warning Message
377
+
378
+ ```svelte
379
+ <RichText
380
+ nodesLimit={5}
381
+ limitWarningMessage="Has alcanzado el límite máximo de 5 elementos."
382
+ />
383
+ ```
384
+
385
+ ## Unique H1 Feature
386
+
387
+ When `uniqueH1` is enabled:
388
+
389
+ 1. The first H1 heading remains as H1
390
+ 2. Any additional H1 headings are automatically converted to paragraphs
391
+ 3. This ensures semantic HTML structure with only one H1 per document
392
+
393
+ ## Default Toolbar
394
+
395
+ If no `toolbarConfig` is provided, the default toolbar is used:
396
+
397
+ ```svelte
398
+ [
399
+ [{ type: "undo" }, "redo"],
400
+ [{ type: "headings" }, { type: "lists" }],
401
+ ["codeBlock", "blockquote"],
402
+ ["fontSize", "lineHeight"],
403
+ ["horizontalRule", "hardBreak"],
404
+ ["inlineMath"],
405
+ ["image", "audio"],
406
+ ["mediaGrid", "table"],
407
+ ["textAlignLeft", "textAlignCenter", "textAlignRight", "clearFormatting", "clearNodes"],
408
+ ]
409
+ ```
410
+
411
+ ## Output
412
+
413
+ The editor provides two output formats:
414
+
415
+ ### HTML Output
416
+
417
+ ```svelte
418
+ function handleUpdate(e) {
419
+ const { html } = e;
420
+ // html: "<h1>Hello</h1><p>World</p>"
421
+ }
233
422
  ```
234
423
 
235
- In this example, the `SpecialBox` extension defines a custom "Mark" that adds a special box inline node to the editor.
424
+ ### JSON Output
236
425
 
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.
426
+ ```svelte
427
+ function handleUpdate(e) {
428
+ const { json } = e;
429
+ // json: { type: "doc", content: [...] }
430
+ }
431
+ ```
238
432
 
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.
433
+ ## Static Rendering
240
434
 
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.
435
+ You can also render the content statically using `renderHTMLFromJSON`:
242
436
 
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.
437
+ ```svelte
438
+ <script lang="ts">
439
+ import { renderHTMLFromJSON } from '@flexiui/svelte-rich-text';
440
+
441
+ let json = { type: "doc", content: [...] };
442
+ let html = renderHTMLFromJSON({ json });
443
+ </script>
444
+
445
+ {@html html}
446
+ ```
244
447
 
245
- You can customize the behavior of the special box node by modifying the `SpecialBox` extension as needed.
448
+ ## License
246
449
 
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).
450
+ MIT