@alpaca-editor/core 1.0.3996 → 1.0.4000

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 (50) hide show
  1. package/dist/editor/field-types/InternalLinkFieldEditor.js +29 -9
  2. package/dist/editor/field-types/InternalLinkFieldEditor.js.map +1 -1
  3. package/dist/editor/field-types/TreeListEditor.js +20 -12
  4. package/dist/editor/field-types/TreeListEditor.js.map +1 -1
  5. package/dist/editor/field-types/richtext/components/ReactSlate.d.ts +3 -3
  6. package/dist/editor/field-types/richtext/components/ReactSlate.js +195 -172
  7. package/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -1
  8. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +1 -1
  9. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
  10. package/dist/editor/sidebar/MainContentTree.js +1 -1
  11. package/dist/editor/sidebar/MainContentTree.js.map +1 -1
  12. package/dist/editor/utils.d.ts +1 -0
  13. package/dist/editor/utils.js +3 -0
  14. package/dist/editor/utils.js.map +1 -1
  15. package/dist/editor/views/CompareView.js.map +1 -1
  16. package/dist/page-wizard/PageWizard.d.ts +5 -1
  17. package/dist/page-wizard/PageWizard.js.map +1 -1
  18. package/dist/page-wizard/WizardSteps.js +1 -0
  19. package/dist/page-wizard/WizardSteps.js.map +1 -1
  20. package/dist/page-wizard/steps/ComponentTypesSelector.d.ts +2 -1
  21. package/dist/page-wizard/steps/ComponentTypesSelector.js +27 -90
  22. package/dist/page-wizard/steps/ComponentTypesSelector.js.map +1 -1
  23. package/dist/page-wizard/steps/ContentStep.js +63 -11
  24. package/dist/page-wizard/steps/ContentStep.js.map +1 -1
  25. package/dist/page-wizard/steps/schema.js +4 -4
  26. package/dist/page-wizard/steps/schema.js.map +1 -1
  27. package/dist/page-wizard/steps/usePageCreator.d.ts +2 -1
  28. package/dist/page-wizard/steps/usePageCreator.js +62 -8
  29. package/dist/page-wizard/steps/usePageCreator.js.map +1 -1
  30. package/dist/page-wizard/usePageWizard.js +2 -0
  31. package/dist/page-wizard/usePageWizard.js.map +1 -1
  32. package/dist/revision.d.ts +2 -2
  33. package/dist/revision.js +2 -2
  34. package/dist/styles.css +3 -3
  35. package/package.json +1 -1
  36. package/src/editor/field-types/InternalLinkFieldEditor.tsx +99 -73
  37. package/src/editor/field-types/TreeListEditor.tsx +39 -32
  38. package/src/editor/field-types/richtext/components/ReactSlate.tsx +532 -446
  39. package/src/editor/page-editor-chrome/PlaceholderDropZone.tsx +1 -1
  40. package/src/editor/sidebar/MainContentTree.tsx +1 -0
  41. package/src/editor/utils.ts +4 -0
  42. package/src/editor/views/CompareView.tsx +1 -1
  43. package/src/page-wizard/PageWizard.tsx +5 -1
  44. package/src/page-wizard/WizardSteps.tsx +1 -0
  45. package/src/page-wizard/steps/ComponentTypesSelector.tsx +34 -115
  46. package/src/page-wizard/steps/ContentStep.tsx +83 -16
  47. package/src/page-wizard/steps/schema.ts +4 -4
  48. package/src/page-wizard/steps/usePageCreator.ts +84 -9
  49. package/src/page-wizard/usePageWizard.ts +2 -0
  50. package/src/revision.ts +2 -2
@@ -1,11 +1,18 @@
1
- import React, { useCallback, useMemo, useState, forwardRef, useRef, useEffect } from 'react';
2
- import { createEditor, Descendant, Editor, Element, Transforms } from 'slate';
3
- import { Slate, Editable, withReact, ReactEditor } from 'slate-react';
4
- import { withHistory } from 'slate-history';
5
- import isEqual from 'lodash/isEqual';
6
- import './ReactSlate.css';
7
-
8
- import {
1
+ import React, {
2
+ useCallback,
3
+ useMemo,
4
+ useState,
5
+ forwardRef,
6
+ useRef,
7
+ useEffect,
8
+ } from "react";
9
+ import { createEditor, Descendant, Editor, Element, Transforms } from "slate";
10
+ import { Slate, Editable, withReact, ReactEditor } from "slate-react";
11
+ import { withHistory } from "slate-history";
12
+ import isEqual from "lodash/isEqual";
13
+ import "./ReactSlate.css";
14
+
15
+ import {
9
16
  ReactSlateProps,
10
17
  CustomElement,
11
18
  ToolbarGroupConfig,
@@ -15,37 +22,41 @@ import {
15
22
  SimplifiedProfile,
16
23
  SLATE_MARKS,
17
24
  SLATE_BLOCKS,
18
- SLATE_ALIGNMENTS
19
- } from '../types';
25
+ SLATE_ALIGNMENTS,
26
+ } from "../types";
20
27
 
21
- import EditorDropdown from './EditorDropdown';
22
- import {ToolbarButton} from './ToolbarButton';
23
- import { LinkEditorDialog } from '../../../LinkEditorDialog';
28
+ import EditorDropdown from "./EditorDropdown";
29
+ import { ToolbarButton } from "./ToolbarButton";
30
+ import { LinkEditorDialog } from "../../../LinkEditorDialog";
24
31
 
25
- import { htmlToSlate, slateToHtml } from '../utils/conversion';
26
- import { createPluginsFromConfig } from '../config/pluginFactory';
27
- import { useCachedSimplifiedProfile } from '../hooks/useProfileCache';
28
- import { classNames } from 'primereact/utils';
32
+ import { htmlToSlate, slateToHtml } from "../utils/conversion";
33
+ import { createPluginsFromConfig } from "../config/pluginFactory";
34
+ import { useCachedSimplifiedProfile } from "../hooks/useProfileCache";
35
+ import { classNames } from "primereact/utils";
29
36
 
30
37
  // Helper function to normalize HTML for comparison
31
38
  const normalizeHtmlForComparison = (html: string): string => {
32
- if (!html) return '';
33
-
39
+ if (!html) return "";
40
+
34
41
  // Create a temporary DOM element to normalize the HTML
35
- const temp = document.createElement('div');
42
+ const temp = document.createElement("div");
36
43
  temp.innerHTML = html;
37
-
44
+
38
45
  // Remove extra whitespace and normalize structure
39
46
  const normalizedHtml = temp.innerHTML
40
- .replace(/\s+/g, ' ') // Replace multiple spaces with single space
41
- .replace(/>\s+</g, '><') // Remove spaces between tags
47
+ .replace(/\s+/g, " ") // Replace multiple spaces with single space
48
+ .replace(/>\s+</g, "><") // Remove spaces between tags
42
49
  .trim();
43
-
50
+
44
51
  // Handle common empty content patterns
45
- if (normalizedHtml === '<p><br></p>' || normalizedHtml === '<br>' || normalizedHtml === '<p></p>') {
46
- return '';
52
+ if (
53
+ normalizedHtml === "<p><br></p>" ||
54
+ normalizedHtml === "<br>" ||
55
+ normalizedHtml === "<p></p>"
56
+ ) {
57
+ return "";
47
58
  }
48
-
59
+
49
60
  return normalizedHtml;
50
61
  };
51
62
 
@@ -53,72 +64,70 @@ const normalizeHtmlForComparison = (html: string): string => {
53
64
  const isHtmlConversionStable = (
54
65
  originalHtml: string,
55
66
  slateValue: Descendant[],
56
- profile: SimplifiedProfile
67
+ profile: SimplifiedProfile,
57
68
  ): boolean => {
58
69
  try {
59
70
  // Convert Slate back to HTML
60
71
  const convertedHtml = slateToHtml(slateValue, profile);
61
-
72
+
62
73
  // Normalize both HTML strings for comparison
63
74
  const normalizedOriginal = normalizeHtmlForComparison(originalHtml);
64
75
  const normalizedConverted = normalizeHtmlForComparison(convertedHtml);
65
-
76
+
66
77
  // Debug logging (can be enabled for troubleshooting)
67
78
  // console.log('HTML Stability Check:', {
68
79
  // original: normalizedOriginal,
69
80
  // converted: normalizedConverted,
70
81
  // stable: normalizedOriginal === normalizedConverted
71
82
  // });
72
-
83
+
73
84
  // Check if they're equivalent
74
85
  return normalizedOriginal === normalizedConverted;
75
86
  } catch (error) {
76
- console.warn('HTML conversion stability check failed:', error);
87
+ console.warn("HTML conversion stability check failed:", error);
77
88
  // If we can't check stability, assume it's not stable to be safe
78
89
  return false;
79
90
  }
80
91
  };
81
92
 
82
-
83
-
84
93
  export const ReactSlate = forwardRef<any, ReactSlateProps>((props, ref) => {
85
- const {
86
- value = '',
87
- onChange,
88
- onFocus,
89
- onBlur,
94
+ const {
95
+ value = "",
96
+ onChange,
97
+ onFocus,
98
+ onBlur,
90
99
  readOnly = false,
91
- placeholder = 'Enter some text...',
92
- profile
100
+ placeholder = "Enter some text...",
101
+ profile,
93
102
  } = props;
94
103
 
95
104
  // Create the Slate editor with plugins
96
105
  const editor = useMemo(() => {
97
106
  // Start with base editor
98
107
  let slateEditor = createEditor();
99
-
108
+
100
109
  // Apply core plugins
101
110
  slateEditor = withReact(slateEditor);
102
111
  slateEditor = withHistory(slateEditor);
103
112
 
104
113
  slateEditor = createPluginsFromConfig(slateEditor);
105
-
114
+
106
115
  return slateEditor;
107
116
  }, []);
108
117
 
109
118
  const editorProfile = profile || {
110
119
  toolbar: {
111
- groups: []
112
- }
120
+ groups: [],
121
+ },
113
122
  };
114
-
123
+
115
124
  // Convert to simplified profile for the conversion functions (with caching)
116
125
  const simplifiedProfile = useCachedSimplifiedProfile(editorProfile);
117
-
126
+
118
127
  // Store the original HTML value for comparison
119
128
  const originalValueRef = useRef<string>(value);
120
129
  const isInitialLoadRef = useRef<boolean>(true);
121
-
130
+
122
131
  // Update original value when prop value changes
123
132
  useMemo(() => {
124
133
  if (value !== originalValueRef.current) {
@@ -126,12 +135,12 @@ export const ReactSlate = forwardRef<any, ReactSlateProps>((props, ref) => {
126
135
  isInitialLoadRef.current = true;
127
136
  }
128
137
  }, [value]);
129
-
138
+
130
139
  // Convert the HTML value to Slate format
131
140
  const [internalValue, setInternalValue] = useState<Descendant[]>(
132
- htmlToSlate(value, simplifiedProfile)
141
+ htmlToSlate(value, simplifiedProfile),
133
142
  );
134
-
143
+
135
144
  // Counter to force remount when value changes externally
136
145
  const [remountKey, setRemountKey] = useState(0);
137
146
 
@@ -141,110 +150,127 @@ export const ReactSlate = forwardRef<any, ReactSlateProps>((props, ref) => {
141
150
  if (!isEqual(newValue, internalValue)) {
142
151
  setInternalValue(newValue);
143
152
  // Force remount by incrementing the key
144
- setRemountKey(prev => prev + 1);
153
+ setRemountKey((prev) => prev + 1);
145
154
  }
146
155
  }, [value, simplifiedProfile]);
147
156
 
148
157
  // Handle value changes with round-trip validation
149
- const handleChange = useCallback((newValue: Descendant[]) => {
150
- setInternalValue(newValue);
151
-
152
- if (onChange) {
153
- const html = slateToHtml(newValue, simplifiedProfile);
154
-
155
- // Check if this is the initial load or if the conversion is stable
156
- if (isInitialLoadRef.current) {
157
- // On initial load, check if the HTML conversion is stable
158
- const isStable = isHtmlConversionStable(
158
+ const handleChange = useCallback(
159
+ (newValue: Descendant[]) => {
160
+ setInternalValue(newValue);
161
+
162
+ if (onChange) {
163
+ const html = slateToHtml(newValue, simplifiedProfile);
164
+
165
+ // Check if this is the initial load or if the conversion is stable
166
+ if (isInitialLoadRef.current) {
167
+ // On initial load, check if the HTML conversion is stable
168
+ const isStable = isHtmlConversionStable(
169
+ originalValueRef.current,
170
+ newValue,
171
+ simplifiedProfile,
172
+ );
173
+
174
+ if (isStable) {
175
+ // If stable, don't trigger onChange on initial load
176
+ isInitialLoadRef.current = false;
177
+ return;
178
+ }
179
+
180
+ // If not stable, we still need to proceed, but mark as no longer initial load
181
+ isInitialLoadRef.current = false;
182
+ }
183
+
184
+ // For subsequent changes, only trigger onChange if there's a meaningful difference
185
+ const normalizedNewHtml = normalizeHtmlForComparison(html);
186
+ const normalizedOriginalHtml = normalizeHtmlForComparison(
159
187
  originalValueRef.current,
160
- newValue,
161
- simplifiedProfile
162
188
  );
163
-
164
- if (isStable) {
165
- // If stable, don't trigger onChange on initial load
166
- isInitialLoadRef.current = false;
167
- return;
189
+
190
+ if (normalizedNewHtml !== normalizedOriginalHtml) {
191
+ // Update the original value reference to the new HTML
192
+ originalValueRef.current = html;
193
+ onChange(html);
168
194
  }
169
-
170
- // If not stable, we still need to proceed, but mark as no longer initial load
171
- isInitialLoadRef.current = false;
172
- }
173
-
174
- // For subsequent changes, only trigger onChange if there's a meaningful difference
175
- const normalizedNewHtml = normalizeHtmlForComparison(html);
176
- const normalizedOriginalHtml = normalizeHtmlForComparison(originalValueRef.current);
177
-
178
- if (normalizedNewHtml !== normalizedOriginalHtml) {
179
- // Update the original value reference to the new HTML
180
- originalValueRef.current = html;
181
- onChange(html);
182
195
  }
183
- }
184
- }, [onChange, simplifiedProfile]);
196
+ },
197
+ [onChange, simplifiedProfile],
198
+ );
185
199
 
186
200
  const getOption = (type: string, id: string): CustomOption | undefined => {
187
201
  switch (type) {
188
- case 'mark':
202
+ case "mark":
189
203
  const markConfig = SLATE_MARKS[id];
190
- return markConfig ? {
191
- id,
192
- label: markConfig.label,
193
- icon: markConfig.icon,
194
- isActive: (editor: Editor) => editor.isMarkActive(id),
195
- toggle: (editor: Editor, event: React.MouseEvent) => {
196
- event.preventDefault();
197
- editor.toggleMark(id);
198
- }
199
- } : undefined;
200
- case 'block':
204
+ return markConfig
205
+ ? {
206
+ id,
207
+ label: markConfig.label,
208
+ icon: markConfig.icon,
209
+ isActive: (editor: Editor) => editor.isMarkActive(id),
210
+ toggle: (editor: Editor, event: React.MouseEvent) => {
211
+ event.preventDefault();
212
+ editor.toggleMark(id);
213
+ },
214
+ }
215
+ : undefined;
216
+ case "block":
201
217
  const blockConfig = SLATE_BLOCKS[id];
202
- return blockConfig ? {
203
- id,
204
- label: blockConfig.label,
205
- icon: blockConfig.icon,
206
- isActive: (editor: Editor) => editor.isBlockActive(id),
207
- toggle: (editor: Editor, event: React.MouseEvent) => {
208
- event.preventDefault();
209
- editor.toggleBlock(id);
210
- }
211
- } : undefined;
212
- case 'alignment':
218
+ return blockConfig
219
+ ? {
220
+ id,
221
+ label: blockConfig.label,
222
+ icon: blockConfig.icon,
223
+ isActive: (editor: Editor) => editor.isBlockActive(id),
224
+ toggle: (editor: Editor, event: React.MouseEvent) => {
225
+ event.preventDefault();
226
+ editor.toggleBlock(id);
227
+ },
228
+ }
229
+ : undefined;
230
+ case "alignment":
213
231
  const alignConfig = SLATE_ALIGNMENTS[id];
214
- return alignConfig ? {
215
- id,
216
- label: alignConfig.label,
217
- icon: alignConfig.icon,
218
- isActive: (editor: Editor) => editor.isAlignActive(alignConfig.value),
219
- toggle: (editor: Editor, event: React.MouseEvent) => {
220
- event.preventDefault();
221
- editor.toggleAlign(alignConfig.value);
222
- }
223
- } : undefined;
224
- case 'link':
232
+ return alignConfig
233
+ ? {
234
+ id,
235
+ label: alignConfig.label,
236
+ icon: alignConfig.icon,
237
+ isActive: (editor: Editor) =>
238
+ editor.isAlignActive(alignConfig.value),
239
+ toggle: (editor: Editor, event: React.MouseEvent) => {
240
+ event.preventDefault();
241
+ editor.toggleAlign(alignConfig.value);
242
+ },
243
+ }
244
+ : undefined;
245
+ case "link":
225
246
  return {
226
- id: 'link',
227
- label: 'Link',
228
- icon: '🔗',
247
+ id: "link",
248
+ label: "Link",
249
+ icon: "🔗",
229
250
  isActive: (editor: Editor) => editor.isLinkActive(),
230
251
  toggle: (editor: Editor, event: React.MouseEvent) => {
231
252
  event.preventDefault();
232
253
  handleLinkButtonClick();
233
- }
254
+ },
234
255
  };
235
- case 'list':
256
+ case "list":
236
257
  return {
237
258
  id,
238
- label: id === 'unordered-list' ? 'Bulleted List' : 'Numbered List',
239
- icon: id === 'unordered-list' ? '' : '1.',
240
- isActive: (editor: Editor) => editor.isListActive(id === 'unordered-list' ? 'unordered' : 'ordered'),
259
+ label: id === "unordered-list" ? "Bulleted List" : "Numbered List",
260
+ icon: id === "unordered-list" ? "" : "1.",
261
+ isActive: (editor: Editor) =>
262
+ editor.isListActive(
263
+ id === "unordered-list" ? "unordered" : "ordered",
264
+ ),
241
265
  toggle: (editor: Editor, event: React.MouseEvent) => {
242
266
  event.preventDefault();
243
- editor.toggleList(id === 'unordered-list' ? 'unordered' : 'ordered');
244
- }
267
+ editor.toggleList(
268
+ id === "unordered-list" ? "unordered" : "ordered",
269
+ );
270
+ },
245
271
  };
246
- case 'divider':
247
- return { id: 'divider', label: 'Divider' };
272
+ case "divider":
273
+ return { id: "divider", label: "Divider" };
248
274
  default:
249
275
  return undefined;
250
276
  }
@@ -253,11 +279,11 @@ export const ReactSlate = forwardRef<any, ReactSlateProps>((props, ref) => {
253
279
  const optionHandlers = {
254
280
  mark: {
255
281
  isActive: (id: string) => editor.isMarkActive(id),
256
- toggle: (id: string) => editor.toggleMark(id)
282
+ toggle: (id: string) => editor.toggleMark(id),
257
283
  },
258
284
  block: {
259
285
  isActive: (id: string) => editor.isBlockActive(id),
260
- toggle: (id: string) => editor.toggleBlock(id)
286
+ toggle: (id: string) => editor.toggleBlock(id),
261
287
  },
262
288
  alignment: {
263
289
  isActive: (id: string) => {
@@ -269,22 +295,22 @@ export const ReactSlate = forwardRef<any, ReactSlateProps>((props, ref) => {
269
295
  if (alignConfig) {
270
296
  editor.toggleAlign(alignConfig.value);
271
297
  }
272
- }
298
+ },
273
299
  },
274
300
  link: {
275
301
  isActive: () => editor.isLinkActive(),
276
- toggle: () => handleLinkButtonClick()
302
+ toggle: () => handleLinkButtonClick(),
277
303
  },
278
304
  list: {
279
305
  isActive: (id: string) => {
280
- const listType = id === 'unordered-list' ? 'unordered' : 'ordered';
306
+ const listType = id === "unordered-list" ? "unordered" : "ordered";
281
307
  return editor.isListActive(listType);
282
308
  },
283
309
  toggle: (id: string, event: React.MouseEvent<HTMLButtonElement>) => {
284
- const listType = id === 'unordered-list' ? 'unordered' : 'ordered';
310
+ const listType = id === "unordered-list" ? "unordered" : "ordered";
285
311
  editor.toggleList(listType);
286
- }
287
- }
312
+ },
313
+ },
288
314
  };
289
315
 
290
316
  const isOptionActive = (type: string, id: string): boolean => {
@@ -292,18 +318,22 @@ export const ReactSlate = forwardRef<any, ReactSlateProps>((props, ref) => {
292
318
  return handler ? handler.isActive(id) : false;
293
319
  };
294
320
 
295
- const handleOptionSelect = (type: string, id: string) => (event: React.MouseEvent<HTMLButtonElement>) => {
296
- event.preventDefault();
297
- const handler = optionHandlers[type as keyof typeof optionHandlers];
298
- if (handler) {
299
- return handler.toggle(id, event);
300
- }
301
- console.warn(`Unhandled option type: ${type}`);
302
- };
321
+ const handleOptionSelect =
322
+ (type: string, id: string) =>
323
+ (event: React.MouseEvent<HTMLButtonElement>) => {
324
+ event.preventDefault();
325
+ const handler = optionHandlers[type as keyof typeof optionHandlers];
326
+ if (handler) {
327
+ return handler.toggle(id, event);
328
+ }
329
+ console.warn(`Unhandled option type: ${type}`);
330
+ };
303
331
 
304
- const createDropdownOptions = (options: ToolbarOptionConfig[]): DropdownOption<any>[] => {
332
+ const createDropdownOptions = (
333
+ options: ToolbarOptionConfig[],
334
+ ): DropdownOption<any>[] => {
305
335
  return options
306
- .map(option => {
336
+ .map((option) => {
307
337
  const optionObj = getOption(option.type, option.id);
308
338
  if (!optionObj) return null;
309
339
 
@@ -313,20 +343,25 @@ export const ReactSlate = forwardRef<any, ReactSlateProps>((props, ref) => {
313
343
  icon: optionObj.icon,
314
344
  style: (optionObj as any).style,
315
345
  isActive: (editor: Editor) => isOptionActive(option.type, option.id),
316
- onSelect: (editor: Editor, event: React.MouseEvent) =>
317
- handleOptionSelect(option.type, option.id)(event as React.MouseEvent<HTMLButtonElement>)
346
+ onSelect: (editor: Editor, event: React.MouseEvent) =>
347
+ handleOptionSelect(
348
+ option.type,
349
+ option.id,
350
+ )(event as React.MouseEvent<HTMLButtonElement>),
318
351
  };
319
352
  })
320
353
  .filter(Boolean) as DropdownOption<any>[];
321
354
  };
322
355
 
323
356
  // Helper function to split options by dividers into sub-groups
324
- const splitOptionsByDividers = (options: ToolbarOptionConfig[]): ToolbarOptionConfig[][] => {
357
+ const splitOptionsByDividers = (
358
+ options: ToolbarOptionConfig[],
359
+ ): ToolbarOptionConfig[][] => {
325
360
  const subGroups: ToolbarOptionConfig[][] = [];
326
361
  let currentGroup: ToolbarOptionConfig[] = [];
327
-
328
- options.forEach(option => {
329
- if (option.type === 'divider') {
362
+
363
+ options.forEach((option) => {
364
+ if (option.type === "divider") {
330
365
  if (currentGroup.length > 0) {
331
366
  subGroups.push(currentGroup);
332
367
  currentGroup = [];
@@ -335,319 +370,358 @@ export const ReactSlate = forwardRef<any, ReactSlateProps>((props, ref) => {
335
370
  currentGroup.push(option);
336
371
  }
337
372
  });
338
-
373
+
339
374
  // Add the last group if it has options
340
375
  if (currentGroup.length > 0) {
341
376
  subGroups.push(currentGroup);
342
377
  }
343
-
378
+
344
379
  return subGroups;
345
380
  };
346
381
 
347
382
  const renderToolbarGroup = (group: ToolbarGroupConfig, index: number) => {
348
- const validOptions = group.options.filter(option => getOption(option.type, option.id) || option.type === 'divider');
349
-
383
+ const validOptions = group.options.filter(
384
+ (option) =>
385
+ getOption(option.type, option.id) || option.type === "divider",
386
+ );
387
+
350
388
  if (validOptions.length === 0) return null;
351
389
 
352
390
  const groupStyle: React.CSSProperties = {
353
- display: 'flex',
354
- alignItems: 'center',
355
- gap: '8px',
356
- flexWrap: 'wrap'
391
+ display: "flex",
392
+ alignItems: "center",
393
+ gap: "8px",
394
+ flexWrap: "wrap",
357
395
  };
358
396
 
359
- return (
397
+ return (
360
398
  <div key={`group-${group.id || index}`} style={groupStyle}>
361
- {group.display === 'buttons' ? (
362
- (() => {
363
- const subGroups = splitOptionsByDividers(validOptions);
364
- return subGroups.map((subGroup, subGroupIndex) => (
365
- <div
366
- key={`subgroup-${subGroupIndex}`}
367
- className="toolbar-button-group"
368
- >
369
- {subGroup.map((option, optionIndex) => {
370
- const optionObj = getOption(option.type, option.id);
371
- if (!optionObj) return null;
372
-
373
- return (
374
- <ToolbarButton
375
- key={`${option.type}-${option.id}`}
376
- icon={optionObj.icon}
377
- active={isOptionActive(option.type, option.id)}
378
- onMouseDown={handleOptionSelect(option.type, option.id)}
379
- />
380
- );
381
- })}
382
- </div>
383
- ));
384
- })()
385
- ) : (
386
- (() => {
387
- const dropdownOptions = createDropdownOptions(validOptions);
388
- const blockOptions = validOptions.filter(option => option.type === 'block');
389
-
390
- // If there's only one block option, render it as a disabled-style button
391
- if (blockOptions.length === 1) {
392
- const singleOption = dropdownOptions.find(opt =>
393
- blockOptions.some(blockOpt =>
394
- blockOpt.type === 'block' &&
395
- getOption(blockOpt.type, blockOpt.id) === opt.value
396
- )
399
+ {group.display === "buttons"
400
+ ? (() => {
401
+ const subGroups = splitOptionsByDividers(validOptions);
402
+ return subGroups.map((subGroup, subGroupIndex) => (
403
+ <div
404
+ key={`subgroup-${subGroupIndex}`}
405
+ className="toolbar-button-group"
406
+ >
407
+ {subGroup.map((option, optionIndex) => {
408
+ const optionObj = getOption(option.type, option.id);
409
+ if (!optionObj) return null;
410
+
411
+ return (
412
+ <ToolbarButton
413
+ key={`${option.type}-${option.id}`}
414
+ icon={optionObj.icon}
415
+ active={isOptionActive(option.type, option.id)}
416
+ onMouseDown={handleOptionSelect(option.type, option.id)}
417
+ />
418
+ );
419
+ })}
420
+ </div>
421
+ ));
422
+ })()
423
+ : (() => {
424
+ const dropdownOptions = createDropdownOptions(validOptions);
425
+ const blockOptions = validOptions.filter(
426
+ (option) => option.type === "block",
397
427
  );
398
-
399
- return (
400
- <div className="toolbar-dropdown-container">
401
- <button
402
- className="toolbar-dropdown-button"
403
- disabled
404
- >
405
- {group.label ? (
406
- <>
407
- <span className="toolbar-dropdown-content">
408
- {group.label}: {singleOption?.label}
409
- </span>
410
- <span className="toolbar-dropdown-arrow">▼</span>
411
- </>
412
- ) : group.showIconsOnly ? (
413
- <>
414
- <span className="toolbar-dropdown-icon">
415
- {singleOption?.icon}
416
- </span>
417
- <span className="toolbar-dropdown-arrow">▼</span>
418
- </>
419
- ) : (
420
- <>
421
- <span className="toolbar-dropdown-icon">
422
- {singleOption?.icon && (
423
- <span className="toolbar-dropdown-icon">{singleOption.icon}</span>
424
- )}
428
+
429
+ // If there's only one block option, render it as a disabled-style button
430
+ if (blockOptions.length === 1) {
431
+ const singleOption = dropdownOptions.find((opt) =>
432
+ blockOptions.some(
433
+ (blockOpt) =>
434
+ blockOpt.type === "block" &&
435
+ getOption(blockOpt.type, blockOpt.id) === opt.value,
436
+ ),
437
+ );
438
+
439
+ return (
440
+ <div className="toolbar-dropdown-container">
441
+ <button className="toolbar-dropdown-button" disabled>
442
+ {group.label ? (
443
+ <>
425
444
  <span className="toolbar-dropdown-content">
426
- {singleOption?.label}
445
+ {group.label}: {singleOption?.label}
427
446
  </span>
428
- </span>
429
- <span className="toolbar-dropdown-arrow">▼</span>
430
- </>
431
- )}
432
- </button>
447
+ <span className="toolbar-dropdown-arrow">▼</span>
448
+ </>
449
+ ) : group.showIconsOnly ? (
450
+ <>
451
+ <span className="toolbar-dropdown-icon">
452
+ {singleOption?.icon}
453
+ </span>
454
+ <span className="toolbar-dropdown-arrow">▼</span>
455
+ </>
456
+ ) : (
457
+ <>
458
+ <span className="toolbar-dropdown-icon">
459
+ {singleOption?.icon && (
460
+ <span className="toolbar-dropdown-icon">
461
+ {singleOption.icon}
462
+ </span>
463
+ )}
464
+ <span className="toolbar-dropdown-content">
465
+ {singleOption?.label}
466
+ </span>
467
+ </span>
468
+ <span className="toolbar-dropdown-arrow">▼</span>
469
+ </>
470
+ )}
471
+ </button>
472
+ </div>
473
+ );
474
+ }
475
+
476
+ // Multiple options - render normally wrapped in grey container
477
+ const isActive = dropdownOptions.some((option) =>
478
+ option.isActive(editor),
479
+ );
480
+ return (
481
+ <div className="toolbar-dropdown-container">
482
+ <EditorDropdown
483
+ options={dropdownOptions}
484
+ editor={editor}
485
+ label={group.label}
486
+ buttonStyle={{
487
+ padding: "5px 10px",
488
+ margin: "0",
489
+ background: isActive ? "#ffffff" : "transparent",
490
+ border: "none",
491
+ borderRadius: "3px",
492
+ cursor: "pointer",
493
+ boxShadow: isActive
494
+ ? "0 1px 2px rgba(0,0,0,0.1)"
495
+ : "none",
496
+ }}
497
+ />
433
498
  </div>
434
499
  );
435
- }
436
-
437
- // Multiple options - render normally wrapped in grey container
438
- const isActive = dropdownOptions.some(option => option.isActive(editor));
439
- return (
440
- <div className="toolbar-dropdown-container">
441
- <EditorDropdown
442
- options={dropdownOptions}
443
- editor={editor}
444
- label={group.label}
445
- buttonStyle={{
446
- padding: '5px 10px',
447
- margin: '0',
448
- background: isActive ? '#ffffff' : 'transparent',
449
- border: 'none',
450
- borderRadius: '3px',
451
- cursor: 'pointer',
452
- boxShadow: isActive ? '0 1px 2px rgba(0,0,0,0.1)' : 'none'
453
- }}
454
- />
455
- </div>
456
- );
457
- })()
458
- )}
500
+ })()}
459
501
  </div>
460
502
  );
461
503
  };
462
504
 
463
505
  const [showLinkDialog, setShowLinkDialog] = useState(false);
464
506
  const [selectedLink, setSelectedLink] = useState<any>(null);
465
- const [linkDialogCallback, setLinkDialogCallback] = useState<((link: any) => void) | null>(null);
507
+ const [linkDialogCallback, setLinkDialogCallback] = useState<
508
+ ((link: any) => void) | null
509
+ >(null);
466
510
 
467
511
  const editLink = useCallback((element: any) => {
468
- const linkType = element.link?.type || 'external';
512
+ const linkType = element.link?.type || "external";
469
513
  let linkData;
470
-
471
- if (linkType === 'internal') {
514
+
515
+ if (linkType === "internal") {
472
516
  linkData = {
473
- type: 'internal',
474
- itemId: element.link?.itemId || element.link?.targetItemLongId?.split("/").pop() || '',
475
- targetItemLongId: element.link?.targetItemLongId || '',
476
- target: element.link?.target || '',
477
- queryString: element.link?.queryString || ''
517
+ type: "internal",
518
+ itemId:
519
+ element.link?.itemId ||
520
+ element.link?.targetItemLongId?.split("/").pop() ||
521
+ "",
522
+ targetItemLongId: element.link?.targetItemLongId || "",
523
+ target: element.link?.target || "",
524
+ queryString: element.link?.queryString || "",
478
525
  };
479
526
  } else {
480
527
  linkData = {
481
- type: 'external',
482
- url: element.url || element.link?.url || '',
483
- target: element.link?.target || '_blank',
484
- queryString: element.link?.queryString || ''
528
+ type: "external",
529
+ url: element.url || element.link?.url || "",
530
+ target: element.link?.target || "_blank",
531
+ queryString: element.link?.queryString || "",
485
532
  };
486
533
  }
487
-
534
+
488
535
  setSelectedLink(linkData);
489
536
  setShowLinkDialog(true);
490
537
  }, []);
491
538
 
492
- const handleLinkUpdate = useCallback((link: any) => {
493
- if (linkDialogCallback) {
494
- linkDialogCallback(link);
495
- setLinkDialogCallback(null);
496
- } else {
497
- const [linkNode] = Editor.nodes(editor, {
498
- match: n => !Editor.isEditor(n) && Element.isElement(n) && n.type === 'link'
499
- });
500
-
501
- if (linkNode) {
502
- const [node, path] = linkNode;
503
- let newProperties: Partial<CustomElement>;
504
-
505
- if (link.type === 'internal') {
506
- newProperties = {
507
- url: '',
508
- link: {
509
- type: 'internal',
510
- targetItemLongId: link.targetItemLongId,
511
- itemId: link.itemId,
512
- target: link.target,
513
- queryString: link.queryString
514
- }
515
- };
516
- } else {
517
- newProperties = {
518
- url: link.url,
519
- link: {
520
- type: 'external',
539
+ const handleLinkUpdate = useCallback(
540
+ (link: any) => {
541
+ if (linkDialogCallback) {
542
+ linkDialogCallback(link);
543
+ setLinkDialogCallback(null);
544
+ } else {
545
+ const [linkNode] = Editor.nodes(editor, {
546
+ match: (n) =>
547
+ !Editor.isEditor(n) && Element.isElement(n) && n.type === "link",
548
+ });
549
+
550
+ if (linkNode) {
551
+ const [node, path] = linkNode;
552
+ let newProperties: Partial<CustomElement>;
553
+
554
+ if (link.type === "internal") {
555
+ newProperties = {
556
+ url: "",
557
+ link: {
558
+ type: "internal",
559
+ targetItemLongId: link.targetItemLongId,
560
+ itemId: link.itemId,
561
+ target: link.target,
562
+ queryString: link.queryString,
563
+ },
564
+ };
565
+ } else {
566
+ newProperties = {
521
567
  url: link.url,
522
- target: link.target,
523
- queryString: link.queryString
524
- }
525
- };
526
- }
527
-
528
- Transforms.setNodes(editor, newProperties, { at: path });
529
-
530
- // Move cursor after the link
531
- const after = Editor.after(editor, path);
532
- if (after) {
533
- Transforms.select(editor, after);
568
+ link: {
569
+ type: "external",
570
+ url: link.url,
571
+ target: link.target,
572
+ queryString: link.queryString,
573
+ },
574
+ };
575
+ }
576
+
577
+ Transforms.setNodes(editor, newProperties, { at: path });
578
+
579
+ // Move cursor after the link
580
+ const after = Editor.after(editor, path);
581
+ if (after) {
582
+ Transforms.select(editor, after);
583
+ }
584
+
585
+ ReactEditor.focus(editor);
534
586
  }
535
-
536
- ReactEditor.focus(editor);
537
587
  }
538
- }
539
-
540
- setShowLinkDialog(false);
541
- setSelectedLink(null);
542
- }, [editor, linkDialogCallback]);
588
+
589
+ setShowLinkDialog(false);
590
+ setSelectedLink(null);
591
+ },
592
+ [editor, linkDialogCallback],
593
+ );
543
594
 
544
595
  const handleLinkButtonClick = useCallback(() => {
545
596
  editor.insertLink({
546
597
  onOpenLinkDialog: (callback: (link: any) => void) => {
547
- setSelectedLink({
548
- type: 'external',
549
- url: '',
550
- target: '_blank'
598
+ setSelectedLink({
599
+ type: "external",
600
+ url: "",
601
+ target: "_blank",
551
602
  });
552
603
  setShowLinkDialog(true);
553
-
604
+
554
605
  setLinkDialogCallback(() => callback);
555
- }
606
+ },
556
607
  });
557
608
  }, [editor]);
558
609
 
559
- const handleKeyDown = useCallback((event: React.KeyboardEvent) => {
560
- if (event.key === 'Enter' && event.shiftKey) {
561
- // Handle Shift+Enter for line breaks in all block types
562
- event.preventDefault();
563
-
564
- if (editor.selection) {
565
- // Insert literal <br> text
566
- editor.insertText('<br>');
567
- }
568
- } else if (event.key === 'Tab') {
569
- event.preventDefault();
570
-
571
- // Check if we're in a list item more explicitly
572
- if (editor.selection) {
573
- // Try to find the closest list item ancestor using Editor.above
574
- const listItem = Editor.above(editor, {
575
- at: editor.selection,
576
- match: n => !Editor.isEditor(n) && Element.isElement(n) && n.type === 'list-item'
577
- });
578
-
579
- if (listItem) {
580
- if (event.shiftKey) {
581
- // Shift+Tab: Outdent
582
- editor.outdentList();
583
- } else {
584
- // Tab: Indent
585
- editor.indentList();
610
+ const handleKeyDown = useCallback(
611
+ (event: React.KeyboardEvent) => {
612
+ if (event.key === "Enter" && event.shiftKey) {
613
+ // Handle Shift+Enter for line breaks in all block types
614
+ event.preventDefault();
615
+
616
+ if (editor.selection) {
617
+ // Insert literal <br> text
618
+ editor.insertText("<br>");
619
+ }
620
+ } else if (event.key === "Tab") {
621
+ event.preventDefault();
622
+
623
+ // Check if we're in a list item more explicitly
624
+ if (editor.selection) {
625
+ // Try to find the closest list item ancestor using Editor.above
626
+ const listItem = Editor.above(editor, {
627
+ at: editor.selection,
628
+ match: (n) =>
629
+ !Editor.isEditor(n) &&
630
+ Element.isElement(n) &&
631
+ n.type === "list-item",
632
+ });
633
+
634
+ if (listItem) {
635
+ if (event.shiftKey) {
636
+ // Shift+Tab: Outdent
637
+ editor.outdentList();
638
+ } else {
639
+ // Tab: Indent
640
+ editor.indentList();
641
+ }
586
642
  }
587
643
  }
588
- }
589
- } else if (event.key === 'Backspace' || event.key === 'Delete') {
590
- // Handle empty list items
591
- if (editor.selection) {
592
- const listItem = Editor.above(editor, {
593
- at: editor.selection,
594
- match: n => !Editor.isEditor(n) && Element.isElement(n) && n.type === 'list-item'
595
- });
596
-
597
- if (listItem) {
598
- const selectedText = Editor.string(editor, editor.selection);
599
- const [node, path] = listItem;
600
- const nodeText = Editor.string(editor, path);
601
-
602
- // If the list item is empty or only contains whitespace, convert to paragraph
603
- if (!nodeText.trim() || (selectedText === nodeText && nodeText.trim())) {
604
- event.preventDefault();
605
- Transforms.setNodes(
606
- editor,
607
- { type: 'paragraph', listType: undefined, indent: undefined },
608
- {
609
- match: n => !Editor.isEditor(n) && Element.isElement(n) && n.type === 'list-item',
610
- split: true
611
- }
612
- );
644
+ } else if (event.key === "Backspace" || event.key === "Delete") {
645
+ // Handle empty list items
646
+ if (editor.selection) {
647
+ const listItem = Editor.above(editor, {
648
+ at: editor.selection,
649
+ match: (n) =>
650
+ !Editor.isEditor(n) &&
651
+ Element.isElement(n) &&
652
+ n.type === "list-item",
653
+ });
654
+
655
+ if (listItem) {
656
+ const selectedText = Editor.string(editor, editor.selection);
657
+ const [node, path] = listItem;
658
+ const nodeText = Editor.string(editor, path);
659
+
660
+ // If the list item is empty or only contains whitespace, convert to paragraph
661
+ if (
662
+ !nodeText.trim() ||
663
+ (selectedText === nodeText && nodeText.trim())
664
+ ) {
665
+ event.preventDefault();
666
+ Transforms.setNodes(
667
+ editor,
668
+ { type: "paragraph", listType: undefined, indent: undefined },
669
+ {
670
+ match: (n) =>
671
+ !Editor.isEditor(n) &&
672
+ Element.isElement(n) &&
673
+ n.type === "list-item",
674
+ split: true,
675
+ },
676
+ );
677
+ }
613
678
  }
614
679
  }
615
680
  }
616
- }
617
- }, [editor]);
681
+ },
682
+ [editor],
683
+ );
618
684
 
619
685
  return (
620
686
  <div className={`slate-editor ${props.className}`}>
621
- <Slate
622
- key={remountKey}
623
- editor={editor}
624
- initialValue={internalValue}
687
+ <Slate
688
+ key={remountKey}
689
+ editor={editor}
690
+ initialValue={internalValue}
625
691
  onChange={handleChange}
626
692
  >
627
693
  {!readOnly && (
628
694
  <div className="toolbar">
629
695
  {(() => {
630
696
  // Group toolbar items by row
631
- const groupsByRow = editorProfile.toolbar.groups.reduce((acc, group, index) => {
632
- const row = group.row !== undefined ? group.row : index;
633
- if (!acc[row]) acc[row] = [];
634
- acc[row].push(group);
635
- return acc;
636
- }, {} as Record<number, typeof editorProfile.toolbar.groups>);
637
-
697
+ const groupsByRow = editorProfile.toolbar.groups.reduce(
698
+ (acc, group, index) => {
699
+ const row = group.row !== undefined ? group.row : index;
700
+ if (!acc[row]) acc[row] = [];
701
+ acc[row].push(group);
702
+ return acc;
703
+ },
704
+ {} as Record<number, typeof editorProfile.toolbar.groups>,
705
+ );
706
+
638
707
  // Render each row
639
708
  return Object.entries(groupsByRow)
640
709
  .sort(([a], [b]) => parseInt(a) - parseInt(b))
641
710
  .map(([rowIndex, rowGroups]) => (
642
711
  <div key={`row-${rowIndex}`} className="toolbar-row">
643
- {rowGroups.map(group => renderToolbarGroup(group, parseInt(rowIndex)))}
712
+ {rowGroups.map((group) =>
713
+ renderToolbarGroup(group, parseInt(rowIndex)),
714
+ )}
644
715
  </div>
645
716
  ));
646
717
  })()}
647
718
  </div>
648
719
  )}
649
720
  <Editable
650
- className={classNames(readOnly ? "bg-gray-4" : "bg-gray-5", "focus-shadow")}
721
+ className={classNames(
722
+ readOnly ? "bg-gray-4" : "bg-gray-5",
723
+ "focus-shadow p-2",
724
+ )}
651
725
  readOnly={readOnly}
652
726
  placeholder={placeholder}
653
727
  onFocus={onFocus}
@@ -655,19 +729,21 @@ export const ReactSlate = forwardRef<any, ReactSlateProps>((props, ref) => {
655
729
  onKeyDown={handleKeyDown}
656
730
  renderElement={({ attributes, children, element }) => {
657
731
  const style: React.CSSProperties = {
658
- textAlign: element.align || 'left',
732
+ textAlign: element.align || "left",
659
733
  };
660
-
661
- if (element.type === 'link') {
662
- const isInternal = element.link?.type === 'internal';
663
- const url = isInternal ? '#' : (element.url || element.link?.url || '#');
664
-
734
+
735
+ if (element.type === "link") {
736
+ const isInternal = element.link?.type === "internal";
737
+ const url = isInternal
738
+ ? "#"
739
+ : element.url || element.link?.url || "#";
740
+
665
741
  return (
666
- <a
667
- {...attributes}
742
+ <a
743
+ {...attributes}
668
744
  href={url}
669
745
  style={style}
670
- className={`slate-link ${isInternal ? 'internal-link' : 'external-link'}`}
746
+ className={`slate-link ${isInternal ? "internal-link" : "external-link"}`}
671
747
  onClick={(e) => {
672
748
  if (!readOnly) {
673
749
  e.preventDefault();
@@ -679,94 +755,104 @@ export const ReactSlate = forwardRef<any, ReactSlateProps>((props, ref) => {
679
755
  </a>
680
756
  );
681
757
  }
682
-
683
- if (element.type === 'list-item') {
758
+
759
+ if (element.type === "list-item") {
684
760
  const indent = element.indent || 0;
685
- const listType = element.listType || 'unordered';
686
- const isOrdered = listType === 'ordered';
687
-
761
+ const listType = element.listType || "unordered";
762
+ const isOrdered = listType === "ordered";
763
+
688
764
  // Calculate proper numbering for ordered lists
689
765
  let listNumber = 1;
690
766
  if (isOrdered) {
691
767
  // Find the position of this item within its level
692
768
  const allElements = editor.children as CustomElement[];
693
- const currentIndex = allElements.findIndex(el => el === element);
694
-
769
+ const currentIndex = allElements.findIndex(
770
+ (el) => el === element,
771
+ );
772
+
695
773
  // Count preceding list items at the same indent level and list type
696
774
  let count = 0;
697
775
  for (let i = 0; i < currentIndex; i++) {
698
776
  const prevElement = allElements[i];
699
- if (prevElement &&
700
- prevElement.type === 'list-item' &&
701
- prevElement.listType === 'ordered' &&
702
- (prevElement.indent || 0) === indent) {
777
+ if (
778
+ prevElement &&
779
+ prevElement.type === "list-item" &&
780
+ prevElement.listType === "ordered" &&
781
+ (prevElement.indent || 0) === indent
782
+ ) {
703
783
  count++;
704
- } else if (prevElement &&
705
- prevElement.type === 'list-item' &&
706
- (prevElement.indent || 0) < indent) {
784
+ } else if (
785
+ prevElement &&
786
+ prevElement.type === "list-item" &&
787
+ (prevElement.indent || 0) < indent
788
+ ) {
707
789
  // Reset count when we encounter a parent-level item
708
790
  count = 0;
709
791
  }
710
792
  }
711
793
  listNumber = count + 1;
712
794
  }
713
-
795
+
714
796
  const listStyle: React.CSSProperties = {
715
797
  ...style,
716
- position: 'relative',
717
- listStyleType: 'none',
798
+ position: "relative",
799
+ listStyleType: "none",
718
800
  };
719
-
720
- const bulletContent = isOrdered ? `${listNumber}.` : '';
721
-
801
+
802
+ const bulletContent = isOrdered ? `${listNumber}.` : "";
803
+
722
804
  return (
723
- <div
724
- {...attributes}
805
+ <div
806
+ {...attributes}
725
807
  style={listStyle}
726
808
  className={`slate-list-item slate-list-${listType}`}
727
809
  data-indent={indent}
728
810
  >
729
- <span className="slate-list-bullet">
730
- {bulletContent}
731
- </span>
732
- <div className="slate-list-content">
733
- {children}
734
- </div>
811
+ <span className="slate-list-bullet">{bulletContent}</span>
812
+ <div className="slate-list-content">{children}</div>
735
813
  </div>
736
814
  );
737
815
  }
738
-
816
+
739
817
  // Handle different block types using built-in SLATE_BLOCKS configuration
740
818
  const blockConfig = SLATE_BLOCKS[element.type];
741
- if (blockConfig && element.type === 'no-tag') {
819
+ if (blockConfig && element.type === "no-tag") {
742
820
  // Special handling for no-tag blocks (plain text without wrapper)
743
- return <span {...attributes} style={style}>{children}</span>;
821
+ return (
822
+ <span {...attributes} style={style}>
823
+ {children}
824
+ </span>
825
+ );
744
826
  }
745
-
827
+
746
828
  // For standard blocks, use the appropriate HTML tag
747
829
  if (blockConfig) {
748
830
  const tagName = blockConfig.htmlTag;
749
- return React.createElement(tagName, { ...attributes, style }, children);
831
+ return React.createElement(
832
+ tagName,
833
+ { ...attributes, style },
834
+ children,
835
+ );
750
836
  }
751
-
837
+
752
838
  // Default fallback to paragraph
753
- return <p {...attributes} style={style}>{children}</p>;
839
+ return (
840
+ <p {...attributes} style={style}>
841
+ {children}
842
+ </p>
843
+ );
754
844
  }}
755
845
  renderLeaf={({ attributes, children, leaf }) => {
756
846
  let el = <span {...attributes}>{children}</span>;
757
-
847
+
758
848
  // Apply marks using the built-in SLATE_MARKS configuration
759
- simplifiedProfile.marks.forEach(markId => {
849
+ simplifiedProfile.marks.forEach((markId) => {
760
850
  if ((leaf as any)[markId]) {
761
851
  const markConfig = SLATE_MARKS[markId];
762
852
  if (markConfig) {
763
- if (markId === 'extrabold') {
853
+ if (markId === "extrabold") {
764
854
  // Special handling for extrabold with CSS class
765
- el = (
766
- <span className="extrabold">
767
- {el}
768
- </span>
769
- );
855
+ el = <span className="extrabold">{el}</span>;
770
856
  } else {
771
857
  // Standard HTML tag rendering
772
858
  const tagName = markConfig.htmlTag;
@@ -775,12 +861,12 @@ export const ReactSlate = forwardRef<any, ReactSlateProps>((props, ref) => {
775
861
  }
776
862
  }
777
863
  });
778
-
864
+
779
865
  return el;
780
866
  }}
781
867
  />
782
868
  </Slate>
783
-
869
+
784
870
  {showLinkDialog && selectedLink && (
785
871
  <LinkEditorDialog
786
872
  linkValue={selectedLink}
@@ -796,6 +882,6 @@ export const ReactSlate = forwardRef<any, ReactSlateProps>((props, ref) => {
796
882
  );
797
883
  });
798
884
 
799
- ReactSlate.displayName = 'ReactSlate';
885
+ ReactSlate.displayName = "ReactSlate";
800
886
 
801
887
  export default ReactSlate;