@alpaca-editor/core 1.0.3969 → 1.0.3973
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/FieldList.d.ts +3 -0
- package/dist/editor/FieldList.js +3 -1
- package/dist/editor/FieldList.js.map +1 -1
- package/dist/editor/client/EditorClient.js +10 -0
- 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/pageModelBuilder.js +2 -1
- package/dist/editor/client/pageModelBuilder.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-viewer/EditorForm.js +77 -12
- package/dist/editor/page-viewer/EditorForm.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +13 -45
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/page-viewer/pageModelSkeletonBuilder.js +3 -0
- package/dist/editor/page-viewer/pageModelSkeletonBuilder.js.map +1 -1
- package/dist/editor/page-viewer/pageViewContext.d.ts +1 -0
- package/dist/editor/page-viewer/pageViewContext.js +5 -0
- package/dist/editor/page-viewer/pageViewContext.js.map +1 -1
- package/dist/editor/pageModel.d.ts +3 -0
- package/dist/editor/services/contentService.d.ts +1 -0
- 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 +96 -44
- 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 +37 -26
- 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 +6 -0
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
- package/src/editor/FieldList.tsx +35 -2
- package/src/editor/client/EditorClient.tsx +16 -0
- package/src/editor/client/editContext.ts +3 -0
- package/src/editor/client/pageModelBuilder.ts +2 -1
- package/src/editor/page-editor-chrome/CommentHighlighting.tsx +81 -54
- package/src/editor/page-viewer/EditorForm.tsx +96 -12
- package/src/editor/page-viewer/PageViewerFrame.tsx +17 -59
- package/src/editor/page-viewer/pageModelSkeletonBuilder.ts +3 -0
- package/src/editor/page-viewer/pageViewContext.ts +9 -3
- package/src/editor/pageModel.ts +3 -0
- package/src/editor/services/contentService.ts +7 -1
- package/src/editor/sidebar/ComponentPalette.tsx +4 -4
- package/src/editor/sidebar/ComponentTree.tsx +150 -67
- package/src/editor/sidebar/Debug.tsx +1 -1
- package/src/editor/utils.ts +41 -28
- 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 } 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,25 @@ 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
|
+
|
|
48
68
|
useEffect(() => {
|
|
49
69
|
if (treeRef.current) {
|
|
50
70
|
const selectedNodeKey = Object.keys(selectedKeys || {})[0];
|
|
@@ -106,7 +126,18 @@ export function ComponentTree({}) {
|
|
|
106
126
|
tags: [],
|
|
107
127
|
};
|
|
108
128
|
|
|
109
|
-
|
|
129
|
+
// Always map components, but filter based on editability and descendants
|
|
130
|
+
const mappedComponents = p.components.map((c) => mapComponentNode(c, node));
|
|
131
|
+
|
|
132
|
+
if (editContext?.hideNonEditableComponents) {
|
|
133
|
+
// Show components that are either editable or have editable descendants
|
|
134
|
+
node.children = mappedComponents.filter((componentNode) => {
|
|
135
|
+
const component = componentNode.data as Component;
|
|
136
|
+
return component.editable || hasEditableDescendants(component);
|
|
137
|
+
});
|
|
138
|
+
} else {
|
|
139
|
+
node.children = mappedComponents;
|
|
140
|
+
}
|
|
110
141
|
|
|
111
142
|
return node;
|
|
112
143
|
}
|
|
@@ -119,23 +150,42 @@ export function ComponentTree({}) {
|
|
|
119
150
|
return [];
|
|
120
151
|
}
|
|
121
152
|
|
|
122
|
-
//
|
|
123
|
-
|
|
153
|
+
// Filter placeholders based on hideNonEditableComponents setting and editable descendants
|
|
154
|
+
let placeholdersToShow = c.placeholders;
|
|
155
|
+
if (editContext?.hideNonEditableComponents) {
|
|
156
|
+
placeholdersToShow = c.placeholders.filter((p) => {
|
|
157
|
+
// Show placeholder if it's editable or has editable descendants
|
|
158
|
+
if (p.editable) return true;
|
|
159
|
+
return p.components.some(
|
|
160
|
+
(comp) => comp.editable || hasEditableDescendants(comp),
|
|
161
|
+
);
|
|
162
|
+
});
|
|
163
|
+
}
|
|
124
164
|
|
|
125
|
-
if (
|
|
126
|
-
return
|
|
127
|
-
} else if (
|
|
128
|
-
const placeholder =
|
|
129
|
-
// For single placeholders,
|
|
130
|
-
|
|
165
|
+
if (placeholdersToShow.length > 1) {
|
|
166
|
+
return placeholdersToShow.map((x) => mapPlaceholderNode(x, parent));
|
|
167
|
+
} else if (placeholdersToShow.length > 0) {
|
|
168
|
+
const placeholder = placeholdersToShow[0]!;
|
|
169
|
+
// For single placeholders, map the components directly (don't show placeholder node)
|
|
170
|
+
const mappedComponents = placeholder.components.map((c) => {
|
|
131
171
|
const componentNode = mapComponentNode(c, parent);
|
|
132
|
-
// Apply gray styling to components in non-editable placeholders
|
|
133
|
-
if (!placeholder.editable) {
|
|
172
|
+
// Apply gray styling to components in non-editable placeholders (only when showing non-editable components)
|
|
173
|
+
if (!placeholder.editable && !editContext?.hideNonEditableComponents) {
|
|
134
174
|
componentNode.className =
|
|
135
175
|
(componentNode.className || "") + " text-gray-400";
|
|
136
176
|
}
|
|
137
177
|
return componentNode;
|
|
138
178
|
});
|
|
179
|
+
|
|
180
|
+
if (editContext?.hideNonEditableComponents) {
|
|
181
|
+
// Filter components to only show editable ones or those with editable descendants
|
|
182
|
+
return mappedComponents.filter((componentNode) => {
|
|
183
|
+
const component = componentNode.data as Component;
|
|
184
|
+
return component.editable || hasEditableDescendants(component);
|
|
185
|
+
});
|
|
186
|
+
} else {
|
|
187
|
+
return mappedComponents;
|
|
188
|
+
}
|
|
139
189
|
}
|
|
140
190
|
return [];
|
|
141
191
|
}
|
|
@@ -158,7 +208,8 @@ export function ComponentTree({}) {
|
|
|
158
208
|
data: c,
|
|
159
209
|
parent: parent,
|
|
160
210
|
tags: [],
|
|
161
|
-
className:
|
|
211
|
+
className:
|
|
212
|
+
c.isRemovedFromMasterLanguage || !c.editable ? "text-gray-400" : "",
|
|
162
213
|
type: "component",
|
|
163
214
|
};
|
|
164
215
|
|
|
@@ -219,6 +270,7 @@ export function ComponentTree({}) {
|
|
|
219
270
|
node.children = mapPlaceholders(c, node);
|
|
220
271
|
|
|
221
272
|
if (c.items.length > 0 && c.items[0]!.id !== c.datasourceItem?.id) {
|
|
273
|
+
console.log("c.items", c.items, c);
|
|
222
274
|
const itemsNode: CustomTreeNode = {
|
|
223
275
|
key: "items" + c.id,
|
|
224
276
|
label: "items",
|
|
@@ -287,6 +339,7 @@ export function ComponentTree({}) {
|
|
|
287
339
|
|
|
288
340
|
const handleTreeSelection = useCallback(
|
|
289
341
|
(key: string, event: React.MouseEvent) => {
|
|
342
|
+
console.log("handleTreeSelection", key, event);
|
|
290
343
|
let newKeys = [key];
|
|
291
344
|
if (event.ctrlKey) {
|
|
292
345
|
if (selectedKeys.includes(key)) {
|
|
@@ -300,6 +353,8 @@ export function ComponentTree({}) {
|
|
|
300
353
|
.filter((key) => nodeDictionary[key])
|
|
301
354
|
.map((key) => nodeDictionary[key]!.componentId!);
|
|
302
355
|
|
|
356
|
+
console.log("selectedComponentIds", selectedComponentIds, nodeDictionary);
|
|
357
|
+
|
|
303
358
|
editContextRef.current?.select(selectedComponentIds);
|
|
304
359
|
|
|
305
360
|
if (selectedComponentIds.length === 1) {
|
|
@@ -489,60 +544,88 @@ export function ComponentTree({}) {
|
|
|
489
544
|
|
|
490
545
|
// Use the PerfectTree component
|
|
491
546
|
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
|
-
|
|
547
|
+
<div className="flex h-full flex-col">
|
|
548
|
+
{/* Toolbar */}
|
|
549
|
+
<div className="flex items-center justify-between border-b border-gray-200 px-2 py-1">
|
|
550
|
+
<SimpleIconButton
|
|
551
|
+
icon={
|
|
552
|
+
editContext?.hideNonEditableComponents ? (
|
|
553
|
+
<EyeOff className="h-4 w-4" strokeWidth={1.5} />
|
|
554
|
+
) : (
|
|
555
|
+
<EyeIcon className="h-4 w-4" strokeWidth={1.5} />
|
|
556
|
+
)
|
|
557
|
+
}
|
|
558
|
+
label={
|
|
559
|
+
editContext?.hideNonEditableComponents
|
|
560
|
+
? "Show non-editable components"
|
|
561
|
+
: "Hide non-editable components"
|
|
562
|
+
}
|
|
563
|
+
size="small"
|
|
564
|
+
selected={editContext?.hideNonEditableComponents}
|
|
565
|
+
onClick={() =>
|
|
566
|
+
editContext?.setHideNonEditableComponents(
|
|
567
|
+
!editContext.hideNonEditableComponents,
|
|
568
|
+
)
|
|
569
|
+
}
|
|
570
|
+
/>
|
|
571
|
+
</div>
|
|
572
|
+
|
|
573
|
+
{/* Tree content */}
|
|
574
|
+
<div className="flex-1 p-2" ref={treeRef}>
|
|
575
|
+
<PerfectTree
|
|
576
|
+
nodes={rootNodes}
|
|
577
|
+
isDragging={!!editContext?.dragObject}
|
|
578
|
+
selectedKeys={selectedItems}
|
|
579
|
+
expandedKeys={expandedItems}
|
|
580
|
+
onToggleExpand={handleToggle}
|
|
581
|
+
onSelect={handleTreeSelection}
|
|
582
|
+
onContextMenu={handleTreeContextMenu}
|
|
583
|
+
enableDragAndDrop={true}
|
|
584
|
+
onDragOverZone={(parent, index, event) =>
|
|
585
|
+
handleDragOverZone(parent as CustomTreeNode | null, index, event)
|
|
586
|
+
}
|
|
587
|
+
isValidDropZone={(parent, index) => {
|
|
588
|
+
const placeholder = getPlaceholder(parent as CustomTreeNode | null);
|
|
589
|
+
if (!placeholder) return false;
|
|
590
|
+
if (!editContext?.dragObject) return false;
|
|
591
|
+
const result = isValidPlaceholder(
|
|
592
|
+
placeholder,
|
|
593
|
+
editContext.dragObject,
|
|
594
|
+
);
|
|
595
|
+
|
|
596
|
+
return result;
|
|
597
|
+
}}
|
|
598
|
+
onStartDrag={(data) => {
|
|
599
|
+
const component = data.node.data as Component;
|
|
600
|
+
|
|
601
|
+
// Initialize drag data to make sure dataTransfer is set
|
|
602
|
+
data.event.dataTransfer.setData("text/plain", data.node.key);
|
|
603
|
+
|
|
604
|
+
// Only create drag object for components with datasourceItem
|
|
605
|
+
if (!component?.datasourceItem) return;
|
|
606
|
+
setTimeout(() => {
|
|
607
|
+
editContext!.dragStart({
|
|
608
|
+
type: "component",
|
|
609
|
+
typeId: component.typeId,
|
|
610
|
+
templateId: component.datasourceItem?.templateId,
|
|
611
|
+
name: component.name,
|
|
612
|
+
component: {
|
|
613
|
+
id: component.id,
|
|
614
|
+
language: editContext!.page!.item.language,
|
|
615
|
+
version: editContext!.page!.item.version,
|
|
616
|
+
},
|
|
617
|
+
});
|
|
618
|
+
}, 1);
|
|
619
|
+
}}
|
|
620
|
+
onDragEnd={(event) => {
|
|
621
|
+
editContext!.dragEnd();
|
|
622
|
+
}}
|
|
623
|
+
onDrop={(parent, index, event) =>
|
|
624
|
+
handleDropZone(parent as CustomTreeNode | null, index, event)
|
|
625
|
+
}
|
|
626
|
+
renderNode={(node) => renderNode(node as CustomTreeNode)}
|
|
627
|
+
/>
|
|
628
|
+
</div>
|
|
546
629
|
</div>
|
|
547
630
|
);
|
|
548
631
|
}
|
|
@@ -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,19 @@ 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
|
+
) {
|
|
269
|
+
console.log("found editable component", element);
|
|
261
270
|
return element.getAttribute("data-component-start") ?? undefined;
|
|
262
271
|
}
|
|
263
272
|
const prev: Element | null = element.previousElementSibling;
|
|
@@ -268,6 +277,10 @@ export function findNearestComponentId(startElement: Element) {
|
|
|
268
277
|
return;
|
|
269
278
|
}
|
|
270
279
|
|
|
280
|
+
function isEditableComponent(element: Element) {
|
|
281
|
+
return element.getAttribute("data-editable") !== "false";
|
|
282
|
+
}
|
|
283
|
+
|
|
271
284
|
export function findFieldElement(
|
|
272
285
|
iframe: HTMLIFrameElement,
|
|
273
286
|
fieldDescriptor: FieldDescriptor,
|
|
@@ -427,35 +440,35 @@ export const getAbsolutePosition = (
|
|
|
427
440
|
};
|
|
428
441
|
};
|
|
429
442
|
|
|
430
|
-
export function findParentComponentId(element: HTMLElement) {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
443
|
+
// export function findParentComponentId(element: HTMLElement) {
|
|
444
|
+
// while (element && element !== document.documentElement) {
|
|
445
|
+
// if (element.getAttribute("sc_item")) {
|
|
446
|
+
// return extractItemIdFromItemUri(element.getAttribute("sc_item")!);
|
|
447
|
+
// }
|
|
435
448
|
|
|
436
|
-
|
|
449
|
+
// const startElement = findStartElement(element);
|
|
437
450
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
}
|
|
451
|
+
// if (startElement) {
|
|
452
|
+
// return startElement.getAttribute("data-component-start");
|
|
453
|
+
// }
|
|
454
|
+
// element = element.parentElement as HTMLElement;
|
|
455
|
+
// }
|
|
456
|
+
// return null;
|
|
457
|
+
// }
|
|
445
458
|
|
|
446
|
-
function findStartElement(element: HTMLElement) {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
}
|
|
459
|
+
// function findStartElement(element: HTMLElement) {
|
|
460
|
+
// let prev: Element | null = element;
|
|
461
|
+
// while (prev) {
|
|
462
|
+
// prev = prev.previousElementSibling;
|
|
463
|
+
// if (
|
|
464
|
+
// prev?.getAttribute("data-component-start") &&
|
|
465
|
+
// !prev.hasAttribute("data-skip-component")
|
|
466
|
+
// ) {
|
|
467
|
+
// return prev;
|
|
468
|
+
// }
|
|
469
|
+
// }
|
|
470
|
+
// return null;
|
|
471
|
+
// }
|
|
459
472
|
|
|
460
473
|
export function normalizeGuid(id: string) {
|
|
461
474
|
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.3973";
|
|
2
|
+
export const buildDate = "2025-07-02 01:52:41";
|
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;
|