@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.
Files changed (171) hide show
  1. package/dist/client-components/index.d.ts +1 -0
  2. package/dist/client-components/index.js +1 -0
  3. package/dist/client-components/index.js.map +1 -1
  4. package/dist/components/ui/calendar.d.ts +7 -0
  5. package/dist/components/ui/calendar.js +62 -0
  6. package/dist/components/ui/calendar.js.map +1 -0
  7. package/dist/config/config.js +11 -0
  8. package/dist/config/config.js.map +1 -1
  9. package/dist/editor/ContentTree.d.ts +2 -1
  10. package/dist/editor/ContentTree.js +2 -2
  11. package/dist/editor/ContentTree.js.map +1 -1
  12. package/dist/editor/FieldList.js +37 -10
  13. package/dist/editor/FieldList.js.map +1 -1
  14. package/dist/editor/FieldListField.js +21 -10
  15. package/dist/editor/FieldListField.js.map +1 -1
  16. package/dist/editor/client/EditorClient.js +5 -3
  17. package/dist/editor/client/EditorClient.js.map +1 -1
  18. package/dist/editor/client/itemsRepository.js +57 -9
  19. package/dist/editor/client/itemsRepository.js.map +1 -1
  20. package/dist/editor/client/pageModelBuilder.js +1 -1
  21. package/dist/editor/client/pageModelBuilder.js.map +1 -1
  22. package/dist/editor/commands/itemCommands.js +1 -1
  23. package/dist/editor/commands/itemCommands.js.map +1 -1
  24. package/dist/editor/field-types/DateFieldEditor.d.ts +5 -0
  25. package/dist/editor/field-types/DateFieldEditor.js +93 -0
  26. package/dist/editor/field-types/DateFieldEditor.js.map +1 -0
  27. package/dist/editor/field-types/ImageFieldEditor.js +1 -1
  28. package/dist/editor/field-types/ImageFieldEditor.js.map +1 -1
  29. package/dist/editor/field-types/InternalLinkFieldEditor.js +29 -9
  30. package/dist/editor/field-types/InternalLinkFieldEditor.js.map +1 -1
  31. package/dist/editor/field-types/LinkFieldEditor.js +1 -1
  32. package/dist/editor/field-types/LinkFieldEditor.js.map +1 -1
  33. package/dist/editor/field-types/MultiLineText.js +3 -1
  34. package/dist/editor/field-types/MultiLineText.js.map +1 -1
  35. package/dist/editor/field-types/PictureFieldEditor.js +1 -1
  36. package/dist/editor/field-types/PictureFieldEditor.js.map +1 -1
  37. package/dist/editor/field-types/SingleLineText.js +3 -1
  38. package/dist/editor/field-types/SingleLineText.js.map +1 -1
  39. package/dist/editor/field-types/TreeListEditor.js +90 -17
  40. package/dist/editor/field-types/TreeListEditor.js.map +1 -1
  41. package/dist/editor/field-types/richtext/components/ReactSlate.d.ts +3 -3
  42. package/dist/editor/field-types/richtext/components/ReactSlate.js +195 -172
  43. package/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -1
  44. package/dist/editor/fieldTypes.d.ts +1 -1
  45. package/dist/editor/media-selector/AiImageSearch.js +2 -1
  46. package/dist/editor/media-selector/AiImageSearch.js.map +1 -1
  47. package/dist/editor/media-selector/AiImageSearchPrompt.js +2 -1
  48. package/dist/editor/media-selector/AiImageSearchPrompt.js.map +1 -1
  49. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +1 -1
  50. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
  51. package/dist/editor/page-viewer/DeviceToolbar.js +3 -2
  52. package/dist/editor/page-viewer/DeviceToolbar.js.map +1 -1
  53. package/dist/editor/page-viewer/MiniMap.js +6 -1
  54. package/dist/editor/page-viewer/MiniMap.js.map +1 -1
  55. package/dist/editor/services/aiService.d.ts +9 -1
  56. package/dist/editor/services/aiService.js.map +1 -1
  57. package/dist/editor/sidebar/Insert.js +1 -1
  58. package/dist/editor/sidebar/Insert.js.map +1 -1
  59. package/dist/editor/sidebar/MainContentTree.d.ts +1 -1
  60. package/dist/editor/sidebar/MainContentTree.js +19 -7
  61. package/dist/editor/sidebar/MainContentTree.js.map +1 -1
  62. package/dist/editor/ui/Icons.js +1 -1
  63. package/dist/editor/ui/Icons.js.map +1 -1
  64. package/dist/editor/ui/ItemNameDialogNew.js +14 -10
  65. package/dist/editor/ui/ItemNameDialogNew.js.map +1 -1
  66. package/dist/editor/ui/PerfectTree.d.ts +2 -0
  67. package/dist/editor/ui/PerfectTree.js +1 -1
  68. package/dist/editor/ui/PerfectTree.js.map +1 -1
  69. package/dist/editor/ui/Spinner.js +1 -1
  70. package/dist/editor/ui/Spinner.js.map +1 -1
  71. package/dist/editor/utils.d.ts +1 -0
  72. package/dist/editor/utils.js +3 -0
  73. package/dist/editor/utils.js.map +1 -1
  74. package/dist/editor/views/CompareView.js.map +1 -1
  75. package/dist/page-wizard/PageWizard.d.ts +5 -1
  76. package/dist/page-wizard/PageWizard.js.map +1 -1
  77. package/dist/page-wizard/WizardSteps.js +1 -0
  78. package/dist/page-wizard/WizardSteps.js.map +1 -1
  79. package/dist/page-wizard/steps/ComponentTypesSelector.d.ts +2 -1
  80. package/dist/page-wizard/steps/ComponentTypesSelector.js +27 -90
  81. package/dist/page-wizard/steps/ComponentTypesSelector.js.map +1 -1
  82. package/dist/page-wizard/steps/ContentStep.js +118 -27
  83. package/dist/page-wizard/steps/ContentStep.js.map +1 -1
  84. package/dist/page-wizard/steps/FindItemsStep.d.ts +2 -0
  85. package/dist/page-wizard/steps/FindItemsStep.js +293 -0
  86. package/dist/page-wizard/steps/FindItemsStep.js.map +1 -0
  87. package/dist/page-wizard/steps/ImagesStep.js +9 -1
  88. package/dist/page-wizard/steps/ImagesStep.js.map +1 -1
  89. package/dist/page-wizard/steps/LayoutStep.js +24 -14
  90. package/dist/page-wizard/steps/LayoutStep.js.map +1 -1
  91. package/dist/page-wizard/steps/MetaDataStep.js +21 -11
  92. package/dist/page-wizard/steps/MetaDataStep.js.map +1 -1
  93. package/dist/page-wizard/steps/SelectStep.js +38 -31
  94. package/dist/page-wizard/steps/SelectStep.js.map +1 -1
  95. package/dist/page-wizard/steps/StructureStep.d.ts +2 -0
  96. package/dist/page-wizard/steps/StructureStep.js +156 -0
  97. package/dist/page-wizard/steps/StructureStep.js.map +1 -0
  98. package/dist/page-wizard/steps/schema.js +4 -4
  99. package/dist/page-wizard/steps/schema.js.map +1 -1
  100. package/dist/page-wizard/steps/usePageCreator.d.ts +2 -1
  101. package/dist/page-wizard/steps/usePageCreator.js +62 -8
  102. package/dist/page-wizard/steps/usePageCreator.js.map +1 -1
  103. package/dist/page-wizard/usePageWizard.js +2 -0
  104. package/dist/page-wizard/usePageWizard.js.map +1 -1
  105. package/dist/page-wizard/utils/dataAccessor.d.ts +39 -0
  106. package/dist/page-wizard/utils/dataAccessor.js +222 -0
  107. package/dist/page-wizard/utils/dataAccessor.js.map +1 -0
  108. package/dist/revision.d.ts +2 -2
  109. package/dist/revision.js +2 -2
  110. package/dist/splash-screen/RecentPages.js +14 -3
  111. package/dist/splash-screen/RecentPages.js.map +1 -1
  112. package/dist/styles.css +180 -2
  113. package/package.json +3 -1
  114. package/src/client-components/index.ts +1 -3
  115. package/src/components/ui/calendar.tsx +175 -0
  116. package/src/config/config.tsx +11 -1
  117. package/src/editor/ContentTree.tsx +4 -1
  118. package/src/editor/FieldList.tsx +44 -18
  119. package/src/editor/FieldListField.tsx +98 -23
  120. package/src/editor/client/EditorClient.tsx +6 -3
  121. package/src/editor/client/itemsRepository.ts +74 -10
  122. package/src/editor/client/pageModelBuilder.ts +1 -1
  123. package/src/editor/commands/itemCommands.tsx +2 -3
  124. package/src/editor/field-types/DateFieldEditor.tsx +132 -0
  125. package/src/editor/field-types/ImageFieldEditor.tsx +1 -1
  126. package/src/editor/field-types/InternalLinkFieldEditor.tsx +99 -73
  127. package/src/editor/field-types/LinkFieldEditor.tsx +2 -2
  128. package/src/editor/field-types/MultiLineText.tsx +5 -1
  129. package/src/editor/field-types/PictureFieldEditor.tsx +1 -1
  130. package/src/editor/field-types/SingleLineText.tsx +5 -1
  131. package/src/editor/field-types/TreeListEditor.tsx +149 -56
  132. package/src/editor/field-types/richtext/components/ReactSlate.tsx +537 -446
  133. package/src/editor/fieldTypes.ts +1 -1
  134. package/src/editor/media-selector/AiImageSearch.tsx +2 -1
  135. package/src/editor/media-selector/AiImageSearchPrompt.tsx +2 -1
  136. package/src/editor/page-editor-chrome/PlaceholderDropZone.tsx +1 -1
  137. package/src/editor/page-viewer/DeviceToolbar.tsx +17 -5
  138. package/src/editor/page-viewer/MiniMap.tsx +7 -2
  139. package/src/editor/services/aiService.ts +10 -1
  140. package/src/editor/sidebar/Insert.tsx +1 -1
  141. package/src/editor/sidebar/MainContentTree.tsx +27 -14
  142. package/src/editor/ui/Icons.tsx +16 -5
  143. package/src/editor/ui/ItemNameDialogNew.tsx +42 -30
  144. package/src/editor/ui/PerfectTree.tsx +3 -1
  145. package/src/editor/ui/Spinner.tsx +3 -1
  146. package/src/editor/utils.ts +4 -0
  147. package/src/editor/views/CompareView.tsx +1 -1
  148. package/src/page-wizard/PageWizard.tsx +5 -1
  149. package/src/page-wizard/WizardSteps.tsx +1 -0
  150. package/src/page-wizard/steps/ComponentTypesSelector.tsx +34 -115
  151. package/src/page-wizard/steps/ContentStep.tsx +149 -34
  152. package/src/page-wizard/steps/FindItemsStep.tsx +546 -0
  153. package/src/page-wizard/steps/ImagesStep.tsx +13 -1
  154. package/src/page-wizard/steps/LayoutStep.tsx +27 -16
  155. package/src/page-wizard/steps/MetaDataStep.tsx +26 -13
  156. package/src/page-wizard/steps/SelectStep.tsx +61 -32
  157. package/src/page-wizard/steps/StructureStep.tsx +350 -0
  158. package/src/page-wizard/steps/schema.ts +4 -4
  159. package/src/page-wizard/steps/usePageCreator.ts +84 -9
  160. package/src/page-wizard/usePageWizard.ts +2 -0
  161. package/src/page-wizard/utils/dataAccessor.ts +275 -0
  162. package/src/revision.ts +2 -2
  163. package/src/splash-screen/RecentPages.tsx +22 -3
  164. package/dist/editor/ai/GhostWriter.d.ts +0 -1
  165. package/dist/editor/ai/GhostWriter.js +0 -347
  166. package/dist/editor/ai/GhostWriter.js.map +0 -1
  167. package/dist/editor/component-designer/ComponentDesignerAiTerminal.d.ts +0 -1
  168. package/dist/editor/component-designer/ComponentDesignerAiTerminal.js +0 -7
  169. package/dist/editor/component-designer/ComponentDesignerAiTerminal.js.map +0 -1
  170. /package/src/editor/ai/{GhostWriter.tsx → GhostWriter.tsx_} +0 -0
  171. /package/src/editor/component-designer/{ComponentDesignerAiTerminal.tsx → ComponentDesignerAiTerminal.tsx_} +0 -0
@@ -124,7 +124,7 @@ export type DateField = Field & {
124
124
  value: DateFieldValue;
125
125
  };
126
126
 
127
- export type DateFieldValue = Field & {
127
+ export type DateFieldValue = {
128
128
  date: string;
129
129
  };
130
130
 
@@ -70,7 +70,8 @@ export function AiImageSearch({
70
70
  );
71
71
 
72
72
  setLoadingPrompt(false);
73
- const newPrompt = result.responseText.replaceAll("\n", "");
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 newPrompt = result.responseText.replaceAll("\n", "");
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="flex justify-center w-full items-center bg-gray-100 p-1 z-1000 text-sm gap-2 border-b">
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
- icon={<RotateDeviceIcon className="w-4 h-4" />}
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="Rotate"
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<any> {
60
+ ): Promise<ExecutePromptResponse | null> {
52
61
  const context = createAiContext({ editContext });
53
62
 
54
63
  const response = await fetch(context.endpoint, {
@@ -16,7 +16,7 @@ export function Insert() {
16
16
  content: (
17
17
  <div className="relative flex-1">
18
18
  <div className="absolute inset-0 overflow-auto">
19
- <MainContentTree mode="insert" />
19
+ <MainContentTree mode="insert-component" />
20
20
  </div>
21
21
  </div>
22
22
  ),
@@ -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
- (x: ItemTreeNodeData) => {
26
- return (
27
- mode === "insert" &&
28
- insertOptions?.find(
29
- (insertOption: InsertOption) =>
30
- insertOption.typeId == x.templateId ||
31
- insertOption.compatibleTypeIds?.find(
32
- (compatibleTemplate) => compatibleTemplate == x.templateId,
33
- ) !== undefined,
34
- ) !== undefined
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">
@@ -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
- viewBox="0 0 24 24"
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 d="M21.323 8.616l-4.94-4.94a1.251 1.251 0 0 0-1.767 0l-10.94 10.94a1.251 1.251 0 0 0 0 1.768l4.94 4.94a1.25 1.25 0 0 0 1.768 0l10.94-10.94a1.251 1.251 0 0 0 0-1.768zM14 5.707L19.293 11 11.5 18.793 6.207 13.5zm-4.323 14.91a.25.25 0 0 1-.354 0l-1.47-1.47.5-.5-2-2-.5.5-1.47-1.47a.25.25 0 0 1 0-.354L5.5 14.207l5.293 5.293zm10.94-10.94l-.617.616L14.707 5l.616-.616a.25.25 0 0 1 .354 0l4.94 4.94a.25.25 0 0 1 0 .353zm1.394 6.265V18a3.003 3.003 0 0 1-3 3h-3.292l1.635 1.634-.707.707-2.848-2.847 2.848-2.848.707.707L15.707 20h3.304a2.002 2.002 0 0 0 2-2v-2.058zM4 9H3V7a3.003 3.003 0 0 1 3-3h3.293L7.646 2.354l.707-.707 2.848 2.847L8.354 7.34l-.707-.707L9.28 5H6a2.002 2.002 0 0 0-2 2z" />
403
- <path fill="none" d="M0 0h24v24H0z" />
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 { Dialog } from "primereact/dialog";
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
- visible={true}
85
- onHide={() => {
86
- props.onClose?.(null);
87
- }}
88
- onShow={() => {
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
- <div className="p-3">
96
- <div className="my-2 text-sm">
97
- {props.message || "Enter a name for the new item:"}
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
- <InputText
100
- ref={nameRef}
101
- value={name}
102
- className="w-full"
103
- onChange={(e) => setName(e.target.value)}
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}
@@ -4,6 +4,8 @@ export function Spinner({
4
4
  size?: "2xl" | "3xl" | "4xl" | "5xl";
5
5
  }) {
6
6
  return (
7
- <i className={`pi pi-cog pi-spin text-${size} text-theme-secondary/40`}></i>
7
+ <i
8
+ className={`pi pi-spin pi-spinner text-${size} text-theme-secondary/40`}
9
+ ></i>
8
10
  );
9
11
  }
@@ -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 { EditorMode, useEditContext } from "../client/editContext";
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 = SchemaPlaceholder[];
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
- setSelectedComponentTypes(availableComponentTypes);
42
- setData({
43
- ...data,
44
- selectedComponentTypes: availableComponentTypes,
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 = availableComponentTypes.filter((type) =>
90
- type.toLowerCase().includes(searchFilter.toLowerCase()),
91
- );
90
+ const filteredComponentTypes =
91
+ availableComponentTypes?.filter((type) =>
92
+ type.toLowerCase().includes(searchFilter.toLowerCase()),
93
+ ) || [];
92
94
 
93
- // Helper function to recursively extract component types
94
- const extractComponentTypes = (
95
+ // Helper function to extract placeholders from the schema
96
+ const extractPlaceholders = (
95
97
  items: PageSchema | SchemaComponent[],
96
98
  ): string[] => {
97
- if (!items || !Array.isArray(items)) return [];
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
- // Process components in placeholders recursively
108
- if ("placeholders" in item && Array.isArray(item.placeholders)) {
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 types;
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 selections based on data or preselected values
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 (schema) {
200
- try {
201
- // Parse schema if it's a string
202
- schema =
203
- typeof schema === "string"
204
- ? (JSON.parse(schema) as PageSchema)
205
- : schema;
206
-
207
- // Extract component types
208
- const componentTypes = extractComponentTypes(schema);
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
- }, [schema, step]);
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"