@alpaca-editor/core 1.0.3997 → 1.0.4007
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/client-components/index.d.ts +1 -0
- package/dist/client-components/index.js +1 -0
- package/dist/client-components/index.js.map +1 -1
- package/dist/components/ui/calendar.d.ts +7 -0
- package/dist/components/ui/calendar.js +62 -0
- package/dist/components/ui/calendar.js.map +1 -0
- package/dist/config/config.js +11 -0
- package/dist/config/config.js.map +1 -1
- package/dist/editor/ContentTree.d.ts +2 -1
- package/dist/editor/ContentTree.js +2 -2
- package/dist/editor/ContentTree.js.map +1 -1
- package/dist/editor/FieldList.js +37 -10
- package/dist/editor/FieldList.js.map +1 -1
- package/dist/editor/FieldListField.js +21 -10
- package/dist/editor/FieldListField.js.map +1 -1
- package/dist/editor/client/EditorClient.js +5 -3
- package/dist/editor/client/EditorClient.js.map +1 -1
- package/dist/editor/client/itemsRepository.js +57 -9
- package/dist/editor/client/itemsRepository.js.map +1 -1
- package/dist/editor/client/pageModelBuilder.js +1 -1
- package/dist/editor/client/pageModelBuilder.js.map +1 -1
- package/dist/editor/commands/itemCommands.js +1 -1
- package/dist/editor/commands/itemCommands.js.map +1 -1
- package/dist/editor/field-types/DateFieldEditor.d.ts +5 -0
- package/dist/editor/field-types/DateFieldEditor.js +93 -0
- package/dist/editor/field-types/DateFieldEditor.js.map +1 -0
- package/dist/editor/field-types/ImageFieldEditor.js +1 -1
- package/dist/editor/field-types/ImageFieldEditor.js.map +1 -1
- package/dist/editor/field-types/InternalLinkFieldEditor.js +29 -9
- package/dist/editor/field-types/InternalLinkFieldEditor.js.map +1 -1
- package/dist/editor/field-types/LinkFieldEditor.js +1 -1
- package/dist/editor/field-types/LinkFieldEditor.js.map +1 -1
- package/dist/editor/field-types/MultiLineText.js +3 -1
- package/dist/editor/field-types/MultiLineText.js.map +1 -1
- package/dist/editor/field-types/PictureFieldEditor.js +1 -1
- package/dist/editor/field-types/PictureFieldEditor.js.map +1 -1
- package/dist/editor/field-types/SingleLineText.js +3 -1
- package/dist/editor/field-types/SingleLineText.js.map +1 -1
- package/dist/editor/field-types/TreeListEditor.js +90 -17
- 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/fieldTypes.d.ts +1 -1
- package/dist/editor/media-selector/AiImageSearch.js +2 -1
- package/dist/editor/media-selector/AiImageSearch.js.map +1 -1
- package/dist/editor/media-selector/AiImageSearchPrompt.js +2 -1
- package/dist/editor/media-selector/AiImageSearchPrompt.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/page-viewer/DeviceToolbar.js +3 -2
- package/dist/editor/page-viewer/DeviceToolbar.js.map +1 -1
- package/dist/editor/page-viewer/MiniMap.js +6 -1
- package/dist/editor/page-viewer/MiniMap.js.map +1 -1
- package/dist/editor/services/aiService.d.ts +9 -1
- package/dist/editor/services/aiService.js.map +1 -1
- package/dist/editor/sidebar/Insert.js +1 -1
- package/dist/editor/sidebar/Insert.js.map +1 -1
- package/dist/editor/sidebar/MainContentTree.d.ts +1 -1
- package/dist/editor/sidebar/MainContentTree.js +19 -7
- package/dist/editor/sidebar/MainContentTree.js.map +1 -1
- package/dist/editor/ui/Icons.js +1 -1
- package/dist/editor/ui/Icons.js.map +1 -1
- package/dist/editor/ui/ItemNameDialogNew.js +14 -10
- package/dist/editor/ui/ItemNameDialogNew.js.map +1 -1
- package/dist/editor/ui/PerfectTree.d.ts +2 -0
- package/dist/editor/ui/PerfectTree.js +1 -1
- package/dist/editor/ui/PerfectTree.js.map +1 -1
- package/dist/editor/ui/Spinner.js +1 -1
- package/dist/editor/ui/Spinner.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 +118 -27
- package/dist/page-wizard/steps/ContentStep.js.map +1 -1
- package/dist/page-wizard/steps/FindItemsStep.d.ts +2 -0
- package/dist/page-wizard/steps/FindItemsStep.js +293 -0
- package/dist/page-wizard/steps/FindItemsStep.js.map +1 -0
- package/dist/page-wizard/steps/ImagesStep.js +9 -1
- package/dist/page-wizard/steps/ImagesStep.js.map +1 -1
- package/dist/page-wizard/steps/LayoutStep.js +24 -14
- package/dist/page-wizard/steps/LayoutStep.js.map +1 -1
- package/dist/page-wizard/steps/MetaDataStep.js +21 -11
- package/dist/page-wizard/steps/MetaDataStep.js.map +1 -1
- package/dist/page-wizard/steps/SelectStep.js +38 -31
- package/dist/page-wizard/steps/SelectStep.js.map +1 -1
- package/dist/page-wizard/steps/StructureStep.d.ts +2 -0
- package/dist/page-wizard/steps/StructureStep.js +156 -0
- package/dist/page-wizard/steps/StructureStep.js.map +1 -0
- 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/page-wizard/utils/dataAccessor.d.ts +39 -0
- package/dist/page-wizard/utils/dataAccessor.js +222 -0
- package/dist/page-wizard/utils/dataAccessor.js.map +1 -0
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/splash-screen/RecentPages.js +14 -3
- package/dist/splash-screen/RecentPages.js.map +1 -1
- package/dist/styles.css +180 -2
- package/package.json +3 -1
- package/src/client-components/index.ts +1 -3
- package/src/components/ui/calendar.tsx +175 -0
- package/src/config/config.tsx +11 -1
- package/src/editor/ContentTree.tsx +4 -1
- package/src/editor/FieldList.tsx +44 -18
- package/src/editor/FieldListField.tsx +98 -23
- package/src/editor/client/EditorClient.tsx +6 -3
- package/src/editor/client/itemsRepository.ts +74 -10
- package/src/editor/client/pageModelBuilder.ts +1 -1
- package/src/editor/commands/itemCommands.tsx +2 -3
- package/src/editor/field-types/DateFieldEditor.tsx +132 -0
- package/src/editor/field-types/ImageFieldEditor.tsx +1 -1
- package/src/editor/field-types/InternalLinkFieldEditor.tsx +99 -73
- package/src/editor/field-types/LinkFieldEditor.tsx +2 -2
- package/src/editor/field-types/MultiLineText.tsx +5 -1
- package/src/editor/field-types/PictureFieldEditor.tsx +1 -1
- package/src/editor/field-types/SingleLineText.tsx +5 -1
- package/src/editor/field-types/TreeListEditor.tsx +149 -56
- package/src/editor/field-types/richtext/components/ReactSlate.tsx +537 -446
- package/src/editor/fieldTypes.ts +1 -1
- package/src/editor/media-selector/AiImageSearch.tsx +2 -1
- package/src/editor/media-selector/AiImageSearchPrompt.tsx +2 -1
- package/src/editor/page-editor-chrome/PlaceholderDropZone.tsx +1 -1
- package/src/editor/page-viewer/DeviceToolbar.tsx +17 -5
- package/src/editor/page-viewer/MiniMap.tsx +7 -2
- package/src/editor/services/aiService.ts +10 -1
- package/src/editor/sidebar/Insert.tsx +1 -1
- package/src/editor/sidebar/MainContentTree.tsx +27 -14
- package/src/editor/ui/Icons.tsx +16 -5
- package/src/editor/ui/ItemNameDialogNew.tsx +42 -30
- package/src/editor/ui/PerfectTree.tsx +3 -1
- package/src/editor/ui/Spinner.tsx +3 -1
- 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 +149 -34
- package/src/page-wizard/steps/FindItemsStep.tsx +546 -0
- package/src/page-wizard/steps/ImagesStep.tsx +13 -1
- package/src/page-wizard/steps/LayoutStep.tsx +27 -16
- package/src/page-wizard/steps/MetaDataStep.tsx +26 -13
- package/src/page-wizard/steps/SelectStep.tsx +61 -32
- package/src/page-wizard/steps/StructureStep.tsx +350 -0
- 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/page-wizard/utils/dataAccessor.ts +275 -0
- package/src/revision.ts +2 -2
- package/src/splash-screen/RecentPages.tsx +22 -3
- package/dist/editor/ai/GhostWriter.d.ts +0 -1
- package/dist/editor/ai/GhostWriter.js +0 -347
- package/dist/editor/ai/GhostWriter.js.map +0 -1
- package/dist/editor/component-designer/ComponentDesignerAiTerminal.d.ts +0 -1
- package/dist/editor/component-designer/ComponentDesignerAiTerminal.js +0 -7
- package/dist/editor/component-designer/ComponentDesignerAiTerminal.js.map +0 -1
- /package/src/editor/ai/{GhostWriter.tsx → GhostWriter.tsx_} +0 -0
- /package/src/editor/component-designer/{ComponentDesignerAiTerminal.tsx → ComponentDesignerAiTerminal.tsx_} +0 -0
package/src/editor/fieldTypes.ts
CHANGED
|
@@ -70,7 +70,8 @@ export function AiImageSearch({
|
|
|
70
70
|
);
|
|
71
71
|
|
|
72
72
|
setLoadingPrompt(false);
|
|
73
|
-
const
|
|
73
|
+
const lastMessage = result?.messages?.[result.messages.length - 1];
|
|
74
|
+
const newPrompt = lastMessage?.content?.replaceAll("\n", "") || "";
|
|
74
75
|
setPrompt(newPrompt);
|
|
75
76
|
} catch (error) {
|
|
76
77
|
if (error instanceof Error && error.name !== "AbortError") {
|
|
@@ -53,7 +53,8 @@ export function AiImageSearchPrompt({
|
|
|
53
53
|
);
|
|
54
54
|
|
|
55
55
|
setLoadingPrompt(false);
|
|
56
|
-
const
|
|
56
|
+
const lastMessage = result?.messages?.[result.messages.length - 1];
|
|
57
|
+
const newPrompt = lastMessage?.content?.replaceAll("\n", "") || "";
|
|
57
58
|
setPrompt(newPrompt);
|
|
58
59
|
} catch (error) {
|
|
59
60
|
if (error instanceof Error && error.name !== "AbortError") {
|
|
@@ -137,7 +137,7 @@ export function PlaceholderDropZone({
|
|
|
137
137
|
{
|
|
138
138
|
label: insertMenuTitle || "Insert",
|
|
139
139
|
disabled: true,
|
|
140
|
-
className: "border-b border-gray-400 pb-2 pl-2",
|
|
140
|
+
className: "border-b border-gray-400 pb-2 pl-2 text-xs",
|
|
141
141
|
template: () => {
|
|
142
142
|
return <span className="text-sm text-black">Insert</span>;
|
|
143
143
|
},
|
|
@@ -5,6 +5,7 @@ import { RotateDeviceIcon } from "../ui/Icons";
|
|
|
5
5
|
import { useDebouncedCallback } from "use-debounce";
|
|
6
6
|
import { PageViewContext } from "./pageViewContext";
|
|
7
7
|
import { EditorConfiguration } from "../../config/types";
|
|
8
|
+
import { cn } from "../../lib/utils";
|
|
8
9
|
|
|
9
10
|
export function DeviceToolbar({
|
|
10
11
|
pageViewContext,
|
|
@@ -17,17 +18,17 @@ export function DeviceToolbar({
|
|
|
17
18
|
(width: number | undefined) => {
|
|
18
19
|
pageViewContext.setDeviceWidth(width);
|
|
19
20
|
},
|
|
20
|
-
400
|
|
21
|
+
400,
|
|
21
22
|
);
|
|
22
23
|
const debouncedSetDeviceHeight = useDebouncedCallback(
|
|
23
24
|
(height: number | undefined) => {
|
|
24
25
|
pageViewContext.setDeviceHeight(height);
|
|
25
26
|
},
|
|
26
|
-
400
|
|
27
|
+
400,
|
|
27
28
|
);
|
|
28
29
|
|
|
29
30
|
return (
|
|
30
|
-
<div className="
|
|
31
|
+
<div className="bg-gray-4 z-1000 mb-2 flex w-full items-center justify-center gap-2 text-sm">
|
|
31
32
|
<Dropdown
|
|
32
33
|
options={configuration.devices.map((x) => ({
|
|
33
34
|
label: x.name,
|
|
@@ -53,6 +54,7 @@ export function DeviceToolbar({
|
|
|
53
54
|
/>
|
|
54
55
|
<SimpleIconButton
|
|
55
56
|
icon="pi pi-lock"
|
|
57
|
+
className="hover:bg-gray-3"
|
|
56
58
|
selected={pageViewContext.lockHeight || false}
|
|
57
59
|
onClick={() =>
|
|
58
60
|
pageViewContext.setLockHeight(!pageViewContext.lockHeight)
|
|
@@ -60,10 +62,20 @@ export function DeviceToolbar({
|
|
|
60
62
|
label="Lock Height"
|
|
61
63
|
/>
|
|
62
64
|
<SimpleIconButton
|
|
63
|
-
|
|
65
|
+
className="hover:bg-gray-3"
|
|
66
|
+
icon={
|
|
67
|
+
<RotateDeviceIcon
|
|
68
|
+
className={cn(
|
|
69
|
+
"h-4 w-4 transition-transform duration-300",
|
|
70
|
+
pageViewContext.rotate ? "rotate-90" : "",
|
|
71
|
+
)}
|
|
72
|
+
/>
|
|
73
|
+
}
|
|
64
74
|
selected={pageViewContext.rotate || false}
|
|
65
75
|
onClick={() => pageViewContext.setRotate(!pageViewContext.rotate)}
|
|
66
|
-
label=
|
|
76
|
+
label={
|
|
77
|
+
pageViewContext.rotate ? "Switch to Portrait" : "Switch to Landscape"
|
|
78
|
+
}
|
|
67
79
|
/>
|
|
68
80
|
</div>
|
|
69
81
|
);
|
|
@@ -123,9 +123,14 @@ export function MiniMap({
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
if (correspondingNode && originalNode) {
|
|
126
|
-
if (originalNode.tagName === "HEAD")
|
|
126
|
+
if (originalNode.tagName === "HEAD") {
|
|
127
127
|
correspondingNode.innerHTML = originalNode.innerHTML;
|
|
128
|
-
else
|
|
128
|
+
} else if (
|
|
129
|
+
correspondingNode.parentNode?.nodeType === Node.DOCUMENT_NODE
|
|
130
|
+
) {
|
|
131
|
+
// Can't use outerHTML when parent is the document node
|
|
132
|
+
correspondingNode.innerHTML = originalNode.innerHTML;
|
|
133
|
+
} else {
|
|
129
134
|
correspondingNode.outerHTML = originalNode.outerHTML;
|
|
130
135
|
}
|
|
131
136
|
}
|
|
@@ -34,6 +34,15 @@ type Message = {
|
|
|
34
34
|
role: string;
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
+
export interface ExecutePromptResponse {
|
|
38
|
+
editOperations: any[];
|
|
39
|
+
messages: Message[];
|
|
40
|
+
numInputTokens: number;
|
|
41
|
+
numOutputTokens: number;
|
|
42
|
+
numCachedTokens: number;
|
|
43
|
+
state: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
37
46
|
export async function executePrompt(
|
|
38
47
|
messages: Message[],
|
|
39
48
|
editContext: EditContextType,
|
|
@@ -48,7 +57,7 @@ export async function executePrompt(
|
|
|
48
57
|
options?: RequestInit,
|
|
49
58
|
model?: string,
|
|
50
59
|
callback?: (response: any) => void,
|
|
51
|
-
): Promise<
|
|
60
|
+
): Promise<ExecutePromptResponse | null> {
|
|
52
61
|
const context = createAiContext({ editContext });
|
|
53
62
|
|
|
54
63
|
const response = await fetch(context.endpoint, {
|
|
@@ -10,7 +10,7 @@ export function MainContentTree({
|
|
|
10
10
|
mode,
|
|
11
11
|
rootItemId,
|
|
12
12
|
}: {
|
|
13
|
-
mode: "insert" | "normal" | "select-page";
|
|
13
|
+
mode: "insert-component" | "normal" | "select-page";
|
|
14
14
|
rootItemId?: string;
|
|
15
15
|
}) {
|
|
16
16
|
const editContext = useEditContext();
|
|
@@ -22,17 +22,28 @@ export function MainContentTree({
|
|
|
22
22
|
const [selectedItemIds, setSelectedItemIds] = useState<string[]>([]);
|
|
23
23
|
|
|
24
24
|
const isDraggable = useCallback(
|
|
25
|
-
(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
25
|
+
(item: ItemTreeNodeData) => {
|
|
26
|
+
// Only allow dragging in insert-component mode
|
|
27
|
+
if (mode !== "insert-component") {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!insertOptions) return false;
|
|
32
|
+
|
|
33
|
+
// Check if the item's template is compatible with any insert option
|
|
34
|
+
return insertOptions.some((insertOption) => {
|
|
35
|
+
// Direct type match
|
|
36
|
+
if (insertOption.typeId === item.templateId) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Compatible type match
|
|
41
|
+
return (
|
|
42
|
+
insertOption.compatibleTypeIds?.some(
|
|
43
|
+
(compatibleTypeId) => compatibleTypeId === item.templateId,
|
|
44
|
+
) ?? false
|
|
45
|
+
);
|
|
46
|
+
});
|
|
36
47
|
},
|
|
37
48
|
[mode, insertOptions],
|
|
38
49
|
);
|
|
@@ -73,12 +84,13 @@ export function MainContentTree({
|
|
|
73
84
|
? selectedItem?.idPath.split("/").slice(0, -1).join("/")
|
|
74
85
|
: undefined
|
|
75
86
|
}
|
|
87
|
+
scrollToSelected={true}
|
|
76
88
|
className="h-full"
|
|
77
89
|
selectPagesOnly={mode === "select-page"}
|
|
78
|
-
selectionMode={mode == "insert" ? "none" : "multiple"}
|
|
90
|
+
selectionMode={mode == "insert-component" ? "none" : "multiple"}
|
|
79
91
|
selectedItemIds={selectedItemIds}
|
|
80
92
|
onSelectionChange={(selection) => {
|
|
81
|
-
if (mode === "insert") return;
|
|
93
|
+
if (mode === "insert-component") return;
|
|
82
94
|
const selectedItems = selection as ItemTreeNodeData[];
|
|
83
95
|
setSelectedItemIds(selectedItems.map((x) => x.id));
|
|
84
96
|
if (selectedItems.length > 0 && selectedItems[0])
|
|
@@ -88,6 +100,7 @@ export function MainContentTree({
|
|
|
88
100
|
version: selectedItems[0].version,
|
|
89
101
|
});
|
|
90
102
|
}}
|
|
103
|
+
showGrabCursorForDraggableNodes={mode === "insert-component"}
|
|
91
104
|
isDraggable={isDraggable}
|
|
92
105
|
renderNode={(node, defaultRenderer) => (
|
|
93
106
|
<div className="group flex w-full gap-4">
|
package/src/editor/ui/Icons.tsx
CHANGED
|
@@ -393,14 +393,25 @@ export function FormEditIcon({ className }: { className?: string }) {
|
|
|
393
393
|
export function RotateDeviceIcon({ className }: { className?: string }) {
|
|
394
394
|
return (
|
|
395
395
|
<svg
|
|
396
|
-
|
|
396
|
+
width="16"
|
|
397
|
+
height="18"
|
|
398
|
+
viewBox="0 0 16 18"
|
|
399
|
+
fill="none"
|
|
397
400
|
xmlns="http://www.w3.org/2000/svg"
|
|
398
401
|
className={className}
|
|
399
|
-
stroke="currentColor"
|
|
400
|
-
fill="currentColor"
|
|
401
402
|
>
|
|
402
|
-
<path
|
|
403
|
-
|
|
403
|
+
<path
|
|
404
|
+
d="M10.24 9C10.8561 9 11.1641 9 11.3994 9.12456C11.6064 9.23413 11.7746 9.40897 11.8801 9.62401C12 9.86848 12 10.1885 12 10.8286L12 15.1714C12 15.8115 12 16.1315 11.8801 16.376C11.7746 16.591 11.6064 16.7659 11.3994 16.8754C11.1641 17 10.8561 17 10.24 17L2.76 17C2.14394 17 1.83591 17 1.60061 16.8754C1.39363 16.7659 1.22535 16.591 1.11989 16.376C0.999999 16.1315 0.999999 15.8115 0.999999 15.1714L1 10.8286C1 10.1885 1 9.86848 1.11989 9.62401C1.22535 9.40897 1.39363 9.23413 1.60061 9.12456C1.83591 9 2.14394 9 2.76 9L10.24 9Z"
|
|
405
|
+
stroke="#111111"
|
|
406
|
+
stroke-linecap="round"
|
|
407
|
+
stroke-linejoin="round"
|
|
408
|
+
/>
|
|
409
|
+
<path
|
|
410
|
+
d="M15 11L15 9.11111C15 7.24427 15 6.31085 14.6321 5.59781C14.3086 4.9706 13.7923 4.46067 13.1572 4.14109C12.4353 3.77778 11.4902 3.77778 9.6 3.77778L6 3.77778M6 3.77778L8.8125 6.55556M6 3.77778L8.8125 1"
|
|
411
|
+
stroke="#111111"
|
|
412
|
+
stroke-linecap="round"
|
|
413
|
+
stroke-linejoin="round"
|
|
414
|
+
/>
|
|
404
415
|
</svg>
|
|
405
416
|
);
|
|
406
417
|
}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Dialog,
|
|
3
|
+
DialogContent,
|
|
4
|
+
DialogHeader,
|
|
5
|
+
DialogTitle,
|
|
6
|
+
} from "../../components/ui/dialog";
|
|
2
7
|
|
|
3
8
|
import { useEffect, useRef, useState } from "react";
|
|
4
9
|
import DialogButtons from "./DialogButtons";
|
|
@@ -32,6 +37,12 @@ export function ItemNameDialog(
|
|
|
32
37
|
setName(props?.name || "");
|
|
33
38
|
}, [props]);
|
|
34
39
|
|
|
40
|
+
// Focus and select the input when dialog opens
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
nameRef.current?.focus();
|
|
43
|
+
nameRef.current?.select();
|
|
44
|
+
}, []);
|
|
45
|
+
|
|
35
46
|
const checkNameValidDebounced = useDebouncedCallback(
|
|
36
47
|
async () => checkName(),
|
|
37
48
|
500,
|
|
@@ -81,38 +92,39 @@ export function ItemNameDialog(
|
|
|
81
92
|
|
|
82
93
|
return (
|
|
83
94
|
<Dialog
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
nameRef.current?.focus();
|
|
90
|
-
nameRef.current?.select();
|
|
95
|
+
open={true}
|
|
96
|
+
onOpenChange={(open) => {
|
|
97
|
+
if (!open) {
|
|
98
|
+
props.onClose?.(null);
|
|
99
|
+
}
|
|
91
100
|
}}
|
|
92
|
-
style={{ width: "400px" }}
|
|
93
|
-
header={props?.title ?? "Name"}
|
|
94
101
|
>
|
|
95
|
-
<
|
|
96
|
-
<
|
|
97
|
-
{props
|
|
102
|
+
<DialogContent style={{ width: "400px" }}>
|
|
103
|
+
<DialogHeader>
|
|
104
|
+
<DialogTitle>{props?.title ?? "Name"}</DialogTitle>
|
|
105
|
+
</DialogHeader>
|
|
106
|
+
<div className="p-3">
|
|
107
|
+
<div className="my-2 text-sm">
|
|
108
|
+
{props.message || "Enter a name for the new item:"}
|
|
109
|
+
</div>
|
|
110
|
+
<InputText
|
|
111
|
+
ref={nameRef}
|
|
112
|
+
value={name}
|
|
113
|
+
className="w-full"
|
|
114
|
+
onChange={(e) => setName(e.target.value)}
|
|
115
|
+
onKeyDown={(ev) => {
|
|
116
|
+
if (ev.key === "Enter" && isValid) handleOk();
|
|
117
|
+
}}
|
|
118
|
+
/>
|
|
119
|
+
{validationError && (
|
|
120
|
+
<div className="mt-2 text-red-500">{validationError}</div>
|
|
121
|
+
)}
|
|
98
122
|
</div>
|
|
99
|
-
<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
onKeyDown={(ev) => {
|
|
105
|
-
if (ev.key === "Enter" && isValid) handleOk();
|
|
106
|
-
}}
|
|
107
|
-
/>
|
|
108
|
-
{validationError && (
|
|
109
|
-
<div className="mt-2 text-red-500">{validationError}</div>
|
|
110
|
-
)}
|
|
111
|
-
</div>
|
|
112
|
-
<DialogButtons>
|
|
113
|
-
<Button onClick={handleOk} label="Ok" disabled={!isValid} />
|
|
114
|
-
<Button onClick={() => props.onClose?.(null)} label="Cancel" />
|
|
115
|
-
</DialogButtons>
|
|
123
|
+
<DialogButtons>
|
|
124
|
+
<Button onClick={handleOk} label="Ok" disabled={!isValid} />
|
|
125
|
+
<Button onClick={() => props.onClose?.(null)} label="Cancel" />
|
|
126
|
+
</DialogButtons>
|
|
127
|
+
</DialogContent>
|
|
116
128
|
</Dialog>
|
|
117
129
|
);
|
|
118
130
|
}
|
|
@@ -16,6 +16,8 @@ export interface TreeNode<T = any> {
|
|
|
16
16
|
data?: T;
|
|
17
17
|
/** Indicates if the node is expandable (has or can have children) */
|
|
18
18
|
hasChildren?: boolean;
|
|
19
|
+
/** Indicates if the node can be dragged */
|
|
20
|
+
isDraggable?: boolean;
|
|
19
21
|
/**
|
|
20
22
|
* If present, contains the node's children.
|
|
21
23
|
* Use undefined to signal that children have not yet been loaded.
|
|
@@ -530,7 +532,7 @@ const NodeContent = memo(
|
|
|
530
532
|
return (
|
|
531
533
|
<div
|
|
532
534
|
className="tree-node mb-0.5 flex cursor-pointer items-center"
|
|
533
|
-
draggable={enableDragAndDrop}
|
|
535
|
+
draggable={enableDragAndDrop && !!node.isDraggable}
|
|
534
536
|
onClick={handleSelect}
|
|
535
537
|
onDragStart={(event) => handleDragStart(event)}
|
|
536
538
|
onDragEnd={onDragEnd as any}
|
package/src/editor/utils.ts
CHANGED
|
@@ -465,6 +465,10 @@ export const getAbsolutePosition = (
|
|
|
465
465
|
// return null;
|
|
466
466
|
// }
|
|
467
467
|
|
|
468
|
+
export function stripGuid(id: string) {
|
|
469
|
+
return id.replace(/[{}]/g, "").toLowerCase();
|
|
470
|
+
}
|
|
471
|
+
|
|
468
472
|
export function normalizeGuid(id: string) {
|
|
469
473
|
id = id.toUpperCase();
|
|
470
474
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { useEditContext } from "../client/editContext";
|
|
3
3
|
import { LanguageSelector } from "../menubar/LanguageSelector";
|
|
4
4
|
import { VersionSelector } from "../menubar/VersionSelector";
|
|
5
5
|
import { FullItem, ItemDescriptor, Version } from "../pageModel";
|
|
@@ -13,7 +13,10 @@ export type Wizard = {
|
|
|
13
13
|
templateId: string;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
export type PageSchema =
|
|
16
|
+
export type PageSchema = {
|
|
17
|
+
placeholders: SchemaPlaceholder[];
|
|
18
|
+
pageFields: SchemaField[];
|
|
19
|
+
};
|
|
17
20
|
|
|
18
21
|
export type SchemaComponent = {
|
|
19
22
|
type: string;
|
|
@@ -65,6 +68,7 @@ export type WizardPageModel = {
|
|
|
65
68
|
metaKeywords: string;
|
|
66
69
|
message?: string;
|
|
67
70
|
images?: Thumbnail[];
|
|
71
|
+
fields: WizardField[];
|
|
68
72
|
};
|
|
69
73
|
|
|
70
74
|
export type WizardPageComponent = {
|
|
@@ -330,6 +330,7 @@ export function WizardSteps({ wizard, parentItem }: WizardStepsProps) {
|
|
|
330
330
|
name: "",
|
|
331
331
|
metaDescription: "",
|
|
332
332
|
metaKeywords: "",
|
|
333
|
+
fields: [],
|
|
333
334
|
};
|
|
334
335
|
const setPageModel = pageWizard?.setPageModel ?? (() => {});
|
|
335
336
|
const internalState = pageWizard?.internalState ?? {};
|
|
@@ -15,6 +15,7 @@ export function ComponentTypeSelector({
|
|
|
15
15
|
data,
|
|
16
16
|
setData,
|
|
17
17
|
step,
|
|
18
|
+
availableComponentTypes,
|
|
18
19
|
}: {
|
|
19
20
|
selectedComponentTypes?: string[];
|
|
20
21
|
setSelectedComponentTypes: Dispatch<SetStateAction<string[]>>;
|
|
@@ -22,10 +23,8 @@ export function ComponentTypeSelector({
|
|
|
22
23
|
data: WizardData;
|
|
23
24
|
setData: (data: WizardData) => void;
|
|
24
25
|
step: WizardStep;
|
|
26
|
+
availableComponentTypes?: string[];
|
|
25
27
|
}) {
|
|
26
|
-
const [availableComponentTypes, setAvailableComponentTypes] = useState<
|
|
27
|
-
string[]
|
|
28
|
-
>([]);
|
|
29
28
|
const [preselectedTypes, setPreselectedTypes] = useState<string[]>([]);
|
|
30
29
|
const [searchFilter, setSearchFilter] = useState<string>("");
|
|
31
30
|
|
|
@@ -38,11 +37,13 @@ export function ComponentTypeSelector({
|
|
|
38
37
|
|
|
39
38
|
// Handle select all component types
|
|
40
39
|
const handleSelectAllComponents = () => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
if (availableComponentTypes) {
|
|
41
|
+
setSelectedComponentTypes(availableComponentTypes);
|
|
42
|
+
setData({
|
|
43
|
+
...data,
|
|
44
|
+
selectedComponentTypes: availableComponentTypes,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
46
47
|
};
|
|
47
48
|
|
|
48
49
|
// Handle clear all component types
|
|
@@ -86,56 +87,28 @@ export function ComponentTypeSelector({
|
|
|
86
87
|
};
|
|
87
88
|
|
|
88
89
|
// Filter available components by search term
|
|
89
|
-
const filteredComponentTypes =
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
const filteredComponentTypes =
|
|
91
|
+
availableComponentTypes?.filter((type) =>
|
|
92
|
+
type.toLowerCase().includes(searchFilter.toLowerCase()),
|
|
93
|
+
) || [];
|
|
92
94
|
|
|
93
|
-
// Helper function to
|
|
94
|
-
const
|
|
95
|
+
// Helper function to extract placeholders from the schema
|
|
96
|
+
const extractPlaceholders = (
|
|
95
97
|
items: PageSchema | SchemaComponent[],
|
|
96
98
|
): string[] => {
|
|
97
|
-
if (!items
|
|
98
|
-
|
|
99
|
-
let types: string[] = [];
|
|
100
|
-
|
|
101
|
-
for (const item of items) {
|
|
102
|
-
// Add the current component type if it exists
|
|
103
|
-
if ("type" in item) {
|
|
104
|
-
types.push(item.type);
|
|
105
|
-
}
|
|
99
|
+
if (!items) return [];
|
|
106
100
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
for (const placeholder of item.placeholders) {
|
|
110
|
-
if (placeholder.components && Array.isArray(placeholder.components)) {
|
|
111
|
-
types = [
|
|
112
|
-
...types,
|
|
113
|
-
...extractComponentTypes(placeholder.components),
|
|
114
|
-
];
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Process components directly (for top-level structure)
|
|
120
|
-
if ("components" in item && Array.isArray(item.components)) {
|
|
121
|
-
types = [...types, ...extractComponentTypes(item.components)];
|
|
122
|
-
}
|
|
101
|
+
if (items && "placeholders" in items) {
|
|
102
|
+
return items.placeholders.map((placeholder) => placeholder.name);
|
|
123
103
|
}
|
|
124
104
|
|
|
125
|
-
return
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
// Helper function to extract placeholders from the schema
|
|
129
|
-
const extractPlaceholders = (
|
|
130
|
-
items: PageSchema | SchemaComponent[],
|
|
131
|
-
): string[] => {
|
|
132
|
-
if (!items || !Array.isArray(items)) return [];
|
|
105
|
+
if (!Array.isArray(items)) return [];
|
|
133
106
|
|
|
134
107
|
let placeholders: string[] = [];
|
|
135
108
|
|
|
136
109
|
for (const item of items) {
|
|
137
110
|
// Add the current placeholder name if it exists
|
|
138
|
-
if ("name" in item) {
|
|
111
|
+
if ("name" in item && typeof item.name === "string") {
|
|
139
112
|
placeholders.push(item.name);
|
|
140
113
|
}
|
|
141
114
|
|
|
@@ -167,75 +140,20 @@ export function ComponentTypeSelector({
|
|
|
167
140
|
return placeholders;
|
|
168
141
|
};
|
|
169
142
|
|
|
170
|
-
// Initialize
|
|
171
|
-
const initializeSelections = (
|
|
172
|
-
uniqueTypes: string[],
|
|
173
|
-
stepPreselectedTypes: string[],
|
|
174
|
-
) => {
|
|
175
|
-
// Initialize selected types from data (parent component should have already initialized this)
|
|
176
|
-
if (
|
|
177
|
-
data.selectedComponentTypes &&
|
|
178
|
-
Array.isArray(data.selectedComponentTypes)
|
|
179
|
-
) {
|
|
180
|
-
// Filter out any types that are no longer available
|
|
181
|
-
const validSelectedTypes = data.selectedComponentTypes.filter((type) =>
|
|
182
|
-
uniqueTypes.includes(type),
|
|
183
|
-
);
|
|
184
|
-
setSelectedComponentTypes(validSelectedTypes);
|
|
185
|
-
} else {
|
|
186
|
-
// Fallback initialization if parent didn't handle it
|
|
187
|
-
const initialSelection =
|
|
188
|
-
stepPreselectedTypes.length > 0 ? stepPreselectedTypes : uniqueTypes;
|
|
189
|
-
setSelectedComponentTypes(initialSelection);
|
|
190
|
-
setData({
|
|
191
|
-
...data,
|
|
192
|
-
selectedComponentTypes: initialSelection,
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
// Extract component types and placeholders from wizard schema when available
|
|
143
|
+
// Initialize preselected types from step configuration
|
|
198
144
|
useEffect(() => {
|
|
199
|
-
if (
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
// Remove duplicates and sort alphabetically
|
|
211
|
-
const uniqueTypes = Array.from(
|
|
212
|
-
new Set(componentTypes),
|
|
213
|
-
).sort() as string[];
|
|
214
|
-
|
|
215
|
-
setAvailableComponentTypes(uniqueTypes);
|
|
216
|
-
|
|
217
|
-
// Parse preselected components from step if available
|
|
218
|
-
let stepPreselectedTypes: string[] = [];
|
|
219
|
-
if (step.fields["preselectedComponents"]) {
|
|
220
|
-
// Split by comma or newline and trim whitespace
|
|
221
|
-
stepPreselectedTypes = step.fields["preselectedComponents"]
|
|
222
|
-
.split(/[,\n\r]+/)
|
|
223
|
-
.map((type: string) => type.trim())
|
|
224
|
-
.filter((type: string) => type && uniqueTypes.includes(type)); // Only include valid types
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Set preselected types for UI differentiation
|
|
228
|
-
setPreselectedTypes(stepPreselectedTypes);
|
|
229
|
-
|
|
230
|
-
// Parse preselected placeholders from step if available
|
|
231
|
-
|
|
232
|
-
// Initialize component types and placeholders
|
|
233
|
-
initializeSelections(uniqueTypes, stepPreselectedTypes);
|
|
234
|
-
} catch (error) {
|
|
235
|
-
console.error("Error processing schema:", error);
|
|
236
|
-
}
|
|
145
|
+
if (availableComponentTypes && step.fields["preselectedComponents"]) {
|
|
146
|
+
// Parse preselected components from step if available
|
|
147
|
+
const stepPreselectedTypes = step.fields["preselectedComponents"]
|
|
148
|
+
.split(/[,\n\r]+/)
|
|
149
|
+
.map((type: string) => type.trim())
|
|
150
|
+
.filter(
|
|
151
|
+
(type: string) => type && availableComponentTypes.includes(type),
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
setPreselectedTypes(stepPreselectedTypes);
|
|
237
155
|
}
|
|
238
|
-
}, [
|
|
156
|
+
}, [availableComponentTypes, step]);
|
|
239
157
|
|
|
240
158
|
return (
|
|
241
159
|
<div className="space-y-4">
|
|
@@ -371,7 +289,7 @@ export function ComponentTypeSelector({
|
|
|
371
289
|
);
|
|
372
290
|
})
|
|
373
291
|
) : (
|
|
374
|
-
<div className="p-8 text-center text-gray-500">
|
|
292
|
+
<div className="p-8 text-center text-sm text-gray-500">
|
|
375
293
|
{searchFilter
|
|
376
294
|
? "No matching component types found"
|
|
377
295
|
: "No component types available"}
|
|
@@ -386,6 +304,7 @@ export function ComponentTypeSelector({
|
|
|
386
304
|
disabled={
|
|
387
305
|
selectedComponentTypes &&
|
|
388
306
|
Array.isArray(selectedComponentTypes) &&
|
|
307
|
+
availableComponentTypes &&
|
|
389
308
|
selectedComponentTypes.length === availableComponentTypes.length
|
|
390
309
|
}
|
|
391
310
|
className="flex-1 rounded bg-gray-200 px-2 py-1 text-xs text-gray-700 hover:bg-gray-300 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:text-gray-400"
|