@alpaca-editor/core 1.0.3942 → 1.0.3943

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 (308) hide show
  1. package/.prettierrc +3 -0
  2. package/build.css +3 -0
  3. package/components.json +21 -0
  4. package/dist/editor/ContentTree.d.ts +2 -1
  5. package/dist/editor/ContentTree.js +23 -21
  6. package/dist/editor/ContentTree.js.map +1 -1
  7. package/dist/editor/FieldActionsOverlay.js +0 -2
  8. package/dist/editor/FieldActionsOverlay.js.map +1 -1
  9. package/dist/editor/ScrollingContentTree.js +1 -1
  10. package/dist/editor/ScrollingContentTree.js.map +1 -1
  11. package/dist/editor/Titlebar.js +1 -1
  12. package/dist/editor/Titlebar.js.map +1 -1
  13. package/dist/editor/ai/GhostWriter.js +24 -3
  14. package/dist/editor/ai/GhostWriter.js.map +1 -1
  15. package/dist/editor/client/EditorClient.js +7 -7
  16. package/dist/editor/client/EditorClient.js.map +1 -1
  17. package/dist/editor/field-types/InternalLinkFieldEditor.js +60 -10
  18. package/dist/editor/field-types/InternalLinkFieldEditor.js.map +1 -1
  19. package/dist/editor/media-selector/MediaFolderBrowser.js +48 -1
  20. package/dist/editor/media-selector/MediaFolderBrowser.js.map +1 -1
  21. package/dist/editor/menubar/PageSelector.js +116 -65
  22. package/dist/editor/menubar/PageSelector.js.map +1 -1
  23. package/dist/editor/page-viewer/EditorForm.js +5 -2
  24. package/dist/editor/page-viewer/EditorForm.js.map +1 -1
  25. package/dist/editor/ui/ItemSearch.js +14 -8
  26. package/dist/editor/ui/ItemSearch.js.map +1 -1
  27. package/dist/editor/ui/PerfectTree.d.ts +4 -2
  28. package/dist/editor/ui/PerfectTree.js +78 -4
  29. package/dist/editor/ui/PerfectTree.js.map +1 -1
  30. package/dist/editor/ui/Splitter.js +1 -1
  31. package/dist/revision.d.ts +2 -2
  32. package/dist/revision.js +2 -2
  33. package/dist/styles.css +8 -2
  34. package/eslint.config.mjs +4 -0
  35. package/images/bg-shape-black.webp +0 -0
  36. package/images/wizard-bg.png +0 -0
  37. package/images/wizard-tour.png +0 -0
  38. package/images/wizard.png +0 -0
  39. package/package.json +2 -8
  40. package/src/client-components/api.ts +6 -0
  41. package/src/client-components/index.ts +19 -0
  42. package/src/components/ActionButton.tsx +50 -0
  43. package/src/components/Error.tsx +57 -0
  44. package/src/components/ui/CardConnector.tsx +56 -0
  45. package/src/components/ui/button.tsx +62 -0
  46. package/src/components/ui/card.tsx +372 -0
  47. package/src/components/ui/context-menu.tsx +250 -0
  48. package/src/config/config.tsx +917 -0
  49. package/src/config/types.ts +286 -0
  50. package/src/editor/ComponentInfo.tsx +90 -0
  51. package/src/editor/ConfirmationDialog.tsx +103 -0
  52. package/src/editor/ContentTree.tsx +733 -0
  53. package/src/editor/ContextMenu.tsx +230 -0
  54. package/src/editor/Editor.tsx +90 -0
  55. package/src/editor/EditorWarning.tsx +34 -0
  56. package/src/editor/EditorWarnings.tsx +33 -0
  57. package/src/editor/FieldActionsOverlay.tsx +296 -0
  58. package/src/editor/FieldEditorPopup.tsx +65 -0
  59. package/src/editor/FieldHistory.tsx +75 -0
  60. package/src/editor/FieldList.tsx +190 -0
  61. package/src/editor/FieldListField.tsx +391 -0
  62. package/src/editor/FieldListFieldWithFallbacks.tsx +217 -0
  63. package/src/editor/FloatingToolbar.tsx +163 -0
  64. package/src/editor/ImageEditor.tsx +128 -0
  65. package/src/editor/ItemInfo.tsx +90 -0
  66. package/src/editor/LinkEditorDialog.tsx +196 -0
  67. package/src/editor/MainLayout.tsx +95 -0
  68. package/src/editor/MobileLayout.tsx +68 -0
  69. package/src/editor/NewEditorClient.tsx +11 -0
  70. package/src/editor/PictureCropper.tsx +568 -0
  71. package/src/editor/PictureEditor.tsx +301 -0
  72. package/src/editor/PictureEditorDialog.tsx +381 -0
  73. package/src/editor/PublishDialog.ignore +74 -0
  74. package/src/editor/ScrollingContentTree.tsx +68 -0
  75. package/src/editor/Terminal.tsx +227 -0
  76. package/src/editor/Titlebar.tsx +104 -0
  77. package/src/editor/ai/AiPopup.tsx +59 -0
  78. package/src/editor/ai/AiResponseMessage.tsx +106 -0
  79. package/src/editor/ai/AiTerminal.tsx +503 -0
  80. package/src/editor/ai/AiToolCall.tsx +61 -0
  81. package/src/editor/ai/EditorAiTerminal.tsx +20 -0
  82. package/src/editor/ai/GhostWriter.tsx +480 -0
  83. package/src/editor/ai/aiPageModel.ts +108 -0
  84. package/src/editor/ai/editorAiContext.ts +18 -0
  85. package/src/editor/client/AboutDialog.tsx +44 -0
  86. package/src/editor/client/EditorClient.tsx +2241 -0
  87. package/src/editor/client/GenericDialog.tsx +50 -0
  88. package/src/editor/client/editContext.ts +416 -0
  89. package/src/editor/client/helpers.ts +44 -0
  90. package/src/editor/client/itemsRepository.ts +574 -0
  91. package/src/editor/client/operations.ts +768 -0
  92. package/src/editor/client/pageModelBuilder.ts +219 -0
  93. package/src/editor/commands/commands.ts +22 -0
  94. package/src/editor/commands/componentCommands.tsx +431 -0
  95. package/src/editor/commands/createVersionCommand.ts +33 -0
  96. package/src/editor/commands/deleteVersionCommand.ts +71 -0
  97. package/src/editor/commands/itemCommands.tsx +351 -0
  98. package/src/editor/commands/localizeItem/LocalizeItemDialog.tsx +201 -0
  99. package/src/editor/commands/localizeItem/LocalizeItemUtils.ts +27 -0
  100. package/src/editor/commands/undo.ts +39 -0
  101. package/src/editor/component-designer/ComponentDesigner.tsx +70 -0
  102. package/src/editor/component-designer/ComponentDesignerAiTerminal.tsx +11 -0
  103. package/src/editor/component-designer/ComponentDesignerMenu.tsx +91 -0
  104. package/src/editor/component-designer/ComponentEditor.tsx +97 -0
  105. package/src/editor/component-designer/ComponentRenderingCodeEditor.tsx +31 -0
  106. package/src/editor/component-designer/ComponentRenderingEditor.tsx +104 -0
  107. package/src/editor/component-designer/ComponentsDropdown.tsx +39 -0
  108. package/src/editor/component-designer/PlaceholdersEditor.tsx +179 -0
  109. package/src/editor/component-designer/RenderingsDropdown.tsx +36 -0
  110. package/src/editor/component-designer/TemplateEditor.tsx +236 -0
  111. package/src/editor/component-designer/aiContext.ts +23 -0
  112. package/src/editor/componentTreeHelper.tsx +116 -0
  113. package/src/editor/context-menu/CopyMoveMenu.tsx +103 -0
  114. package/src/editor/context-menu/InsertMenu.tsx +347 -0
  115. package/src/editor/control-center/About.tsx +342 -0
  116. package/src/editor/control-center/ControlCenterMenu.tsx +76 -0
  117. package/src/editor/control-center/IndexOverview.tsx +50 -0
  118. package/src/editor/control-center/IndexSettings.tsx +266 -0
  119. package/src/editor/control-center/Info.tsx +104 -0
  120. package/src/editor/control-center/QuotaInfo.tsx +301 -0
  121. package/src/editor/control-center/Status.tsx +113 -0
  122. package/src/editor/control-center/WebSocketMessages.tsx +155 -0
  123. package/src/editor/editor-warnings/ItemLocked.tsx +63 -0
  124. package/src/editor/editor-warnings/NoLanguageWriteAccess.tsx +22 -0
  125. package/src/editor/editor-warnings/NoWorkflowWriteAccess.tsx +23 -0
  126. package/src/editor/editor-warnings/NoWriteAccess.tsx +16 -0
  127. package/src/editor/editor-warnings/ValidationErrors.tsx +54 -0
  128. package/src/editor/field-types/AttachmentEditor.tsx +9 -0
  129. package/src/editor/field-types/CheckboxEditor.tsx +47 -0
  130. package/src/editor/field-types/DropLinkEditor.tsx +80 -0
  131. package/src/editor/field-types/DropListEditor.tsx +84 -0
  132. package/src/editor/field-types/ImageFieldEditor.tsx +65 -0
  133. package/src/editor/field-types/InternalLinkFieldEditor.tsx +188 -0
  134. package/src/editor/field-types/LinkFieldEditor.tsx +85 -0
  135. package/src/editor/field-types/MultiLineText.tsx +82 -0
  136. package/src/editor/field-types/PictureFieldEditor.tsx +121 -0
  137. package/src/editor/field-types/RawEditor.tsx +53 -0
  138. package/src/editor/field-types/ReactQuill.tsx +580 -0
  139. package/src/editor/field-types/RichTextEditor.tsx +22 -0
  140. package/src/editor/field-types/RichTextEditorComponent.tsx +127 -0
  141. package/src/editor/field-types/SingleLineText.tsx +174 -0
  142. package/src/editor/field-types/TreeListEditor.tsx +261 -0
  143. package/src/editor/fieldTypes.ts +140 -0
  144. package/src/editor/media-selector/AiImageSearch.tsx +185 -0
  145. package/src/editor/media-selector/AiImageSearchPrompt.tsx +94 -0
  146. package/src/editor/media-selector/MediaFolderBrowser.tsx +321 -0
  147. package/src/editor/media-selector/MediaSelector.tsx +42 -0
  148. package/src/editor/media-selector/Preview.tsx +14 -0
  149. package/src/editor/media-selector/Thumbnails.tsx +48 -0
  150. package/src/editor/media-selector/TreeSelector.tsx +292 -0
  151. package/src/editor/media-selector/UploadZone.tsx +137 -0
  152. package/src/editor/media-selector/index.ts +8 -0
  153. package/src/editor/menubar/ActionsMenu.tsx +94 -0
  154. package/src/editor/menubar/ActiveUsers.tsx +17 -0
  155. package/src/editor/menubar/ApproveAndPublish.tsx +18 -0
  156. package/src/editor/menubar/BrowseHistory.tsx +28 -0
  157. package/src/editor/menubar/ItemLanguageVersion.tsx +76 -0
  158. package/src/editor/menubar/LanguageSelector.tsx +226 -0
  159. package/src/editor/menubar/Menu.tsx +83 -0
  160. package/src/editor/menubar/NavButtons.tsx +74 -0
  161. package/src/editor/menubar/PageSelector.tsx +278 -0
  162. package/src/editor/menubar/PageViewerControls.tsx +120 -0
  163. package/src/editor/menubar/PreviewSecondaryControls.tsx +18 -0
  164. package/src/editor/menubar/SecondaryControls.tsx +45 -0
  165. package/src/editor/menubar/Separator.tsx +12 -0
  166. package/src/editor/menubar/SiteInfo.tsx +53 -0
  167. package/src/editor/menubar/User.tsx +27 -0
  168. package/src/editor/menubar/VersionSelector.tsx +142 -0
  169. package/src/editor/page-editor-chrome/CommentHighlighting.tsx +307 -0
  170. package/src/editor/page-editor-chrome/CommentHighlightings.tsx +35 -0
  171. package/src/editor/page-editor-chrome/FieldActionIndicator.tsx +59 -0
  172. package/src/editor/page-editor-chrome/FieldActionIndicators.tsx +23 -0
  173. package/src/editor/page-editor-chrome/FieldEditedIndicator.tsx +64 -0
  174. package/src/editor/page-editor-chrome/FieldEditedIndicators.tsx +35 -0
  175. package/src/editor/page-editor-chrome/FrameMenu.tsx +338 -0
  176. package/src/editor/page-editor-chrome/FrameMenus.tsx +48 -0
  177. package/src/editor/page-editor-chrome/InlineEditor.tsx +765 -0
  178. package/src/editor/page-editor-chrome/LockedFieldIndicator.tsx +61 -0
  179. package/src/editor/page-editor-chrome/NoLayout.tsx +36 -0
  180. package/src/editor/page-editor-chrome/PageEditorChrome.tsx +122 -0
  181. package/src/editor/page-editor-chrome/PictureEditorOverlay.tsx +161 -0
  182. package/src/editor/page-editor-chrome/PlaceholderDropZone.tsx +169 -0
  183. package/src/editor/page-editor-chrome/PlaceholderDropZones.tsx +315 -0
  184. package/src/editor/page-editor-chrome/SuggestionHighlighting.tsx +300 -0
  185. package/src/editor/page-editor-chrome/SuggestionHighlightings.tsx +40 -0
  186. package/src/editor/page-editor-chrome/useInlineAICompletion.tsx +828 -0
  187. package/src/editor/page-viewer/DeviceToolbar.tsx +70 -0
  188. package/src/editor/page-viewer/EditorForm.tsx +262 -0
  189. package/src/editor/page-viewer/MiniMap.tsx +362 -0
  190. package/src/editor/page-viewer/PageViewer.tsx +169 -0
  191. package/src/editor/page-viewer/PageViewerFrame.tsx +1022 -0
  192. package/src/editor/page-viewer/pageModelSkeletonBuilder.ts +412 -0
  193. package/src/editor/page-viewer/pageViewContext.ts +186 -0
  194. package/src/editor/pageModel.ts +220 -0
  195. package/src/editor/picture-shared.tsx +53 -0
  196. package/src/editor/reviews/Comment.tsx +308 -0
  197. package/src/editor/reviews/Comments.tsx +125 -0
  198. package/src/editor/reviews/DiffView.tsx +109 -0
  199. package/src/editor/reviews/PreviewInfo.tsx +35 -0
  200. package/src/editor/reviews/Reviews.tsx +280 -0
  201. package/src/editor/reviews/SuggestedEdit.tsx +316 -0
  202. package/src/editor/reviews/reviewCommands.tsx +47 -0
  203. package/src/editor/reviews/useReviews.tsx +70 -0
  204. package/src/editor/services/aiService.ts +173 -0
  205. package/src/editor/services/componentDesignerService.ts +151 -0
  206. package/src/editor/services/contentService.ts +180 -0
  207. package/src/editor/services/editService.ts +488 -0
  208. package/src/editor/services/indexService.ts +24 -0
  209. package/src/editor/services/reviewsService.ts +53 -0
  210. package/src/editor/services/serviceHelper.ts +95 -0
  211. package/src/editor/services/suggestedEditsService.ts +39 -0
  212. package/src/editor/services/systemService.ts +5 -0
  213. package/src/editor/services/translationService.ts +21 -0
  214. package/src/editor/services-server/api.ts +150 -0
  215. package/src/editor/services-server/graphQL.ts +106 -0
  216. package/src/editor/sidebar/ComponentPalette.tsx +161 -0
  217. package/src/editor/sidebar/ComponentTree.tsx +549 -0
  218. package/src/editor/sidebar/Debug.tsx +111 -0
  219. package/src/editor/sidebar/DictionaryEditor.tsx +261 -0
  220. package/src/editor/sidebar/EditHistory.tsx +134 -0
  221. package/src/editor/sidebar/GraphQL.tsx +164 -0
  222. package/src/editor/sidebar/Insert.tsx +35 -0
  223. package/src/editor/sidebar/MainContentTree.tsx +102 -0
  224. package/src/editor/sidebar/Performance.tsx +53 -0
  225. package/src/editor/sidebar/Sessions.tsx +35 -0
  226. package/src/editor/sidebar/Sidebar.tsx +20 -0
  227. package/src/editor/sidebar/SidebarView.tsx +152 -0
  228. package/src/editor/sidebar/Translations.tsx +295 -0
  229. package/src/editor/sidebar/Validation.tsx +102 -0
  230. package/src/editor/sidebar/ViewSelector.tsx +60 -0
  231. package/src/editor/sidebar/Workbox.tsx +209 -0
  232. package/src/editor/ui/CenteredMessage.tsx +7 -0
  233. package/src/editor/ui/CopyMoveTargetSelectorDialog.tsx +81 -0
  234. package/src/editor/ui/CopyToClipboardButton.tsx +24 -0
  235. package/src/editor/ui/DialogButtons.tsx +11 -0
  236. package/src/editor/ui/Icons.tsx +709 -0
  237. package/src/editor/ui/ItemList.tsx +76 -0
  238. package/src/editor/ui/ItemNameDialogNew.tsx +118 -0
  239. package/src/editor/ui/ItemSearch.tsx +159 -0
  240. package/src/editor/ui/PerfectTree.tsx +676 -0
  241. package/src/editor/ui/Section.tsx +35 -0
  242. package/src/editor/ui/SimpleIconButton.tsx +54 -0
  243. package/src/editor/ui/SimpleMenu.tsx +40 -0
  244. package/src/editor/ui/SimpleTable.tsx +60 -0
  245. package/src/editor/ui/SimpleTabs.tsx +60 -0
  246. package/src/editor/ui/SimpleToolbar.tsx +7 -0
  247. package/src/editor/ui/Spinner.tsx +9 -0
  248. package/src/editor/ui/Splitter.tsx +420 -0
  249. package/src/editor/ui/StackedPanels.tsx +134 -0
  250. package/src/editor/ui/Toolbar.tsx +7 -0
  251. package/src/editor/utils/id-helper.ts +3 -0
  252. package/src/editor/utils/insertOptions.ts +69 -0
  253. package/src/editor/utils/itemutils.ts +29 -0
  254. package/src/editor/utils/useMemoDebug.ts +28 -0
  255. package/src/editor/utils.ts +486 -0
  256. package/src/editor/views/CompareView.tsx +245 -0
  257. package/src/editor/views/EditView.tsx +27 -0
  258. package/src/editor/views/ItemEditor.tsx +58 -0
  259. package/src/editor/views/MediaFolderEditView.tsx +66 -0
  260. package/src/editor/views/SingleEditView.tsx +57 -0
  261. package/src/fonts/Geist-Black.woff2 +0 -0
  262. package/src/fonts/Geist-Bold.woff2 +0 -0
  263. package/src/fonts/Geist-ExtraBold.woff2 +0 -0
  264. package/src/fonts/Geist-ExtraLight.woff2 +0 -0
  265. package/src/fonts/Geist-Light.woff2 +0 -0
  266. package/src/fonts/Geist-Medium.woff2 +0 -0
  267. package/src/fonts/Geist-Regular.woff2 +0 -0
  268. package/src/fonts/Geist-SemiBold.woff2 +0 -0
  269. package/src/fonts/Geist-Thin.woff2 +0 -0
  270. package/src/fonts/Geist[wght].woff2 +0 -0
  271. package/src/fonts/index.ts +10 -0
  272. package/src/index.ts +23 -0
  273. package/src/lib/safelist.tsx +16 -0
  274. package/src/lib/utils.ts +6 -0
  275. package/src/page-wizard/PageWizard.tsx +139 -0
  276. package/src/page-wizard/WizardBox.tsx +4 -0
  277. package/src/page-wizard/WizardBoxConnector.tsx +56 -0
  278. package/src/page-wizard/WizardSteps.tsx +458 -0
  279. package/src/page-wizard/service.ts +35 -0
  280. package/src/page-wizard/startPageWizardCommand.ts +26 -0
  281. package/src/page-wizard/steps/BuildPageStep.tsx +259 -0
  282. package/src/page-wizard/steps/CollectStep.tsx +296 -0
  283. package/src/page-wizard/steps/ComponentTypesSelector.tsx +454 -0
  284. package/src/page-wizard/steps/Components.tsx +193 -0
  285. package/src/page-wizard/steps/ContentStep.tsx +890 -0
  286. package/src/page-wizard/steps/EditButton.tsx +34 -0
  287. package/src/page-wizard/steps/FieldEditor.tsx +102 -0
  288. package/src/page-wizard/steps/Generate.tsx +60 -0
  289. package/src/page-wizard/steps/ImagesStep.tsx +382 -0
  290. package/src/page-wizard/steps/LayoutStep.tsx +227 -0
  291. package/src/page-wizard/steps/MetaDataStep.tsx +173 -0
  292. package/src/page-wizard/steps/SelectStep.tsx +281 -0
  293. package/src/page-wizard/steps/schema.ts +180 -0
  294. package/src/page-wizard/steps/usePageCreator.ts +325 -0
  295. package/src/page-wizard/usePageWizard.ts +79 -0
  296. package/src/revision.ts +2 -0
  297. package/src/splash-screen/NewPage.tsx +294 -0
  298. package/src/splash-screen/OpenPage.tsx +113 -0
  299. package/src/splash-screen/RecentPages.tsx +123 -0
  300. package/src/splash-screen/SectionHeadline.tsx +21 -0
  301. package/src/splash-screen/SplashScreen.tsx +195 -0
  302. package/src/tour/Tour.tsx +566 -0
  303. package/src/tour/default-tour.tsx +301 -0
  304. package/src/tour/preview-tour.tsx +128 -0
  305. package/src/types.ts +335 -0
  306. package/styles.css +765 -0
  307. package/tsconfig.build.json +31 -0
  308. package/tsconfig.json +14 -0
@@ -0,0 +1,180 @@
1
+ import {
2
+ WizardSchemaComponent,
3
+ PageSchema,
4
+ SchemaComponent,
5
+ WizardSchemaField,
6
+ } from "../PageWizard";
7
+ type WizardSchemaComponentAccumulator = {
8
+ name: string;
9
+ type: string;
10
+ fields: WizardSchemaField[];
11
+ validParentPlaceholders: Set<string>;
12
+ validChildComponentTypes: Set<string>;
13
+ allowedOnRoot: boolean;
14
+ };
15
+
16
+ export function convertPageSchemaToWizardComponents(
17
+ pageSchema: PageSchema,
18
+ whitelist: string[]
19
+ ): WizardSchemaComponent[] {
20
+ const componentMap = new Map<string, WizardSchemaComponentAccumulator>();
21
+
22
+ /**
23
+ * Recursively processes a SchemaComponent.
24
+ *
25
+ * @param component - The current SchemaComponent to process.
26
+ * @param parentPlaceholder - The name of the placeholder where the component appears.
27
+ * @param isRoot - True if the component is at the root level.
28
+ * @param parentAccumulator - The accumulator of the parent component (if the parent is allowed).
29
+ */
30
+ function processComponent(
31
+ component: SchemaComponent,
32
+ parentPlaceholder: string,
33
+ isRoot: boolean,
34
+ parentAccumulator?: WizardSchemaComponentAccumulator
35
+ ): void {
36
+ const isAllowed = whitelist.includes(component.type);
37
+ let currentAccumulator: WizardSchemaComponentAccumulator | undefined =
38
+ undefined;
39
+
40
+ if (isAllowed) {
41
+ // If a parent accumulator exists (and is allowed), record the child's type as a valid child type.
42
+ if (parentAccumulator) {
43
+ parentAccumulator.validChildComponentTypes.add(component.type);
44
+ }
45
+
46
+ if (componentMap.has(component.typeId)) {
47
+ currentAccumulator = componentMap.get(component.typeId)!;
48
+ currentAccumulator.validParentPlaceholders.add(parentPlaceholder);
49
+ // Mark as allowed on root if encountered at the root level in any instance.
50
+ if (isRoot) {
51
+ currentAccumulator.allowedOnRoot = true;
52
+ }
53
+ } else {
54
+ currentAccumulator = {
55
+ name: component.typeId, // using typeId as the wizard component name
56
+ type: component.type,
57
+ fields: component.fields.map((field) => ({
58
+ name: field.name,
59
+ type: field.type,
60
+ })),
61
+ validParentPlaceholders: new Set([parentPlaceholder]),
62
+ validChildComponentTypes: new Set<string>(),
63
+ allowedOnRoot: isRoot,
64
+ };
65
+ componentMap.set(component.typeId, currentAccumulator);
66
+ }
67
+ }
68
+ // Process child components regardless of whether the current component is allowed.
69
+ for (const placeholder of component.placeholders) {
70
+ for (const child of placeholder.components) {
71
+ processComponent(child, placeholder.name, false, currentAccumulator);
72
+ }
73
+ }
74
+ }
75
+
76
+ // Process each top-level component in the PageSchema.
77
+ for (const placeholder of pageSchema) {
78
+ for (const component of placeholder.components) {
79
+ processComponent(component, placeholder.name, true);
80
+ }
81
+ }
82
+
83
+ // Convert accumulators to final WizardSchemaComponent objects.
84
+ const wizardComponents: WizardSchemaComponent[] = [];
85
+ for (const acc of componentMap.values()) {
86
+ const wizardComponent: WizardSchemaComponent = {
87
+ type: acc.type,
88
+ fields: acc.fields,
89
+ allowedChildrenComponentTypes: Array.from(acc.validChildComponentTypes),
90
+ allowedOnRoot: acc.allowedOnRoot,
91
+ };
92
+ // Only include validParentPlaceholders if there is more than one.
93
+ if (acc.validParentPlaceholders.size > 1) {
94
+ wizardComponent.availableParentPlaceholders = Array.from(
95
+ acc.validParentPlaceholders
96
+ );
97
+ }
98
+ wizardComponents.push(wizardComponent);
99
+ }
100
+
101
+ return wizardComponents;
102
+ }
103
+
104
+ /**
105
+ * Finds a placeholder (by its name) where a child component of type `childComponentType`
106
+ * can be placed inside a parent of type `parentComponentType`. For a parentComponentType
107
+ * equal to "root" (case‑insensitive), the function searches among top‑level placeholders.
108
+ *
109
+ * @param schema - The PageSchema (an array of SchemaPlaceholders).
110
+ * @param parentComponentType - The type of the parent component, or "root" to indicate top‑level.
111
+ * @param childComponentType - The type of the child component to place.
112
+ * @returns The name of a valid placeholder or undefined if none is found.
113
+ */
114
+ export function getPlaceholder(
115
+ schema: PageSchema,
116
+ parentComponentType: string,
117
+ childComponentType: string
118
+ ): string | undefined {
119
+ // Check for the special case where we want to place at the root level.
120
+ if (parentComponentType.toLowerCase() === "root") {
121
+ // First, look for a top-level placeholder that already contains a component
122
+ // of the given childComponentType.
123
+ for (const topPlaceholder of schema) {
124
+ if (
125
+ topPlaceholder.components.some((c) => c.type === childComponentType)
126
+ ) {
127
+ return topPlaceholder.name;
128
+ }
129
+ }
130
+ // If not found, return the first top-level placeholder that is empty.
131
+ for (const topPlaceholder of schema) {
132
+ if (topPlaceholder.components.length === 0) {
133
+ return topPlaceholder.name;
134
+ }
135
+ }
136
+ return undefined;
137
+ }
138
+
139
+ // Recursive helper to search through nested SchemaComponents.
140
+ function searchComponents(components: SchemaComponent[]): string | undefined {
141
+ for (const component of components) {
142
+ // If this component matches the desired parent type, check its placeholders.
143
+ if (component.type === parentComponentType) {
144
+ // First, try to find a placeholder that already has a child of the desired type.
145
+ for (const placeholder of component.placeholders) {
146
+ if (
147
+ placeholder.components.some(
148
+ (child) => child.type === childComponentType
149
+ )
150
+ ) {
151
+ return placeholder.name;
152
+ }
153
+ }
154
+ // Otherwise, pick an empty placeholder.
155
+ for (const placeholder of component.placeholders) {
156
+ if (placeholder.components.length === 0) {
157
+ return placeholder.name;
158
+ }
159
+ }
160
+ }
161
+ // Recurse into any placeholders in the current component.
162
+ for (const placeholder of component.placeholders) {
163
+ const result = searchComponents(placeholder.components);
164
+ if (result) {
165
+ return result;
166
+ }
167
+ }
168
+ }
169
+ return undefined;
170
+ }
171
+
172
+ // Search through all top-level placeholders' components.
173
+ for (const topPlaceholder of schema) {
174
+ const result = searchComponents(topPlaceholder.components);
175
+ if (result) {
176
+ return result;
177
+ }
178
+ }
179
+ return undefined;
180
+ }
@@ -0,0 +1,325 @@
1
+ import { Dispatch, SetStateAction, useMemo } from "react";
2
+ import {
3
+ SchemaComponent,
4
+ Wizard,
5
+ WizardPageComponent,
6
+ WizardPageModel,
7
+ WizardField,
8
+ SchemaField,
9
+ } from "../PageWizard";
10
+ import { useEditContextRef } from "../../editor/client/editContext";
11
+ import { useEditContext } from "../../editor/client/editContext";
12
+ import { getComponentById } from "../../editor/componentTreeHelper";
13
+ import { getPlaceholder } from "./schema";
14
+ import { getItemDescriptor, normalizeGuid } from "../../editor/utils";
15
+ import { ItemDescriptor } from "../../editor/pageModel";
16
+ import { generateImage } from "../../editor/services/aiService";
17
+
18
+ export function usePageCreator(
19
+ pageItem: ItemDescriptor | undefined,
20
+ wizard: Wizard,
21
+ setPageModel: Dispatch<SetStateAction<WizardPageModel>>,
22
+ ) {
23
+ const editContext = useEditContext();
24
+ const editContextRef = useEditContextRef();
25
+
26
+ // Function to build a map of all components from wizard schema
27
+ const buildComponentTypeMap = () => {
28
+ const componentMap = new Map<string, string>();
29
+ const fieldsMap = new Map<string, SchemaField>();
30
+ const placeholderMap = new Map<string, string>();
31
+
32
+ const processComponentsRecursively = (components: SchemaComponent[]) => {
33
+ for (const component of components) {
34
+ // Store the mapping from component type to typeId
35
+ componentMap.set(component.type, component.typeId);
36
+ placeholderMap.set(component.typeId, component.type);
37
+
38
+ // Process nested components in placeholders
39
+ if (component.placeholders && component.placeholders.length > 0) {
40
+ for (const placeholder of component.placeholders) {
41
+ if (placeholder.components && placeholder.components.length > 0) {
42
+ processComponentsRecursively(placeholder.components);
43
+ }
44
+ }
45
+ }
46
+ if (component.fields && component.fields.length > 0) {
47
+ for (const field of component.fields) {
48
+ fieldsMap.set(component.typeId + "_" + field.name, field);
49
+ }
50
+ }
51
+ }
52
+ };
53
+
54
+ // Start processing from the root level of the schema
55
+ if (wizard.schema && wizard.schema.length > 0) {
56
+ for (const placeholder of wizard.schema) {
57
+ if (placeholder.components && placeholder.components.length > 0) {
58
+ processComponentsRecursively(placeholder.components);
59
+ }
60
+ }
61
+ }
62
+
63
+ return { componentMap, fieldsMap };
64
+ };
65
+
66
+ // Build the component type to typeId map
67
+ const mappings = useMemo(() => buildComponentTypeMap(), [wizard.schema]);
68
+
69
+ const createNewComponent = async (
70
+ component: WizardPageComponent,
71
+ parentComponentType: string,
72
+ index: number,
73
+ parentComponentId?: string,
74
+ ): Promise<ItemDescriptor | undefined> => {
75
+ if (!editContext) return undefined;
76
+ const { componentMap } = mappings;
77
+ // Get the typeId from the map using the component type
78
+ const typeId = componentMap.get(component.type) || component.type;
79
+
80
+ if (!typeId) return undefined;
81
+
82
+ // 1. Add the component to the placeholder
83
+ console.log(
84
+ `! Adding component ${component.type} (typeId: ${typeId}) to placeholder ${parentComponentId} at index ${index}. Name: ${component.name}`,
85
+ );
86
+
87
+ const placeholderKey =
88
+ component.placeholder ||
89
+ getPlaceholder(wizard.schema, parentComponentType, component.type);
90
+
91
+ const placeholderId = parentComponentId
92
+ ? placeholderKey + "_" + normalizeGuid(parentComponentId)
93
+ : placeholderKey;
94
+
95
+ if (!placeholderId) {
96
+ console.error("Placeholder ID not found", component);
97
+ return undefined;
98
+ }
99
+
100
+ const addComponentOp = await editContext.operations.addComponent(
101
+ typeId, // Use typeId instead of just type
102
+ placeholderId,
103
+ index,
104
+ getItemDescriptor(pageItem!),
105
+ );
106
+
107
+ if (!addComponentOp?.componentId) {
108
+ console.warn(
109
+ "Failed to add component",
110
+ component,
111
+ "Result Op:",
112
+ addComponentOp,
113
+ );
114
+ return undefined;
115
+ }
116
+
117
+ // Wait for the component to be created
118
+ const componentId = addComponentOp.componentId;
119
+ console.log("! Waiting for component to be created", componentId);
120
+
121
+ let createdComponent;
122
+ let attempts = 0;
123
+ const maxAttempts = 10;
124
+
125
+ while (!createdComponent && attempts < maxAttempts) {
126
+ if (editContextRef.current?.page) {
127
+ createdComponent = getComponentById(
128
+ componentId,
129
+ editContextRef.current?.page,
130
+ );
131
+ if (createdComponent) {
132
+ break;
133
+ }
134
+ }
135
+ if (createdComponent) break;
136
+
137
+ await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 100ms between attempts
138
+ console.log("! Waiting for component to be created", componentId);
139
+ attempts++;
140
+ }
141
+
142
+ if (!createdComponent) {
143
+ console.error(
144
+ "Timeout waiting for component to appear in page model",
145
+ componentId,
146
+ );
147
+ }
148
+
149
+ const componentDescriptor = {
150
+ ...addComponentOp.mainItem,
151
+ id: addComponentOp.componentId,
152
+ };
153
+
154
+ console.log("! Component created:", componentDescriptor);
155
+
156
+ return componentDescriptor;
157
+ };
158
+
159
+ const findComponent = (components: WizardPageComponent[], path: number[]) => {
160
+ const child = components[path[0]!];
161
+ if (!child) return null;
162
+ if (path.length === 1) return child;
163
+ return findComponent(child.children || [], path.slice(1));
164
+ };
165
+
166
+ // Function to recursively create components from the page model
167
+ const createComponentsRecursively = async (
168
+ components: WizardPageComponent[],
169
+ parentComponentType: string,
170
+ parentComponentId?: string,
171
+ parentPath?: number[],
172
+ ) => {
173
+ if (!editContext || !pageItem) return;
174
+
175
+ const { componentMap, fieldsMap } = mappings;
176
+
177
+ // Process each component in the array
178
+ for (let i = 0; i < components.length; i++) {
179
+ //console.log("Processing component", i);
180
+ const component = components[i];
181
+ const componentPath = [...(parentPath || []), i];
182
+
183
+ if (!component?.id) {
184
+ if (!component?.type || !component?.fields) {
185
+ continue;
186
+ }
187
+
188
+ const descriptor = await createNewComponent(
189
+ component,
190
+ parentComponentType,
191
+ i,
192
+ parentComponentId,
193
+ );
194
+ if (!descriptor) continue;
195
+ component.id = descriptor.id;
196
+ setPageModel((prev) => {
197
+ const component = findComponent(prev.components, componentPath);
198
+ if (component) {
199
+ component.id = descriptor.id;
200
+ }
201
+ return {
202
+ ...prev,
203
+ };
204
+ });
205
+ }
206
+
207
+ if (component.fields && component.fields.length > 0) {
208
+ const typeId = componentMap.get(component.type) || component.type;
209
+
210
+ // 2. Edit fields of the component
211
+ for (const field of component.fields) {
212
+ if (
213
+ !field.name ||
214
+ !field.value ||
215
+ field.value + field.type === field.writtenValue
216
+ ) {
217
+ continue;
218
+ }
219
+
220
+ const schemaField = fieldsMap.get(typeId + "_" + field.name);
221
+
222
+ if (!schemaField) {
223
+ console.warn(
224
+ "Field not found",
225
+ field,
226
+ typeId,
227
+ component.type,
228
+ componentMap,
229
+ );
230
+ continue;
231
+ }
232
+
233
+ const fieldDescriptor = {
234
+ fieldId: schemaField.id.toLowerCase().replace(/[{}]/g, ""),
235
+ item: {
236
+ id: component.id,
237
+ language: pageItem.language,
238
+ version: pageItem.version,
239
+ },
240
+ };
241
+
242
+ let rawValue = field.value;
243
+ let value = field.value as any;
244
+
245
+ // console.log("##Processing field: ", field, schemaField, rawValue);
246
+
247
+ if (
248
+ schemaField.type === "Picture" ||
249
+ schemaField.type === "picture"
250
+ ) {
251
+ console.log("##Processing picture field: ", field, schemaField);
252
+ if (rawValue.indexOf("[...]") >= 0) continue;
253
+
254
+ if (
255
+ rawValue.startsWith("generate:") ||
256
+ rawValue.startsWith("id:generate:")
257
+ ) {
258
+ console.log("##Generating image");
259
+ rawValue = rawValue.slice(9);
260
+ const image = await generateImage({
261
+ ...fieldDescriptor,
262
+ prompt: rawValue,
263
+ sessionId: editContext.sessionId,
264
+ pageItem: getItemDescriptor(pageItem),
265
+ });
266
+ } else {
267
+ if (rawValue.startsWith("id:")) {
268
+ console.log("##Processing image id");
269
+ const imageId = rawValue.slice(3);
270
+ if (imageId) {
271
+ value = {
272
+ Variants: [{ Name: "Landscape", MediaId: imageId }],
273
+ };
274
+ }
275
+
276
+ await editContext.operations.editField({
277
+ field: fieldDescriptor,
278
+ rawValue: JSON.stringify(value),
279
+ refresh: "none",
280
+ });
281
+ } else
282
+ console.log(
283
+ "##Do not know how to process picture value: ",
284
+ rawValue,
285
+ );
286
+ }
287
+ } else {
288
+ await editContext.operations.editField({
289
+ field: fieldDescriptor,
290
+ value: value,
291
+ rawValue: rawValue,
292
+ refresh: "none",
293
+ });
294
+ }
295
+
296
+ setPageModel((prev) => {
297
+ const component = findComponent(prev.components, componentPath);
298
+ if (component) {
299
+ const prevField: WizardField | undefined = component.fields.find(
300
+ (f: WizardField) => f.name === field.name,
301
+ );
302
+ if (prevField) {
303
+ prevField.writtenValue = field.value + field.type;
304
+ }
305
+ }
306
+ return {
307
+ ...prev,
308
+ };
309
+ });
310
+ }
311
+ }
312
+
313
+ // 3. Recursively process placeholders
314
+ if (component.children && component.children.length > 0) {
315
+ await createComponentsRecursively(
316
+ component.children,
317
+ component.type,
318
+ component.id,
319
+ componentPath,
320
+ );
321
+ }
322
+ }
323
+ };
324
+ return { createComponentsRecursively };
325
+ }
@@ -0,0 +1,79 @@
1
+ import React, { useMemo, useState, useRef } from "react";
2
+ import { Wizard, WizardData, WizardPageModel } from "./PageWizard";
3
+ import { ItemDescriptor } from "../editor/pageModel";
4
+
5
+ export const usePageWizard = () => {
6
+ const [wizard, setWizard] = useState<Wizard | undefined>(undefined);
7
+ const [parentItem, setParentItem] = useState<ItemDescriptor | undefined>(
8
+ undefined,
9
+ );
10
+
11
+ // Wizard step state that should persist across re-renders
12
+ const [currentStepIndex, setCurrentStepIndex] = useState(0);
13
+ const [data, setData] = useState<WizardData>({});
14
+ const [pageModel, setPageModel] = useState<WizardPageModel>({
15
+ components: [],
16
+ name: "",
17
+ metaDescription: "",
18
+ metaKeywords: "",
19
+ });
20
+ const [internalState, setInternalState] = useState<any>({});
21
+ const [stepCompleted, setStepCompleted] = useState(-1);
22
+ const [pageItem, setPageItem] = useState<ItemDescriptor>();
23
+ const beforeNextCallbackRef = useRef<(() => Promise<boolean>) | null>(null);
24
+
25
+ // Reset wizard step state when wizard changes
26
+ const setWizardWithReset = (
27
+ value: React.SetStateAction<Wizard | undefined>,
28
+ ) => {
29
+ const newWizard = typeof value === "function" ? value(wizard) : value;
30
+ if (newWizard !== wizard) {
31
+ setCurrentStepIndex(0);
32
+ setData({});
33
+ setPageModel({
34
+ components: [],
35
+ name: "",
36
+ metaDescription: "",
37
+ metaKeywords: "",
38
+ });
39
+ setInternalState({});
40
+ setStepCompleted(-1);
41
+ setPageItem(undefined);
42
+ beforeNextCallbackRef.current = null;
43
+ }
44
+ setWizard(newWizard);
45
+ };
46
+
47
+ return useMemo(
48
+ () => ({
49
+ wizard,
50
+ setWizard: setWizardWithReset,
51
+ parentItem,
52
+ setParentItem,
53
+ // Wizard step state
54
+ currentStepIndex,
55
+ setCurrentStepIndex,
56
+ data,
57
+ setData,
58
+ pageModel,
59
+ setPageModel,
60
+ internalState,
61
+ setInternalState,
62
+ stepCompleted,
63
+ setStepCompleted,
64
+ pageItem,
65
+ setPageItem,
66
+ beforeNextCallbackRef,
67
+ }),
68
+ [
69
+ wizard,
70
+ parentItem,
71
+ currentStepIndex,
72
+ data,
73
+ pageModel,
74
+ internalState,
75
+ stepCompleted,
76
+ pageItem,
77
+ ],
78
+ );
79
+ };
@@ -0,0 +1,2 @@
1
+ export const version = "1.0.3943";
2
+ export const buildDate = "2025-06-09 13:59:22";