@alpaca-editor/core 1.0.3969 → 1.0.3974
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/components/ui/command.js +1 -1
- package/dist/components/ui/command.js.map +1 -1
- package/dist/config/config.js +5 -1
- package/dist/config/config.js.map +1 -1
- package/dist/editor/ContentTree.js +1 -1
- package/dist/editor/ContentTree.js.map +1 -1
- package/dist/editor/FieldList.d.ts +3 -0
- package/dist/editor/FieldList.js +3 -1
- package/dist/editor/FieldList.js.map +1 -1
- package/dist/editor/ItemInfo.js +4 -2
- package/dist/editor/ItemInfo.js.map +1 -1
- package/dist/editor/client/EditorClient.js +28 -2
- package/dist/editor/client/EditorClient.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +2 -0
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/operations.js +36 -1
- package/dist/editor/client/operations.js.map +1 -1
- package/dist/editor/client/pageModelBuilder.js +2 -1
- package/dist/editor/client/pageModelBuilder.js.map +1 -1
- package/dist/editor/field-types/ImageFieldEditor.js +3 -3
- package/dist/editor/field-types/ImageFieldEditor.js.map +1 -1
- package/dist/editor/field-types/PictureFieldEditor.js +2 -2
- package/dist/editor/field-types/PictureFieldEditor.js.map +1 -1
- package/dist/editor/menubar/ActiveUsers.js +18 -5
- package/dist/editor/menubar/ActiveUsers.js.map +1 -1
- package/dist/editor/menubar/LanguageSelector.js +3 -10
- package/dist/editor/menubar/LanguageSelector.js.map +1 -1
- package/dist/editor/menubar/WorkflowButton.js +63 -14
- package/dist/editor/menubar/WorkflowButton.js.map +1 -1
- package/dist/editor/page-editor-chrome/CommentHighlighting.js +68 -48
- package/dist/editor/page-editor-chrome/CommentHighlighting.js.map +1 -1
- package/dist/editor/page-editor-chrome/FrameMenu.js +1 -1
- package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
- package/dist/editor/page-viewer/EditorForm.js +77 -12
- package/dist/editor/page-viewer/EditorForm.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +21 -48
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/page-viewer/pageModelSkeletonBuilder.js +7 -1
- package/dist/editor/page-viewer/pageModelSkeletonBuilder.js.map +1 -1
- package/dist/editor/page-viewer/pageViewContext.d.ts +2 -0
- package/dist/editor/page-viewer/pageViewContext.js +10 -0
- package/dist/editor/page-viewer/pageViewContext.js.map +1 -1
- package/dist/editor/pageModel.d.ts +5 -0
- package/dist/editor/services/contentService.d.ts +3 -0
- package/dist/editor/services/contentService.js +0 -1
- package/dist/editor/services/contentService.js.map +1 -1
- package/dist/editor/sidebar/ComponentPalette.js +2 -2
- package/dist/editor/sidebar/ComponentPalette.js.map +1 -1
- package/dist/editor/sidebar/ComponentTree.js +193 -78
- package/dist/editor/sidebar/ComponentTree.js.map +1 -1
- package/dist/editor/sidebar/Debug.js +1 -1
- package/dist/editor/sidebar/Debug.js.map +1 -1
- package/dist/editor/utils.d.ts +1 -2
- package/dist/editor/utils.js +36 -30
- package/dist/editor/utils.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/styles.css +37 -10
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
- package/src/components/ui/command.tsx +1 -1
- package/src/config/config.tsx +5 -1
- package/src/editor/ContentTree.tsx +1 -1
- package/src/editor/FieldList.tsx +35 -2
- package/src/editor/ItemInfo.tsx +7 -6
- package/src/editor/client/EditorClient.tsx +46 -2
- package/src/editor/client/editContext.ts +3 -0
- package/src/editor/client/operations.ts +43 -1
- package/src/editor/client/pageModelBuilder.ts +2 -1
- package/src/editor/field-types/ImageFieldEditor.tsx +7 -7
- package/src/editor/field-types/PictureFieldEditor.tsx +4 -4
- package/src/editor/menubar/ActiveUsers.tsx +26 -11
- package/src/editor/menubar/LanguageSelector.tsx +11 -25
- package/src/editor/menubar/WorkflowButton.tsx +125 -38
- package/src/editor/page-editor-chrome/CommentHighlighting.tsx +82 -54
- package/src/editor/page-editor-chrome/FrameMenu.tsx +1 -1
- package/src/editor/page-viewer/EditorForm.tsx +96 -12
- package/src/editor/page-viewer/PageViewerFrame.tsx +27 -62
- package/src/editor/page-viewer/pageModelSkeletonBuilder.ts +8 -1
- package/src/editor/page-viewer/pageViewContext.ts +15 -3
- package/src/editor/pageModel.ts +5 -0
- package/src/editor/services/contentService.ts +10 -2
- package/src/editor/sidebar/ComponentPalette.tsx +4 -4
- package/src/editor/sidebar/ComponentTree.tsx +273 -114
- package/src/editor/sidebar/Debug.tsx +1 -1
- package/src/editor/utils.ts +40 -32
- package/src/revision.ts +2 -2
- package/src/types.ts +2 -0
|
@@ -13,7 +13,8 @@ import { PerfectTree, TreeNode } from "../ui/PerfectTree";
|
|
|
13
13
|
|
|
14
14
|
import { isValidPlaceholder } from "../componentTreeHelper";
|
|
15
15
|
import { getAbsoluteIconUrl } from "../utils";
|
|
16
|
-
import { Plus } from "lucide-react";
|
|
16
|
+
import { Plus, EyeIcon, EyeOff, Pentagon } from "lucide-react";
|
|
17
|
+
import { SimpleIconButton } from "../ui/SimpleIconButton";
|
|
17
18
|
|
|
18
19
|
type CustomTreeNode = TreeNode<Component | Placeholder> & {
|
|
19
20
|
parent?: CustomTreeNode;
|
|
@@ -45,6 +46,59 @@ export function ComponentTree({}) {
|
|
|
45
46
|
|
|
46
47
|
const treeRef = useRef<HTMLDivElement>(null);
|
|
47
48
|
|
|
49
|
+
// Helper function to check if a component has editable descendants
|
|
50
|
+
// function hasEditableDescendants(component: Component): boolean {
|
|
51
|
+
// if (!component.placeholders) return false;
|
|
52
|
+
|
|
53
|
+
// for (const placeholder of component.placeholders) {
|
|
54
|
+
// // If placeholder itself is editable, we have editable descendants
|
|
55
|
+
// if (placeholder.editable) return true;
|
|
56
|
+
|
|
57
|
+
// // Check if any component in this placeholder is editable or has editable descendants
|
|
58
|
+
// for (const comp of placeholder.components) {
|
|
59
|
+
// if (comp.editable || hasEditableDescendants(comp)) {
|
|
60
|
+
// return true;
|
|
61
|
+
// }
|
|
62
|
+
// }
|
|
63
|
+
// }
|
|
64
|
+
|
|
65
|
+
// return false;
|
|
66
|
+
// }
|
|
67
|
+
|
|
68
|
+
// Helper function to get all editable descendants, flattening the tree
|
|
69
|
+
function getEditableDescendants(
|
|
70
|
+
component: Component,
|
|
71
|
+
parent: CustomTreeNode,
|
|
72
|
+
): CustomTreeNode[] {
|
|
73
|
+
const editableNodes: CustomTreeNode[] = [];
|
|
74
|
+
|
|
75
|
+
if (component.editable) {
|
|
76
|
+
// If this component is editable, include it and map its children normally
|
|
77
|
+
const node = mapComponentNode(component, parent);
|
|
78
|
+
editableNodes.push(node);
|
|
79
|
+
} else {
|
|
80
|
+
// If this component is not editable, skip it and collect its editable descendants
|
|
81
|
+
if (component.placeholders) {
|
|
82
|
+
for (const placeholder of component.placeholders) {
|
|
83
|
+
// if (placeholder.editable) {
|
|
84
|
+
// const placeholderNode = mapPlaceholderNode(placeholder, parent);
|
|
85
|
+
// editableNodes.push(placeholderNode);
|
|
86
|
+
// } else {
|
|
87
|
+
for (const childComponent of placeholder.components) {
|
|
88
|
+
const childEditableNodes = getEditableDescendants(
|
|
89
|
+
childComponent,
|
|
90
|
+
parent,
|
|
91
|
+
);
|
|
92
|
+
editableNodes.push(...childEditableNodes);
|
|
93
|
+
}
|
|
94
|
+
// }
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return editableNodes;
|
|
100
|
+
}
|
|
101
|
+
|
|
48
102
|
useEffect(() => {
|
|
49
103
|
if (treeRef.current) {
|
|
50
104
|
const selectedNodeKey = Object.keys(selectedKeys || {})[0];
|
|
@@ -106,7 +160,24 @@ export function ComponentTree({}) {
|
|
|
106
160
|
tags: [],
|
|
107
161
|
};
|
|
108
162
|
|
|
109
|
-
|
|
163
|
+
if (editContext?.hideNonEditableComponents) {
|
|
164
|
+
// Flatten the tree: collect all editable descendants directly
|
|
165
|
+
const flattenedComponents: CustomTreeNode[] = [];
|
|
166
|
+
for (const component of p.components) {
|
|
167
|
+
const editableNodes = getEditableDescendants(component, node);
|
|
168
|
+
flattenedComponents.push(...editableNodes);
|
|
169
|
+
}
|
|
170
|
+
node.children = flattenedComponents;
|
|
171
|
+
} else {
|
|
172
|
+
// Always map components, but filter based on editability and descendants
|
|
173
|
+
const mappedComponents = p.components.map((c) =>
|
|
174
|
+
mapComponentNode(c, node),
|
|
175
|
+
);
|
|
176
|
+
node.children = mappedComponents.filter((componentNode) => {
|
|
177
|
+
const component = componentNode.data as Component;
|
|
178
|
+
return component.editable || true; //hasEditableDescendants(component);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
110
181
|
|
|
111
182
|
return node;
|
|
112
183
|
}
|
|
@@ -119,23 +190,66 @@ export function ComponentTree({}) {
|
|
|
119
190
|
return [];
|
|
120
191
|
}
|
|
121
192
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
(
|
|
193
|
+
if (editContext?.hideNonEditableComponents) {
|
|
194
|
+
// Flatten the tree: collect all editable descendants from all placeholders
|
|
195
|
+
const flattenedNodes: CustomTreeNode[] = [];
|
|
196
|
+
|
|
197
|
+
for (const placeholder of c.placeholders) {
|
|
198
|
+
if (placeholder.editable) {
|
|
199
|
+
//If placeholder is editable, include it normally
|
|
200
|
+
if (c.placeholders.length > 1 || !c.editable) {
|
|
201
|
+
// Multiple placeholders - show placeholder node
|
|
202
|
+
const placeholderNode = mapPlaceholderNode(placeholder, parent);
|
|
203
|
+
flattenedNodes.push(placeholderNode);
|
|
204
|
+
} else {
|
|
205
|
+
// Single placeholder - map components directly
|
|
206
|
+
for (const component of placeholder.components) {
|
|
207
|
+
const editableNodes = getEditableDescendants(component, parent);
|
|
208
|
+
flattenedNodes.push(...editableNodes);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
// Placeholder is not editable - collect editable descendants from its components
|
|
213
|
+
for (const component of placeholder.components) {
|
|
214
|
+
const editableNodes = getEditableDescendants(component, parent);
|
|
215
|
+
flattenedNodes.push(...editableNodes);
|
|
216
|
+
}
|
|
136
217
|
}
|
|
137
|
-
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return flattenedNodes;
|
|
221
|
+
} else {
|
|
222
|
+
// Original logic for when hideNonEditableComponents is false
|
|
223
|
+
// Filter placeholders based on editable descendants
|
|
224
|
+
let placeholdersToShow = c.placeholders.filter((p) => {
|
|
225
|
+
// Show placeholder if it's editable or has editable descendants
|
|
226
|
+
if (p.editable) return true;
|
|
227
|
+
return p.components.some(
|
|
228
|
+
(comp) => comp.editable || true, // || hasEditableDescendants(comp),
|
|
229
|
+
);
|
|
138
230
|
});
|
|
231
|
+
|
|
232
|
+
if (placeholdersToShow.length > 1) {
|
|
233
|
+
return placeholdersToShow.map((x) => mapPlaceholderNode(x, parent));
|
|
234
|
+
} else if (placeholdersToShow.length > 0) {
|
|
235
|
+
const placeholder = placeholdersToShow[0]!;
|
|
236
|
+
// For single placeholders, map the components directly (don't show placeholder node)
|
|
237
|
+
const mappedComponents = placeholder.components.map((c) => {
|
|
238
|
+
const componentNode = mapComponentNode(c, parent);
|
|
239
|
+
// Apply gray styling to components in non-editable placeholders (only when showing non-editable components)
|
|
240
|
+
if (!placeholder.editable) {
|
|
241
|
+
componentNode.className =
|
|
242
|
+
(componentNode.className || "") + " text-gray-400";
|
|
243
|
+
}
|
|
244
|
+
return componentNode;
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// Filter components to only show editable ones or those with editable descendants
|
|
248
|
+
return mappedComponents.filter((componentNode) => {
|
|
249
|
+
const component = componentNode.data as Component;
|
|
250
|
+
return component.editable || true; // || hasEditableDescendants(component);
|
|
251
|
+
});
|
|
252
|
+
}
|
|
139
253
|
}
|
|
140
254
|
return [];
|
|
141
255
|
}
|
|
@@ -158,7 +272,8 @@ export function ComponentTree({}) {
|
|
|
158
272
|
data: c,
|
|
159
273
|
parent: parent,
|
|
160
274
|
tags: [],
|
|
161
|
-
className:
|
|
275
|
+
className:
|
|
276
|
+
c.isRemovedFromMasterLanguage || !c.editable ? "text-gray-400" : "",
|
|
162
277
|
type: "component",
|
|
163
278
|
};
|
|
164
279
|
|
|
@@ -205,6 +320,16 @@ export function ComponentTree({}) {
|
|
|
205
320
|
});
|
|
206
321
|
}
|
|
207
322
|
|
|
323
|
+
if (c.isSharedLayout) {
|
|
324
|
+
node.tags!.push({
|
|
325
|
+
id: "shared-layout",
|
|
326
|
+
severity: "warning",
|
|
327
|
+
value: "",
|
|
328
|
+
icon: <Pentagon className="h-3 w-3 text-gray-400" strokeWidth={1} />,
|
|
329
|
+
tooltip: "Component is shared across all languages",
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
208
333
|
if (c.isShared) {
|
|
209
334
|
node.tags!.push({
|
|
210
335
|
id: "linked",
|
|
@@ -218,7 +343,11 @@ export function ComponentTree({}) {
|
|
|
218
343
|
|
|
219
344
|
node.children = mapPlaceholders(c, node);
|
|
220
345
|
|
|
221
|
-
if (
|
|
346
|
+
if (
|
|
347
|
+
c.items.length > 0 &&
|
|
348
|
+
c.items[0]!.id !== c.datasourceItem?.id &&
|
|
349
|
+
c.items[0]!.id !== page?.item.id
|
|
350
|
+
) {
|
|
222
351
|
const itemsNode: CustomTreeNode = {
|
|
223
352
|
key: "items" + c.id,
|
|
224
353
|
label: "items",
|
|
@@ -283,7 +412,7 @@ export function ComponentTree({}) {
|
|
|
283
412
|
|
|
284
413
|
setRootNodes(finalNodes);
|
|
285
414
|
setNodeDictionary(dict);
|
|
286
|
-
}, [page]);
|
|
415
|
+
}, [page, editContext?.hideNonEditableComponents]);
|
|
287
416
|
|
|
288
417
|
const handleTreeSelection = useCallback(
|
|
289
418
|
(key: string, event: React.MouseEvent) => {
|
|
@@ -360,45 +489,47 @@ export function ComponentTree({}) {
|
|
|
360
489
|
},
|
|
361
490
|
}));
|
|
362
491
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
menu.
|
|
492
|
+
if (editContext?.mode === "edit") {
|
|
493
|
+
// Check if we have a placeholder to add insert options
|
|
494
|
+
const placeholder = getPlaceholder(nodeDictionary[node.key] || null);
|
|
495
|
+
if (placeholder && placeholder.insertOptions) {
|
|
496
|
+
const insertOptions = placeholder.insertOptions
|
|
497
|
+
.filter((x) => !x.isHidden && !x.isInvalid)
|
|
498
|
+
.map((x) => ({
|
|
499
|
+
id: x.typeId,
|
|
500
|
+
icon: (
|
|
501
|
+
<img
|
|
502
|
+
src={getAbsoluteIconUrl(x.icon)}
|
|
503
|
+
width="16"
|
|
504
|
+
height="16"
|
|
505
|
+
className="m-1"
|
|
506
|
+
/>
|
|
507
|
+
),
|
|
508
|
+
label: x.name,
|
|
509
|
+
command: () => {
|
|
510
|
+
editContextRef.current?.operations.addComponent(
|
|
511
|
+
x.typeId,
|
|
512
|
+
placeholder.key,
|
|
513
|
+
0, // Insert at the beginning by default
|
|
514
|
+
editContextRef.current?.currentItemDescriptor!,
|
|
515
|
+
);
|
|
516
|
+
},
|
|
517
|
+
}));
|
|
518
|
+
|
|
519
|
+
if (insertOptions.length > 0) {
|
|
520
|
+
// Add separator if there are existing menu items
|
|
521
|
+
if (menu.length > 0) {
|
|
522
|
+
menu.push({ separator: true });
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Add insert submenu
|
|
526
|
+
menu.push({
|
|
527
|
+
id: "insert",
|
|
528
|
+
label: "Insert",
|
|
529
|
+
icon: <Plus size={16} />,
|
|
530
|
+
items: insertOptions,
|
|
531
|
+
});
|
|
393
532
|
}
|
|
394
|
-
|
|
395
|
-
// Add insert submenu
|
|
396
|
-
menu.push({
|
|
397
|
-
id: "insert",
|
|
398
|
-
label: "Insert",
|
|
399
|
-
icon: <Plus size={16} />,
|
|
400
|
-
items: insertOptions,
|
|
401
|
-
});
|
|
402
533
|
}
|
|
403
534
|
}
|
|
404
535
|
|
|
@@ -489,60 +620,88 @@ export function ComponentTree({}) {
|
|
|
489
620
|
|
|
490
621
|
// Use the PerfectTree component
|
|
491
622
|
return (
|
|
492
|
-
<div className="
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
editContext
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
623
|
+
<div className="flex h-full flex-col">
|
|
624
|
+
{/* Toolbar */}
|
|
625
|
+
<div className="flex items-center justify-between border-b border-gray-200 px-2 py-1">
|
|
626
|
+
<SimpleIconButton
|
|
627
|
+
icon={
|
|
628
|
+
editContext?.hideNonEditableComponents ? (
|
|
629
|
+
<EyeOff className="h-4 w-4" strokeWidth={1.5} />
|
|
630
|
+
) : (
|
|
631
|
+
<EyeIcon className="h-4 w-4" strokeWidth={1.5} />
|
|
632
|
+
)
|
|
633
|
+
}
|
|
634
|
+
label={
|
|
635
|
+
editContext?.hideNonEditableComponents
|
|
636
|
+
? "Show non-editable components"
|
|
637
|
+
: "Hide non-editable components"
|
|
638
|
+
}
|
|
639
|
+
size="small"
|
|
640
|
+
selected={editContext?.hideNonEditableComponents}
|
|
641
|
+
onClick={() =>
|
|
642
|
+
editContext?.setHideNonEditableComponents(
|
|
643
|
+
!editContext.hideNonEditableComponents,
|
|
644
|
+
)
|
|
645
|
+
}
|
|
646
|
+
/>
|
|
647
|
+
</div>
|
|
648
|
+
|
|
649
|
+
{/* Tree content */}
|
|
650
|
+
<div className="flex-1 p-2" ref={treeRef}>
|
|
651
|
+
<PerfectTree
|
|
652
|
+
nodes={rootNodes}
|
|
653
|
+
isDragging={!!editContext?.dragObject}
|
|
654
|
+
selectedKeys={selectedItems}
|
|
655
|
+
expandedKeys={expandedItems}
|
|
656
|
+
onToggleExpand={handleToggle}
|
|
657
|
+
onSelect={handleTreeSelection}
|
|
658
|
+
onContextMenu={handleTreeContextMenu}
|
|
659
|
+
enableDragAndDrop={true}
|
|
660
|
+
onDragOverZone={(parent, index, event) =>
|
|
661
|
+
handleDragOverZone(parent as CustomTreeNode | null, index, event)
|
|
662
|
+
}
|
|
663
|
+
isValidDropZone={(parent, index) => {
|
|
664
|
+
const placeholder = getPlaceholder(parent as CustomTreeNode | null);
|
|
665
|
+
if (!placeholder) return false;
|
|
666
|
+
if (!editContext?.dragObject) return false;
|
|
667
|
+
const result = isValidPlaceholder(
|
|
668
|
+
placeholder,
|
|
669
|
+
editContext.dragObject,
|
|
670
|
+
);
|
|
671
|
+
|
|
672
|
+
return result;
|
|
673
|
+
}}
|
|
674
|
+
onStartDrag={(data) => {
|
|
675
|
+
const component = data.node.data as Component;
|
|
676
|
+
|
|
677
|
+
// Initialize drag data to make sure dataTransfer is set
|
|
678
|
+
data.event.dataTransfer.setData("text/plain", data.node.key);
|
|
679
|
+
|
|
680
|
+
// Only create drag object for components with datasourceItem
|
|
681
|
+
if (!component?.datasourceItem) return;
|
|
682
|
+
setTimeout(() => {
|
|
683
|
+
editContext!.dragStart({
|
|
684
|
+
type: "component",
|
|
685
|
+
typeId: component.typeId,
|
|
686
|
+
templateId: component.datasourceItem?.templateId,
|
|
687
|
+
name: component.name,
|
|
688
|
+
component: {
|
|
689
|
+
id: component.id,
|
|
690
|
+
language: editContext!.page!.item.language,
|
|
691
|
+
version: editContext!.page!.item.version,
|
|
692
|
+
},
|
|
693
|
+
});
|
|
694
|
+
}, 1);
|
|
695
|
+
}}
|
|
696
|
+
onDragEnd={(event) => {
|
|
697
|
+
editContext!.dragEnd();
|
|
698
|
+
}}
|
|
699
|
+
onDrop={(parent, index, event) =>
|
|
700
|
+
handleDropZone(parent as CustomTreeNode | null, index, event)
|
|
701
|
+
}
|
|
702
|
+
renderNode={(node) => renderNode(node as CustomTreeNode)}
|
|
703
|
+
/>
|
|
704
|
+
</div>
|
|
546
705
|
</div>
|
|
547
706
|
);
|
|
548
707
|
}
|
|
@@ -561,7 +720,7 @@ function renderNode(node: CustomTreeNode) {
|
|
|
561
720
|
<div key={`tag-${node.key}-${x.id}`}>
|
|
562
721
|
<span
|
|
563
722
|
id={`id-${node.key}-${x.id}`}
|
|
564
|
-
className="ml-2 rounded p-0.5 px-1.5 text-xs text-white"
|
|
723
|
+
className="ml-2 flex rounded p-0.5 px-1.5 text-xs text-white"
|
|
565
724
|
style={{
|
|
566
725
|
backgroundColor: x.color,
|
|
567
726
|
marginLeft: "8px",
|
|
@@ -577,7 +736,7 @@ function renderNode(node: CustomTreeNode) {
|
|
|
577
736
|
: undefined
|
|
578
737
|
}
|
|
579
738
|
>
|
|
580
|
-
{x.icon
|
|
739
|
+
{x.icon}
|
|
581
740
|
{x.value}
|
|
582
741
|
</span>
|
|
583
742
|
</div>
|
|
@@ -98,7 +98,7 @@ export function Debug({}: {}) {
|
|
|
98
98
|
tabs={tabs}
|
|
99
99
|
activeTab={activeTab}
|
|
100
100
|
setActiveTab={setActiveTab}
|
|
101
|
-
className="alpaceditor-tabs border-gray-3 border-b px-2 pt-2 text-sm"
|
|
101
|
+
className="alpaceditor-tabs border-gray-3 flex border-b px-2 pt-2 text-sm"
|
|
102
102
|
/>
|
|
103
103
|
|
|
104
104
|
<div className="absolute top-2 right-1 h-4 w-4">
|
package/src/editor/utils.ts
CHANGED
|
@@ -254,10 +254,18 @@ export function getFieldDescriptorFromElement(
|
|
|
254
254
|
};
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
-
export function
|
|
257
|
+
export function findNearestEditableComponentId(startElement: Element) {
|
|
258
258
|
let element: Element | null = startElement;
|
|
259
259
|
while (element) {
|
|
260
|
-
if (element.
|
|
260
|
+
if (element.getAttribute("sc_item") && isEditableComponent(element)) {
|
|
261
|
+
return extractItemIdFromItemUri(element.getAttribute("sc_item")!);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (
|
|
265
|
+
element.hasAttribute("data-component-start") &&
|
|
266
|
+
!element.hasAttribute("data-skip-component") &&
|
|
267
|
+
isEditableComponent(element)
|
|
268
|
+
) {
|
|
261
269
|
return element.getAttribute("data-component-start") ?? undefined;
|
|
262
270
|
}
|
|
263
271
|
const prev: Element | null = element.previousElementSibling;
|
|
@@ -268,6 +276,10 @@ export function findNearestComponentId(startElement: Element) {
|
|
|
268
276
|
return;
|
|
269
277
|
}
|
|
270
278
|
|
|
279
|
+
function isEditableComponent(element: Element) {
|
|
280
|
+
return element.getAttribute("data-editable") !== "false";
|
|
281
|
+
}
|
|
282
|
+
|
|
271
283
|
export function findFieldElement(
|
|
272
284
|
iframe: HTMLIFrameElement,
|
|
273
285
|
fieldDescriptor: FieldDescriptor,
|
|
@@ -277,10 +289,6 @@ export function findFieldElement(
|
|
|
277
289
|
const fieldElement = iframe.contentWindow?.document.body.querySelector(
|
|
278
290
|
"[data-itemid='" +
|
|
279
291
|
fieldDescriptor.item.id +
|
|
280
|
-
"'][data-language='" +
|
|
281
|
-
fieldDescriptor.item.language +
|
|
282
|
-
"'][data-version='" +
|
|
283
|
-
fieldDescriptor.item.version +
|
|
284
292
|
"'][data-fieldid='" +
|
|
285
293
|
fieldDescriptor.fieldId +
|
|
286
294
|
"']",
|
|
@@ -427,35 +435,35 @@ export const getAbsolutePosition = (
|
|
|
427
435
|
};
|
|
428
436
|
};
|
|
429
437
|
|
|
430
|
-
export function findParentComponentId(element: HTMLElement) {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
438
|
+
// export function findParentComponentId(element: HTMLElement) {
|
|
439
|
+
// while (element && element !== document.documentElement) {
|
|
440
|
+
// if (element.getAttribute("sc_item")) {
|
|
441
|
+
// return extractItemIdFromItemUri(element.getAttribute("sc_item")!);
|
|
442
|
+
// }
|
|
435
443
|
|
|
436
|
-
|
|
444
|
+
// const startElement = findStartElement(element);
|
|
437
445
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
}
|
|
446
|
+
// if (startElement) {
|
|
447
|
+
// return startElement.getAttribute("data-component-start");
|
|
448
|
+
// }
|
|
449
|
+
// element = element.parentElement as HTMLElement;
|
|
450
|
+
// }
|
|
451
|
+
// return null;
|
|
452
|
+
// }
|
|
445
453
|
|
|
446
|
-
function findStartElement(element: HTMLElement) {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
}
|
|
454
|
+
// function findStartElement(element: HTMLElement) {
|
|
455
|
+
// let prev: Element | null = element;
|
|
456
|
+
// while (prev) {
|
|
457
|
+
// prev = prev.previousElementSibling;
|
|
458
|
+
// if (
|
|
459
|
+
// prev?.getAttribute("data-component-start") &&
|
|
460
|
+
// !prev.hasAttribute("data-skip-component")
|
|
461
|
+
// ) {
|
|
462
|
+
// return prev;
|
|
463
|
+
// }
|
|
464
|
+
// }
|
|
465
|
+
// return null;
|
|
466
|
+
// }
|
|
459
467
|
|
|
460
468
|
export function normalizeGuid(id: string) {
|
|
461
469
|
id = id.toUpperCase();
|
package/src/revision.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const version = "1.0.
|
|
2
|
-
export const buildDate = "2025-
|
|
1
|
+
export const version = "1.0.3974";
|
|
2
|
+
export const buildDate = "2025-07-02 12:45:37";
|
package/src/types.ts
CHANGED
|
@@ -168,6 +168,7 @@ export type UserPreferences = {
|
|
|
168
168
|
pinnedViews?: string[];
|
|
169
169
|
showViewNames?: boolean;
|
|
170
170
|
showRightSidebar?: boolean;
|
|
171
|
+
hideNonEditableComponents?: boolean;
|
|
171
172
|
};
|
|
172
173
|
|
|
173
174
|
export type HistoryEntry = {
|
|
@@ -238,6 +239,7 @@ export type InsertOption = {
|
|
|
238
239
|
typeId: string;
|
|
239
240
|
name: string;
|
|
240
241
|
icon: string;
|
|
242
|
+
thumbnail?: string;
|
|
241
243
|
group?: string;
|
|
242
244
|
svg?: string;
|
|
243
245
|
isInvalid: boolean;
|