@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.
- package/dist/editor/field-types/InternalLinkFieldEditor.js +29 -9
- package/dist/editor/field-types/InternalLinkFieldEditor.js.map +1 -1
- package/dist/editor/field-types/TreeListEditor.js +20 -12
- package/dist/editor/field-types/TreeListEditor.js.map +1 -1
- package/dist/editor/field-types/richtext/components/ReactSlate.d.ts +3 -3
- package/dist/editor/field-types/richtext/components/ReactSlate.js +195 -172
- package/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +1 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
- package/dist/editor/sidebar/MainContentTree.js +1 -1
- package/dist/editor/sidebar/MainContentTree.js.map +1 -1
- package/dist/editor/utils.d.ts +1 -0
- package/dist/editor/utils.js +3 -0
- package/dist/editor/utils.js.map +1 -1
- package/dist/editor/views/CompareView.js.map +1 -1
- package/dist/page-wizard/PageWizard.d.ts +5 -1
- package/dist/page-wizard/PageWizard.js.map +1 -1
- package/dist/page-wizard/WizardSteps.js +1 -0
- package/dist/page-wizard/WizardSteps.js.map +1 -1
- package/dist/page-wizard/steps/ComponentTypesSelector.d.ts +2 -1
- package/dist/page-wizard/steps/ComponentTypesSelector.js +27 -90
- package/dist/page-wizard/steps/ComponentTypesSelector.js.map +1 -1
- package/dist/page-wizard/steps/ContentStep.js +63 -11
- package/dist/page-wizard/steps/ContentStep.js.map +1 -1
- package/dist/page-wizard/steps/schema.js +4 -4
- package/dist/page-wizard/steps/schema.js.map +1 -1
- package/dist/page-wizard/steps/usePageCreator.d.ts +2 -1
- package/dist/page-wizard/steps/usePageCreator.js +62 -8
- package/dist/page-wizard/steps/usePageCreator.js.map +1 -1
- package/dist/page-wizard/usePageWizard.js +2 -0
- package/dist/page-wizard/usePageWizard.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/styles.css +3 -3
- package/package.json +1 -1
- package/src/editor/field-types/InternalLinkFieldEditor.tsx +99 -73
- package/src/editor/field-types/TreeListEditor.tsx +39 -32
- package/src/editor/field-types/richtext/components/ReactSlate.tsx +532 -446
- package/src/editor/page-editor-chrome/PlaceholderDropZone.tsx +1 -1
- package/src/editor/sidebar/MainContentTree.tsx +1 -0
- package/src/editor/utils.ts +4 -0
- package/src/editor/views/CompareView.tsx +1 -1
- package/src/page-wizard/PageWizard.tsx +5 -1
- package/src/page-wizard/WizardSteps.tsx +1 -0
- package/src/page-wizard/steps/ComponentTypesSelector.tsx +34 -115
- package/src/page-wizard/steps/ContentStep.tsx +83 -16
- package/src/page-wizard/steps/schema.ts +4 -4
- package/src/page-wizard/steps/usePageCreator.ts +84 -9
- package/src/page-wizard/usePageWizard.ts +2 -0
- package/src/revision.ts +2 -2
|
@@ -1,33 +1,35 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import React, { useCallback, useMemo, useState, forwardRef, useRef, useEffect } from
|
|
3
|
-
import { createEditor, Editor, Element, Transforms } from
|
|
4
|
-
import { Slate, Editable, withReact, ReactEditor } from
|
|
5
|
-
import { withHistory } from
|
|
6
|
-
import isEqual from
|
|
7
|
-
import
|
|
8
|
-
import { SLATE_MARKS, SLATE_BLOCKS, SLATE_ALIGNMENTS } from
|
|
9
|
-
import EditorDropdown from
|
|
10
|
-
import { ToolbarButton } from
|
|
11
|
-
import { LinkEditorDialog } from
|
|
12
|
-
import { htmlToSlate, slateToHtml } from
|
|
13
|
-
import { createPluginsFromConfig } from
|
|
14
|
-
import { useCachedSimplifiedProfile } from
|
|
15
|
-
import { classNames } from
|
|
2
|
+
import React, { useCallback, useMemo, useState, forwardRef, useRef, useEffect, } from "react";
|
|
3
|
+
import { createEditor, Editor, Element, Transforms } from "slate";
|
|
4
|
+
import { Slate, Editable, withReact, ReactEditor } from "slate-react";
|
|
5
|
+
import { withHistory } from "slate-history";
|
|
6
|
+
import isEqual from "lodash/isEqual";
|
|
7
|
+
import "./ReactSlate.css";
|
|
8
|
+
import { SLATE_MARKS, SLATE_BLOCKS, SLATE_ALIGNMENTS, } from "../types";
|
|
9
|
+
import EditorDropdown from "./EditorDropdown";
|
|
10
|
+
import { ToolbarButton } from "./ToolbarButton";
|
|
11
|
+
import { LinkEditorDialog } from "../../../LinkEditorDialog";
|
|
12
|
+
import { htmlToSlate, slateToHtml } from "../utils/conversion";
|
|
13
|
+
import { createPluginsFromConfig } from "../config/pluginFactory";
|
|
14
|
+
import { useCachedSimplifiedProfile } from "../hooks/useProfileCache";
|
|
15
|
+
import { classNames } from "primereact/utils";
|
|
16
16
|
// Helper function to normalize HTML for comparison
|
|
17
17
|
const normalizeHtmlForComparison = (html) => {
|
|
18
18
|
if (!html)
|
|
19
|
-
return
|
|
19
|
+
return "";
|
|
20
20
|
// Create a temporary DOM element to normalize the HTML
|
|
21
|
-
const temp = document.createElement(
|
|
21
|
+
const temp = document.createElement("div");
|
|
22
22
|
temp.innerHTML = html;
|
|
23
23
|
// Remove extra whitespace and normalize structure
|
|
24
24
|
const normalizedHtml = temp.innerHTML
|
|
25
|
-
.replace(/\s+/g,
|
|
26
|
-
.replace(/>\s+</g,
|
|
25
|
+
.replace(/\s+/g, " ") // Replace multiple spaces with single space
|
|
26
|
+
.replace(/>\s+</g, "><") // Remove spaces between tags
|
|
27
27
|
.trim();
|
|
28
28
|
// Handle common empty content patterns
|
|
29
|
-
if (normalizedHtml ===
|
|
30
|
-
|
|
29
|
+
if (normalizedHtml === "<p><br></p>" ||
|
|
30
|
+
normalizedHtml === "<br>" ||
|
|
31
|
+
normalizedHtml === "<p></p>") {
|
|
32
|
+
return "";
|
|
31
33
|
}
|
|
32
34
|
return normalizedHtml;
|
|
33
35
|
};
|
|
@@ -49,13 +51,13 @@ const isHtmlConversionStable = (originalHtml, slateValue, profile) => {
|
|
|
49
51
|
return normalizedOriginal === normalizedConverted;
|
|
50
52
|
}
|
|
51
53
|
catch (error) {
|
|
52
|
-
console.warn(
|
|
54
|
+
console.warn("HTML conversion stability check failed:", error);
|
|
53
55
|
// If we can't check stability, assume it's not stable to be safe
|
|
54
56
|
return false;
|
|
55
57
|
}
|
|
56
58
|
};
|
|
57
59
|
export const ReactSlate = forwardRef((props, ref) => {
|
|
58
|
-
const { value =
|
|
60
|
+
const { value = "", onChange, onFocus, onBlur, readOnly = false, placeholder = "Enter some text...", profile, } = props;
|
|
59
61
|
// Create the Slate editor with plugins
|
|
60
62
|
const editor = useMemo(() => {
|
|
61
63
|
// Start with base editor
|
|
@@ -68,8 +70,8 @@ export const ReactSlate = forwardRef((props, ref) => {
|
|
|
68
70
|
}, []);
|
|
69
71
|
const editorProfile = profile || {
|
|
70
72
|
toolbar: {
|
|
71
|
-
groups: []
|
|
72
|
-
}
|
|
73
|
+
groups: [],
|
|
74
|
+
},
|
|
73
75
|
};
|
|
74
76
|
// Convert to simplified profile for the conversion functions (with caching)
|
|
75
77
|
const simplifiedProfile = useCachedSimplifiedProfile(editorProfile);
|
|
@@ -93,7 +95,7 @@ export const ReactSlate = forwardRef((props, ref) => {
|
|
|
93
95
|
if (!isEqual(newValue, internalValue)) {
|
|
94
96
|
setInternalValue(newValue);
|
|
95
97
|
// Force remount by incrementing the key
|
|
96
|
-
setRemountKey(prev => prev + 1);
|
|
98
|
+
setRemountKey((prev) => prev + 1);
|
|
97
99
|
}
|
|
98
100
|
}, [value, simplifiedProfile]);
|
|
99
101
|
// Handle value changes with round-trip validation
|
|
@@ -125,66 +127,72 @@ export const ReactSlate = forwardRef((props, ref) => {
|
|
|
125
127
|
}, [onChange, simplifiedProfile]);
|
|
126
128
|
const getOption = (type, id) => {
|
|
127
129
|
switch (type) {
|
|
128
|
-
case
|
|
130
|
+
case "mark":
|
|
129
131
|
const markConfig = SLATE_MARKS[id];
|
|
130
|
-
return markConfig
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
event
|
|
137
|
-
|
|
132
|
+
return markConfig
|
|
133
|
+
? {
|
|
134
|
+
id,
|
|
135
|
+
label: markConfig.label,
|
|
136
|
+
icon: markConfig.icon,
|
|
137
|
+
isActive: (editor) => editor.isMarkActive(id),
|
|
138
|
+
toggle: (editor, event) => {
|
|
139
|
+
event.preventDefault();
|
|
140
|
+
editor.toggleMark(id);
|
|
141
|
+
},
|
|
138
142
|
}
|
|
139
|
-
|
|
140
|
-
case
|
|
143
|
+
: undefined;
|
|
144
|
+
case "block":
|
|
141
145
|
const blockConfig = SLATE_BLOCKS[id];
|
|
142
|
-
return blockConfig
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
event
|
|
149
|
-
|
|
146
|
+
return blockConfig
|
|
147
|
+
? {
|
|
148
|
+
id,
|
|
149
|
+
label: blockConfig.label,
|
|
150
|
+
icon: blockConfig.icon,
|
|
151
|
+
isActive: (editor) => editor.isBlockActive(id),
|
|
152
|
+
toggle: (editor, event) => {
|
|
153
|
+
event.preventDefault();
|
|
154
|
+
editor.toggleBlock(id);
|
|
155
|
+
},
|
|
150
156
|
}
|
|
151
|
-
|
|
152
|
-
case
|
|
157
|
+
: undefined;
|
|
158
|
+
case "alignment":
|
|
153
159
|
const alignConfig = SLATE_ALIGNMENTS[id];
|
|
154
|
-
return alignConfig
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
event
|
|
161
|
-
|
|
160
|
+
return alignConfig
|
|
161
|
+
? {
|
|
162
|
+
id,
|
|
163
|
+
label: alignConfig.label,
|
|
164
|
+
icon: alignConfig.icon,
|
|
165
|
+
isActive: (editor) => editor.isAlignActive(alignConfig.value),
|
|
166
|
+
toggle: (editor, event) => {
|
|
167
|
+
event.preventDefault();
|
|
168
|
+
editor.toggleAlign(alignConfig.value);
|
|
169
|
+
},
|
|
162
170
|
}
|
|
163
|
-
|
|
164
|
-
case
|
|
171
|
+
: undefined;
|
|
172
|
+
case "link":
|
|
165
173
|
return {
|
|
166
|
-
id:
|
|
167
|
-
label:
|
|
168
|
-
icon:
|
|
174
|
+
id: "link",
|
|
175
|
+
label: "Link",
|
|
176
|
+
icon: "🔗",
|
|
169
177
|
isActive: (editor) => editor.isLinkActive(),
|
|
170
178
|
toggle: (editor, event) => {
|
|
171
179
|
event.preventDefault();
|
|
172
180
|
handleLinkButtonClick();
|
|
173
|
-
}
|
|
181
|
+
},
|
|
174
182
|
};
|
|
175
|
-
case
|
|
183
|
+
case "list":
|
|
176
184
|
return {
|
|
177
185
|
id,
|
|
178
|
-
label: id ===
|
|
179
|
-
icon: id ===
|
|
180
|
-
isActive: (editor) => editor.isListActive(id ===
|
|
186
|
+
label: id === "unordered-list" ? "Bulleted List" : "Numbered List",
|
|
187
|
+
icon: id === "unordered-list" ? "•" : "1.",
|
|
188
|
+
isActive: (editor) => editor.isListActive(id === "unordered-list" ? "unordered" : "ordered"),
|
|
181
189
|
toggle: (editor, event) => {
|
|
182
190
|
event.preventDefault();
|
|
183
|
-
editor.toggleList(id ===
|
|
184
|
-
}
|
|
191
|
+
editor.toggleList(id === "unordered-list" ? "unordered" : "ordered");
|
|
192
|
+
},
|
|
185
193
|
};
|
|
186
|
-
case
|
|
187
|
-
return { id:
|
|
194
|
+
case "divider":
|
|
195
|
+
return { id: "divider", label: "Divider" };
|
|
188
196
|
default:
|
|
189
197
|
return undefined;
|
|
190
198
|
}
|
|
@@ -192,11 +200,11 @@ export const ReactSlate = forwardRef((props, ref) => {
|
|
|
192
200
|
const optionHandlers = {
|
|
193
201
|
mark: {
|
|
194
202
|
isActive: (id) => editor.isMarkActive(id),
|
|
195
|
-
toggle: (id) => editor.toggleMark(id)
|
|
203
|
+
toggle: (id) => editor.toggleMark(id),
|
|
196
204
|
},
|
|
197
205
|
block: {
|
|
198
206
|
isActive: (id) => editor.isBlockActive(id),
|
|
199
|
-
toggle: (id) => editor.toggleBlock(id)
|
|
207
|
+
toggle: (id) => editor.toggleBlock(id),
|
|
200
208
|
},
|
|
201
209
|
alignment: {
|
|
202
210
|
isActive: (id) => {
|
|
@@ -208,22 +216,22 @@ export const ReactSlate = forwardRef((props, ref) => {
|
|
|
208
216
|
if (alignConfig) {
|
|
209
217
|
editor.toggleAlign(alignConfig.value);
|
|
210
218
|
}
|
|
211
|
-
}
|
|
219
|
+
},
|
|
212
220
|
},
|
|
213
221
|
link: {
|
|
214
222
|
isActive: () => editor.isLinkActive(),
|
|
215
|
-
toggle: () => handleLinkButtonClick()
|
|
223
|
+
toggle: () => handleLinkButtonClick(),
|
|
216
224
|
},
|
|
217
225
|
list: {
|
|
218
226
|
isActive: (id) => {
|
|
219
|
-
const listType = id ===
|
|
227
|
+
const listType = id === "unordered-list" ? "unordered" : "ordered";
|
|
220
228
|
return editor.isListActive(listType);
|
|
221
229
|
},
|
|
222
230
|
toggle: (id, event) => {
|
|
223
|
-
const listType = id ===
|
|
231
|
+
const listType = id === "unordered-list" ? "unordered" : "ordered";
|
|
224
232
|
editor.toggleList(listType);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
233
|
+
},
|
|
234
|
+
},
|
|
227
235
|
};
|
|
228
236
|
const isOptionActive = (type, id) => {
|
|
229
237
|
const handler = optionHandlers[type];
|
|
@@ -239,7 +247,7 @@ export const ReactSlate = forwardRef((props, ref) => {
|
|
|
239
247
|
};
|
|
240
248
|
const createDropdownOptions = (options) => {
|
|
241
249
|
return options
|
|
242
|
-
.map(option => {
|
|
250
|
+
.map((option) => {
|
|
243
251
|
const optionObj = getOption(option.type, option.id);
|
|
244
252
|
if (!optionObj)
|
|
245
253
|
return null;
|
|
@@ -249,7 +257,7 @@ export const ReactSlate = forwardRef((props, ref) => {
|
|
|
249
257
|
icon: optionObj.icon,
|
|
250
258
|
style: optionObj.style,
|
|
251
259
|
isActive: (editor) => isOptionActive(option.type, option.id),
|
|
252
|
-
onSelect: (editor, event) => handleOptionSelect(option.type, option.id)(event)
|
|
260
|
+
onSelect: (editor, event) => handleOptionSelect(option.type, option.id)(event),
|
|
253
261
|
};
|
|
254
262
|
})
|
|
255
263
|
.filter(Boolean);
|
|
@@ -258,8 +266,8 @@ export const ReactSlate = forwardRef((props, ref) => {
|
|
|
258
266
|
const splitOptionsByDividers = (options) => {
|
|
259
267
|
const subGroups = [];
|
|
260
268
|
let currentGroup = [];
|
|
261
|
-
options.forEach(option => {
|
|
262
|
-
if (option.type ===
|
|
269
|
+
options.forEach((option) => {
|
|
270
|
+
if (option.type === "divider") {
|
|
263
271
|
if (currentGroup.length > 0) {
|
|
264
272
|
subGroups.push(currentGroup);
|
|
265
273
|
currentGroup = [];
|
|
@@ -276,66 +284,72 @@ export const ReactSlate = forwardRef((props, ref) => {
|
|
|
276
284
|
return subGroups;
|
|
277
285
|
};
|
|
278
286
|
const renderToolbarGroup = (group, index) => {
|
|
279
|
-
const validOptions = group.options.filter(option => getOption(option.type, option.id) || option.type ===
|
|
287
|
+
const validOptions = group.options.filter((option) => getOption(option.type, option.id) || option.type === "divider");
|
|
280
288
|
if (validOptions.length === 0)
|
|
281
289
|
return null;
|
|
282
290
|
const groupStyle = {
|
|
283
|
-
display:
|
|
284
|
-
alignItems:
|
|
285
|
-
gap:
|
|
286
|
-
flexWrap:
|
|
291
|
+
display: "flex",
|
|
292
|
+
alignItems: "center",
|
|
293
|
+
gap: "8px",
|
|
294
|
+
flexWrap: "wrap",
|
|
287
295
|
};
|
|
288
|
-
return (_jsx("div", { style: groupStyle, children: group.display ===
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
296
|
+
return (_jsx("div", { style: groupStyle, children: group.display === "buttons"
|
|
297
|
+
? (() => {
|
|
298
|
+
const subGroups = splitOptionsByDividers(validOptions);
|
|
299
|
+
return subGroups.map((subGroup, subGroupIndex) => (_jsx("div", { className: "toolbar-button-group", children: subGroup.map((option, optionIndex) => {
|
|
300
|
+
const optionObj = getOption(option.type, option.id);
|
|
301
|
+
if (!optionObj)
|
|
302
|
+
return null;
|
|
303
|
+
return (_jsx(ToolbarButton, { icon: optionObj.icon, active: isOptionActive(option.type, option.id), onMouseDown: handleOptionSelect(option.type, option.id) }, `${option.type}-${option.id}`));
|
|
304
|
+
}) }, `subgroup-${subGroupIndex}`)));
|
|
305
|
+
})()
|
|
306
|
+
: (() => {
|
|
307
|
+
const dropdownOptions = createDropdownOptions(validOptions);
|
|
308
|
+
const blockOptions = validOptions.filter((option) => option.type === "block");
|
|
309
|
+
// If there's only one block option, render it as a disabled-style button
|
|
310
|
+
if (blockOptions.length === 1) {
|
|
311
|
+
const singleOption = dropdownOptions.find((opt) => blockOptions.some((blockOpt) => blockOpt.type === "block" &&
|
|
312
|
+
getOption(blockOpt.type, blockOpt.id) === opt.value));
|
|
313
|
+
return (_jsx("div", { className: "toolbar-dropdown-container", children: _jsx("button", { className: "toolbar-dropdown-button", disabled: true, children: group.label ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "toolbar-dropdown-content", children: [group.label, ": ", singleOption?.label] }), _jsx("span", { className: "toolbar-dropdown-arrow", children: "\u25BC" })] })) : group.showIconsOnly ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "toolbar-dropdown-icon", children: singleOption?.icon }), _jsx("span", { className: "toolbar-dropdown-arrow", children: "\u25BC" })] })) : (_jsxs(_Fragment, { children: [_jsxs("span", { className: "toolbar-dropdown-icon", children: [singleOption?.icon && (_jsx("span", { className: "toolbar-dropdown-icon", children: singleOption.icon })), _jsx("span", { className: "toolbar-dropdown-content", children: singleOption?.label })] }), _jsx("span", { className: "toolbar-dropdown-arrow", children: "\u25BC" })] })) }) }));
|
|
314
|
+
}
|
|
315
|
+
// Multiple options - render normally wrapped in grey container
|
|
316
|
+
const isActive = dropdownOptions.some((option) => option.isActive(editor));
|
|
317
|
+
return (_jsx("div", { className: "toolbar-dropdown-container", children: _jsx(EditorDropdown, { options: dropdownOptions, editor: editor, label: group.label, buttonStyle: {
|
|
318
|
+
padding: "5px 10px",
|
|
319
|
+
margin: "0",
|
|
320
|
+
background: isActive ? "#ffffff" : "transparent",
|
|
321
|
+
border: "none",
|
|
322
|
+
borderRadius: "3px",
|
|
323
|
+
cursor: "pointer",
|
|
324
|
+
boxShadow: isActive
|
|
325
|
+
? "0 1px 2px rgba(0,0,0,0.1)"
|
|
326
|
+
: "none",
|
|
327
|
+
} }) }));
|
|
328
|
+
})() }, `group-${group.id || index}`));
|
|
317
329
|
};
|
|
318
330
|
const [showLinkDialog, setShowLinkDialog] = useState(false);
|
|
319
331
|
const [selectedLink, setSelectedLink] = useState(null);
|
|
320
332
|
const [linkDialogCallback, setLinkDialogCallback] = useState(null);
|
|
321
333
|
const editLink = useCallback((element) => {
|
|
322
|
-
const linkType = element.link?.type ||
|
|
334
|
+
const linkType = element.link?.type || "external";
|
|
323
335
|
let linkData;
|
|
324
|
-
if (linkType ===
|
|
336
|
+
if (linkType === "internal") {
|
|
325
337
|
linkData = {
|
|
326
|
-
type:
|
|
327
|
-
itemId: element.link?.itemId ||
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
338
|
+
type: "internal",
|
|
339
|
+
itemId: element.link?.itemId ||
|
|
340
|
+
element.link?.targetItemLongId?.split("/").pop() ||
|
|
341
|
+
"",
|
|
342
|
+
targetItemLongId: element.link?.targetItemLongId || "",
|
|
343
|
+
target: element.link?.target || "",
|
|
344
|
+
queryString: element.link?.queryString || "",
|
|
331
345
|
};
|
|
332
346
|
}
|
|
333
347
|
else {
|
|
334
348
|
linkData = {
|
|
335
|
-
type:
|
|
336
|
-
url: element.url || element.link?.url ||
|
|
337
|
-
target: element.link?.target ||
|
|
338
|
-
queryString: element.link?.queryString ||
|
|
349
|
+
type: "external",
|
|
350
|
+
url: element.url || element.link?.url || "",
|
|
351
|
+
target: element.link?.target || "_blank",
|
|
352
|
+
queryString: element.link?.queryString || "",
|
|
339
353
|
};
|
|
340
354
|
}
|
|
341
355
|
setSelectedLink(linkData);
|
|
@@ -348,32 +362,32 @@ export const ReactSlate = forwardRef((props, ref) => {
|
|
|
348
362
|
}
|
|
349
363
|
else {
|
|
350
364
|
const [linkNode] = Editor.nodes(editor, {
|
|
351
|
-
match: n => !Editor.isEditor(n) && Element.isElement(n) && n.type ===
|
|
365
|
+
match: (n) => !Editor.isEditor(n) && Element.isElement(n) && n.type === "link",
|
|
352
366
|
});
|
|
353
367
|
if (linkNode) {
|
|
354
368
|
const [node, path] = linkNode;
|
|
355
369
|
let newProperties;
|
|
356
|
-
if (link.type ===
|
|
370
|
+
if (link.type === "internal") {
|
|
357
371
|
newProperties = {
|
|
358
|
-
url:
|
|
372
|
+
url: "",
|
|
359
373
|
link: {
|
|
360
|
-
type:
|
|
374
|
+
type: "internal",
|
|
361
375
|
targetItemLongId: link.targetItemLongId,
|
|
362
376
|
itemId: link.itemId,
|
|
363
377
|
target: link.target,
|
|
364
|
-
queryString: link.queryString
|
|
365
|
-
}
|
|
378
|
+
queryString: link.queryString,
|
|
379
|
+
},
|
|
366
380
|
};
|
|
367
381
|
}
|
|
368
382
|
else {
|
|
369
383
|
newProperties = {
|
|
370
384
|
url: link.url,
|
|
371
385
|
link: {
|
|
372
|
-
type:
|
|
386
|
+
type: "external",
|
|
373
387
|
url: link.url,
|
|
374
388
|
target: link.target,
|
|
375
|
-
queryString: link.queryString
|
|
376
|
-
}
|
|
389
|
+
queryString: link.queryString,
|
|
390
|
+
},
|
|
377
391
|
};
|
|
378
392
|
}
|
|
379
393
|
Transforms.setNodes(editor, newProperties, { at: path });
|
|
@@ -392,32 +406,34 @@ export const ReactSlate = forwardRef((props, ref) => {
|
|
|
392
406
|
editor.insertLink({
|
|
393
407
|
onOpenLinkDialog: (callback) => {
|
|
394
408
|
setSelectedLink({
|
|
395
|
-
type:
|
|
396
|
-
url:
|
|
397
|
-
target:
|
|
409
|
+
type: "external",
|
|
410
|
+
url: "",
|
|
411
|
+
target: "_blank",
|
|
398
412
|
});
|
|
399
413
|
setShowLinkDialog(true);
|
|
400
414
|
setLinkDialogCallback(() => callback);
|
|
401
|
-
}
|
|
415
|
+
},
|
|
402
416
|
});
|
|
403
417
|
}, [editor]);
|
|
404
418
|
const handleKeyDown = useCallback((event) => {
|
|
405
|
-
if (event.key ===
|
|
419
|
+
if (event.key === "Enter" && event.shiftKey) {
|
|
406
420
|
// Handle Shift+Enter for line breaks in all block types
|
|
407
421
|
event.preventDefault();
|
|
408
422
|
if (editor.selection) {
|
|
409
423
|
// Insert literal <br> text
|
|
410
|
-
editor.insertText(
|
|
424
|
+
editor.insertText("<br>");
|
|
411
425
|
}
|
|
412
426
|
}
|
|
413
|
-
else if (event.key ===
|
|
427
|
+
else if (event.key === "Tab") {
|
|
414
428
|
event.preventDefault();
|
|
415
429
|
// Check if we're in a list item more explicitly
|
|
416
430
|
if (editor.selection) {
|
|
417
431
|
// Try to find the closest list item ancestor using Editor.above
|
|
418
432
|
const listItem = Editor.above(editor, {
|
|
419
433
|
at: editor.selection,
|
|
420
|
-
match: n => !Editor.isEditor(n) &&
|
|
434
|
+
match: (n) => !Editor.isEditor(n) &&
|
|
435
|
+
Element.isElement(n) &&
|
|
436
|
+
n.type === "list-item",
|
|
421
437
|
});
|
|
422
438
|
if (listItem) {
|
|
423
439
|
if (event.shiftKey) {
|
|
@@ -431,23 +447,28 @@ export const ReactSlate = forwardRef((props, ref) => {
|
|
|
431
447
|
}
|
|
432
448
|
}
|
|
433
449
|
}
|
|
434
|
-
else if (event.key ===
|
|
450
|
+
else if (event.key === "Backspace" || event.key === "Delete") {
|
|
435
451
|
// Handle empty list items
|
|
436
452
|
if (editor.selection) {
|
|
437
453
|
const listItem = Editor.above(editor, {
|
|
438
454
|
at: editor.selection,
|
|
439
|
-
match: n => !Editor.isEditor(n) &&
|
|
455
|
+
match: (n) => !Editor.isEditor(n) &&
|
|
456
|
+
Element.isElement(n) &&
|
|
457
|
+
n.type === "list-item",
|
|
440
458
|
});
|
|
441
459
|
if (listItem) {
|
|
442
460
|
const selectedText = Editor.string(editor, editor.selection);
|
|
443
461
|
const [node, path] = listItem;
|
|
444
462
|
const nodeText = Editor.string(editor, path);
|
|
445
463
|
// If the list item is empty or only contains whitespace, convert to paragraph
|
|
446
|
-
if (!nodeText.trim() ||
|
|
464
|
+
if (!nodeText.trim() ||
|
|
465
|
+
(selectedText === nodeText && nodeText.trim())) {
|
|
447
466
|
event.preventDefault();
|
|
448
|
-
Transforms.setNodes(editor, { type:
|
|
449
|
-
match: n => !Editor.isEditor(n) &&
|
|
450
|
-
|
|
467
|
+
Transforms.setNodes(editor, { type: "paragraph", listType: undefined, indent: undefined }, {
|
|
468
|
+
match: (n) => !Editor.isEditor(n) &&
|
|
469
|
+
Element.isElement(n) &&
|
|
470
|
+
n.type === "list-item",
|
|
471
|
+
split: true,
|
|
451
472
|
});
|
|
452
473
|
}
|
|
453
474
|
}
|
|
@@ -466,43 +487,45 @@ export const ReactSlate = forwardRef((props, ref) => {
|
|
|
466
487
|
// Render each row
|
|
467
488
|
return Object.entries(groupsByRow)
|
|
468
489
|
.sort(([a], [b]) => parseInt(a) - parseInt(b))
|
|
469
|
-
.map(([rowIndex, rowGroups]) => (_jsx("div", { className: "toolbar-row", children: rowGroups.map(group => renderToolbarGroup(group, parseInt(rowIndex))) }, `row-${rowIndex}`)));
|
|
470
|
-
})() })), _jsx(Editable, { className: classNames(readOnly ? "bg-gray-4" : "bg-gray-5", "focus-shadow"), readOnly: readOnly, placeholder: placeholder, onFocus: onFocus, onBlur: onBlur, onKeyDown: handleKeyDown, renderElement: ({ attributes, children, element }) => {
|
|
490
|
+
.map(([rowIndex, rowGroups]) => (_jsx("div", { className: "toolbar-row", children: rowGroups.map((group) => renderToolbarGroup(group, parseInt(rowIndex))) }, `row-${rowIndex}`)));
|
|
491
|
+
})() })), _jsx(Editable, { className: classNames(readOnly ? "bg-gray-4" : "bg-gray-5", "focus-shadow p-2"), readOnly: readOnly, placeholder: placeholder, onFocus: onFocus, onBlur: onBlur, onKeyDown: handleKeyDown, renderElement: ({ attributes, children, element }) => {
|
|
471
492
|
const style = {
|
|
472
|
-
textAlign: element.align ||
|
|
493
|
+
textAlign: element.align || "left",
|
|
473
494
|
};
|
|
474
|
-
if (element.type ===
|
|
475
|
-
const isInternal = element.link?.type ===
|
|
476
|
-
const url = isInternal
|
|
477
|
-
|
|
495
|
+
if (element.type === "link") {
|
|
496
|
+
const isInternal = element.link?.type === "internal";
|
|
497
|
+
const url = isInternal
|
|
498
|
+
? "#"
|
|
499
|
+
: element.url || element.link?.url || "#";
|
|
500
|
+
return (_jsx("a", { ...attributes, href: url, style: style, className: `slate-link ${isInternal ? "internal-link" : "external-link"}`, onClick: (e) => {
|
|
478
501
|
if (!readOnly) {
|
|
479
502
|
e.preventDefault();
|
|
480
503
|
editLink(element);
|
|
481
504
|
}
|
|
482
505
|
}, children: children }));
|
|
483
506
|
}
|
|
484
|
-
if (element.type ===
|
|
507
|
+
if (element.type === "list-item") {
|
|
485
508
|
const indent = element.indent || 0;
|
|
486
|
-
const listType = element.listType ||
|
|
487
|
-
const isOrdered = listType ===
|
|
509
|
+
const listType = element.listType || "unordered";
|
|
510
|
+
const isOrdered = listType === "ordered";
|
|
488
511
|
// Calculate proper numbering for ordered lists
|
|
489
512
|
let listNumber = 1;
|
|
490
513
|
if (isOrdered) {
|
|
491
514
|
// Find the position of this item within its level
|
|
492
515
|
const allElements = editor.children;
|
|
493
|
-
const currentIndex = allElements.findIndex(el => el === element);
|
|
516
|
+
const currentIndex = allElements.findIndex((el) => el === element);
|
|
494
517
|
// Count preceding list items at the same indent level and list type
|
|
495
518
|
let count = 0;
|
|
496
519
|
for (let i = 0; i < currentIndex; i++) {
|
|
497
520
|
const prevElement = allElements[i];
|
|
498
521
|
if (prevElement &&
|
|
499
|
-
prevElement.type ===
|
|
500
|
-
prevElement.listType ===
|
|
522
|
+
prevElement.type === "list-item" &&
|
|
523
|
+
prevElement.listType === "ordered" &&
|
|
501
524
|
(prevElement.indent || 0) === indent) {
|
|
502
525
|
count++;
|
|
503
526
|
}
|
|
504
527
|
else if (prevElement &&
|
|
505
|
-
prevElement.type ===
|
|
528
|
+
prevElement.type === "list-item" &&
|
|
506
529
|
(prevElement.indent || 0) < indent) {
|
|
507
530
|
// Reset count when we encounter a parent-level item
|
|
508
531
|
count = 0;
|
|
@@ -512,17 +535,17 @@ export const ReactSlate = forwardRef((props, ref) => {
|
|
|
512
535
|
}
|
|
513
536
|
const listStyle = {
|
|
514
537
|
...style,
|
|
515
|
-
position:
|
|
516
|
-
listStyleType:
|
|
538
|
+
position: "relative",
|
|
539
|
+
listStyleType: "none",
|
|
517
540
|
};
|
|
518
|
-
const bulletContent = isOrdered ? `${listNumber}.` :
|
|
541
|
+
const bulletContent = isOrdered ? `${listNumber}.` : "";
|
|
519
542
|
return (_jsxs("div", { ...attributes, style: listStyle, className: `slate-list-item slate-list-${listType}`, "data-indent": indent, children: [_jsx("span", { className: "slate-list-bullet", children: bulletContent }), _jsx("div", { className: "slate-list-content", children: children })] }));
|
|
520
543
|
}
|
|
521
544
|
// Handle different block types using built-in SLATE_BLOCKS configuration
|
|
522
545
|
const blockConfig = SLATE_BLOCKS[element.type];
|
|
523
|
-
if (blockConfig && element.type ===
|
|
546
|
+
if (blockConfig && element.type === "no-tag") {
|
|
524
547
|
// Special handling for no-tag blocks (plain text without wrapper)
|
|
525
|
-
return _jsx("span", { ...attributes, style: style, children: children });
|
|
548
|
+
return (_jsx("span", { ...attributes, style: style, children: children }));
|
|
526
549
|
}
|
|
527
550
|
// For standard blocks, use the appropriate HTML tag
|
|
528
551
|
if (blockConfig) {
|
|
@@ -530,17 +553,17 @@ export const ReactSlate = forwardRef((props, ref) => {
|
|
|
530
553
|
return React.createElement(tagName, { ...attributes, style }, children);
|
|
531
554
|
}
|
|
532
555
|
// Default fallback to paragraph
|
|
533
|
-
return _jsx("p", { ...attributes, style: style, children: children });
|
|
556
|
+
return (_jsx("p", { ...attributes, style: style, children: children }));
|
|
534
557
|
}, renderLeaf: ({ attributes, children, leaf }) => {
|
|
535
558
|
let el = _jsx("span", { ...attributes, children: children });
|
|
536
559
|
// Apply marks using the built-in SLATE_MARKS configuration
|
|
537
|
-
simplifiedProfile.marks.forEach(markId => {
|
|
560
|
+
simplifiedProfile.marks.forEach((markId) => {
|
|
538
561
|
if (leaf[markId]) {
|
|
539
562
|
const markConfig = SLATE_MARKS[markId];
|
|
540
563
|
if (markConfig) {
|
|
541
|
-
if (markId ===
|
|
564
|
+
if (markId === "extrabold") {
|
|
542
565
|
// Special handling for extrabold with CSS class
|
|
543
|
-
el =
|
|
566
|
+
el = _jsx("span", { className: "extrabold", children: el });
|
|
544
567
|
}
|
|
545
568
|
else {
|
|
546
569
|
// Standard HTML tag rendering
|
|
@@ -557,6 +580,6 @@ export const ReactSlate = forwardRef((props, ref) => {
|
|
|
557
580
|
setLinkDialogCallback(null);
|
|
558
581
|
} }))] }));
|
|
559
582
|
});
|
|
560
|
-
ReactSlate.displayName =
|
|
583
|
+
ReactSlate.displayName = "ReactSlate";
|
|
561
584
|
export default ReactSlate;
|
|
562
585
|
//# sourceMappingURL=ReactSlate.js.map
|