@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,230 @@
1
+ import { EditContextType } from "./client/editContext";
2
+ import { forwardRef, useImperativeHandle, useRef, useState } from "react";
3
+
4
+ import { FieldDescriptor } from "../types";
5
+ import { Component, FieldButton } from "./pageModel";
6
+ import {
7
+ ContextMenu,
8
+ ContextMenuContent,
9
+ ContextMenuItem,
10
+ ContextMenuSeparator,
11
+ ContextMenuTrigger,
12
+ } from "../components/ui/context-menu";
13
+ import { MenuItem } from "../config/types";
14
+
15
+ // export function getFieldContextMenu(
16
+ // field: Field,
17
+ // editContext: EditContextType,
18
+ // customButtons: EditButton[] = []
19
+ // ) {
20
+ // return (e: any) => {
21
+ // e.preventDefault();
22
+ // e.stopPropagation();
23
+ // const menuItems: MenuItem[] = getComponentMenuItems(
24
+ // editContext,
25
+ // getComponentById(field._editor!.descriptor.item.id, editContext.page!)!
26
+ // );
27
+
28
+ // if (customButtons.length) {
29
+ // if (menuItems.length)
30
+ // menuItems.push({
31
+ // separator: true,
32
+ // });
33
+
34
+ // customButtons.forEach((button) => {
35
+ // menuItems.push({
36
+ // label: button.label,
37
+ // command: (ev) => button.onClick(ev.originalEvent as any),
38
+ // icon: button.icon,
39
+ // });
40
+ // });
41
+ // }
42
+
43
+ // if (field._editor?.buttons?.length) {
44
+ // if (menuItems.length)
45
+ // menuItems.push({
46
+ // separator: true,
47
+ // });
48
+
49
+ // field._editor?.buttons.forEach((button: FieldButton) => {
50
+ // menuItems.push({
51
+ // label: button.label,
52
+ // command: () => {
53
+ // editContext!.triggerFieldAction(field._editor!.descriptor, button);
54
+ // },
55
+ // icon: button.icon ? "pi " + button.icon : undefined,
56
+ // });
57
+ // });
58
+ // }
59
+
60
+ // if (!e.ctrlKey && !e.shiftKey && !e.altKey && menuItems.length) {
61
+ // editContext.select([field._editor!.descriptor.item.id]);
62
+ // editContext!.setFocusedField(field._editor!.descriptor, false);
63
+ // editContext!.showContextMenu(e, menuItems);
64
+ // }
65
+ // };
66
+ // }
67
+
68
+ export async function showComponentContextMenu(
69
+ components: Component[],
70
+ editContext: EditContextType,
71
+ field?: FieldDescriptor,
72
+ fieldButtons?: FieldButton[],
73
+ onParameterizedAction?: (
74
+ field: FieldDescriptor,
75
+ action: FieldButton,
76
+ allFieldButtons: FieldButton[],
77
+ event: any,
78
+ ) => void,
79
+ ) {
80
+ const componentCommandMenuItems = await getComponentMenuItems(
81
+ editContext,
82
+ components,
83
+ );
84
+
85
+ const menuItems = componentCommandMenuItems;
86
+
87
+ if (!editContext.readonly && field && fieldButtons?.length) {
88
+ if (menuItems.length)
89
+ menuItems.push({
90
+ id: "separator",
91
+ separator: true,
92
+ });
93
+
94
+ fieldButtons.forEach((button) => {
95
+ menuItems.push({
96
+ id: button.id,
97
+ label: button.label,
98
+ command: async (event) => {
99
+ // Check if the button has parameters
100
+ if (button.parameters && button.parameters.length > 0) {
101
+ // If we have a parameterized action handler, use it
102
+ if (onParameterizedAction) {
103
+ onParameterizedAction(field, button, fieldButtons, event);
104
+ } else {
105
+ // Fallback: execute without parameters (might not work well)
106
+ editContext!.triggerFieldAction(field, button);
107
+ }
108
+ } else {
109
+ // For simple actions, execute directly
110
+ editContext!.triggerFieldAction(field, button);
111
+ }
112
+ },
113
+ icon: button.icon ? <img src={button.icon} width={16} /> : undefined,
114
+ });
115
+ });
116
+ }
117
+
118
+ return (e: any) => {
119
+ if (!e.shiftKey && !e.altKey) {
120
+ if (menuItems.length) {
121
+ // editContext.select([component.id]);
122
+ editContext!.showContextMenu(e, menuItems);
123
+ }
124
+
125
+ return true;
126
+ }
127
+ return false;
128
+ };
129
+ }
130
+
131
+ export interface EditContextMenuRef {
132
+ show: (event: any, menuItems: MenuItem[]) => void;
133
+ close: (event: any) => void;
134
+ }
135
+
136
+ interface EditContextMenuProps {}
137
+
138
+ export const EditContextMenu = forwardRef<
139
+ EditContextMenuRef,
140
+ EditContextMenuProps
141
+ >((props, ref) => {
142
+ const canvasRef = useRef<HTMLSpanElement>(null);
143
+
144
+ const [menuItems, setMenuItems] = useState<MenuItem[]>([]);
145
+ if (!props) return;
146
+ useImperativeHandle(ref, () => ({
147
+ show: (e: any, items: MenuItem[]) => {
148
+ if (!e.ctrlKey && !e.shiftKey && !e.altKey) {
149
+ setMenuItems(items);
150
+ e.preventDefault();
151
+ triggerRightClick(canvasRef.current!, {
152
+ position: { x: e.clientX, y: e.clientY },
153
+ });
154
+ }
155
+ },
156
+ close: (event: any) => {
157
+ // cm.current?.hide(event);
158
+ },
159
+ }));
160
+
161
+ const triggerRightClick = (
162
+ element: HTMLSpanElement,
163
+ { position }: { position: any },
164
+ ) => {
165
+ const event = new MouseEvent("contextmenu", {
166
+ bubbles: true,
167
+ cancelable: true,
168
+ clientX: position.x,
169
+ clientY: position.y,
170
+ });
171
+ element.dispatchEvent(event);
172
+ };
173
+
174
+ return (
175
+ <ContextMenu>
176
+ <ContextMenuTrigger>
177
+ <span id="contextmenu_canvas" ref={canvasRef}>
178
+ CM trigger
179
+ </span>
180
+ </ContextMenuTrigger>
181
+ <ContextMenuContent>
182
+ {menuItems.map((item, index) =>
183
+ item.separator ? (
184
+ <ContextMenuSeparator />
185
+ ) : (
186
+ <ContextMenuItem
187
+ key={index}
188
+ onClick={(e) => {
189
+ if (item.command) {
190
+ item.command(e);
191
+ }
192
+ // Close the context menu when an item is clicked
193
+ canvasRef.current?.dispatchEvent(
194
+ new KeyboardEvent("keydown", { key: "Escape" }),
195
+ );
196
+ }}
197
+ disabled={item.disabled}
198
+ className="cursor-pointer"
199
+ >
200
+ {item.icon}
201
+ {item.label}
202
+ </ContextMenuItem>
203
+ ),
204
+ )}
205
+ </ContextMenuContent>
206
+ </ContextMenu>
207
+ );
208
+ // return <ContextMenu model={menuItems} ref={cm} />;
209
+ });
210
+ async function getComponentMenuItems(
211
+ editContext: EditContextType,
212
+ components: Component[],
213
+ ): Promise<MenuItem[]> {
214
+ const componentCommands = await editContext.getComponentCommands(components);
215
+
216
+ const componentCommandMenuItems = componentCommands.map((x) => {
217
+ return {
218
+ id: x.id,
219
+ label: x.label,
220
+ icon: x.icon,
221
+ command: (ev: React.SyntheticEvent) =>
222
+ editContext.executeCommand({
223
+ command: x,
224
+ event: ev,
225
+ }),
226
+ disabled: editContext.isCommandDisabled({ command: x }),
227
+ };
228
+ });
229
+ return componentCommandMenuItems;
230
+ }
@@ -0,0 +1,90 @@
1
+ "use client";
2
+
3
+ import { EditorClient } from "./client/EditorClient";
4
+
5
+ import { ItemDescriptor } from "./pageModel";
6
+ import { EditorConfiguration } from "../config/types";
7
+ import { useEffect, useState } from "react";
8
+ import { SystemStatus, UserInfo } from "../types";
9
+
10
+ import { getUserInfo } from "./services/editService";
11
+ import { getSystemStatus } from "./services/systemService";
12
+ import uuid from "react-uuid";
13
+ import { getConfiguration } from "../config/config";
14
+
15
+ export function Editor({
16
+ configure,
17
+ className,
18
+ page,
19
+ }: {
20
+ configure: (props: {
21
+ configuration: EditorConfiguration;
22
+ user: UserInfo;
23
+ }) => EditorConfiguration;
24
+ className?: string;
25
+ page?: ItemDescriptor;
26
+ }) {
27
+ const [config, setConfig] = useState<EditorConfiguration>();
28
+ const [userInfo, setUserInfo] = useState<UserInfo>();
29
+ const [systemStatus, setSystemStatus] = useState<SystemStatus>();
30
+
31
+ const sessionId =
32
+ typeof window !== "undefined"
33
+ ? sessionStorage.getItem("sessionId") || uuid()
34
+ : uuid();
35
+
36
+ useEffect(() => {
37
+ // Get user info and system status
38
+ getUserInfo().then((userInfo) => {
39
+ if (!userInfo) {
40
+ window.location.href = "/sitecore/login";
41
+ return;
42
+ }
43
+ setUserInfo(userInfo);
44
+ });
45
+
46
+ getSystemStatus().then((status) => {
47
+ if (status.data) {
48
+ setSystemStatus(status.data);
49
+ }
50
+ });
51
+ }, []);
52
+
53
+ useEffect(() => {
54
+ if (!userInfo || !systemStatus) return;
55
+
56
+ const config = configure({
57
+ configuration: getConfiguration(),
58
+ user: userInfo,
59
+ });
60
+ setConfig(config);
61
+ }, [userInfo, systemStatus]);
62
+
63
+ if (!userInfo || !systemStatus) return null;
64
+
65
+ if (systemStatus.messages.some((m) => m.severity === "error")) {
66
+ return (
67
+ <div className="fixed inset-0 flex flex-col items-center justify-center gap-2 text-sm">
68
+ <h1 className="text-2xl">Please fix the following issues:</h1>
69
+ <div className="text-sm text-red-500">
70
+ {systemStatus.messages.map((m) => (
71
+ <div key={m.message}>{m.message}</div>
72
+ ))}
73
+ </div>
74
+ <p>Check the logs for more details.</p>
75
+ </div>
76
+ );
77
+ }
78
+
79
+ if (!config) return null;
80
+
81
+ return (
82
+ <EditorClient
83
+ configuration={config}
84
+ className={className}
85
+ item={page}
86
+ sessionId={sessionId}
87
+ userInfo={userInfo}
88
+ ></EditorClient>
89
+ );
90
+ }
@@ -0,0 +1,34 @@
1
+ import { classNames } from "primereact/utils";
2
+
3
+ export function EditorWarning({
4
+ title,
5
+ severity = "warning",
6
+ children,
7
+ }: {
8
+ title: string;
9
+ severity?: "info" | "error" | "warning";
10
+ children: React.ReactNode;
11
+ }) {
12
+ const background =
13
+ severity === "info"
14
+ ? "bg-blue-100"
15
+ : severity === "error"
16
+ ? "bg-red-100"
17
+ : "bg-yellow-100";
18
+ return (
19
+ <div
20
+ className={classNames(
21
+ background,
22
+ "text-sm text-gray-500 border-b border-yellow-300 flex gap-2 items-stretch"
23
+ )}
24
+ >
25
+ <div className="bg-yellow-200 px-4 flex items-center text-gray-900">
26
+ <span className="pi pi-exclamation-triangle text-2xl" />
27
+ </div>
28
+ <div className="p-2">
29
+ <div className="font-bold">{title}</div>
30
+ <div className="text-xs">{children}</div>
31
+ </div>
32
+ </div>
33
+ );
34
+ }
@@ -0,0 +1,33 @@
1
+ import React from "react";
2
+
3
+ import { EditContextType, useEditContext } from "./client/editContext";
4
+
5
+ import { FullItem } from "./pageModel";
6
+
7
+ export type EditorWarningProps = {
8
+ item: FullItem;
9
+ editContext: EditContextType;
10
+ };
11
+
12
+ export function EditorWarnings({ item }: { item?: FullItem }) {
13
+ var context = useEditContext();
14
+ if (!context || context.mode === "preview") return;
15
+
16
+ if (!item) {
17
+ item = context.page?.item;
18
+ }
19
+
20
+ if (!item) return;
21
+
22
+ return (
23
+ <div className="z-50 w-full">
24
+ {context.configuration.editorWarnings.map((x, i) =>
25
+ React.createElement(x, {
26
+ item,
27
+ key: "warning" + i,
28
+ editContext: context!,
29
+ }),
30
+ )}
31
+ </div>
32
+ );
33
+ }
@@ -0,0 +1,296 @@
1
+ import React, { useState, useRef, useEffect } from "react";
2
+ import { OverlayPanel } from "primereact/overlaypanel";
3
+ import { FieldButton, FieldButtonParameter } from "./pageModel";
4
+
5
+ interface FieldActionsOverlayProps {
6
+ generatorButtons?: FieldButton[];
7
+ onActionClick: (action: FieldButton) => void;
8
+ onParameterizedActionExecute: (
9
+ action: FieldButton,
10
+ parameters: Record<string, string>,
11
+ ) => void;
12
+ currentOverlay?: any;
13
+ fieldId: string;
14
+ setCurrentOverlay: (overlay: any) => void;
15
+ preSelectedAction?: FieldButton; // Auto-select this action when overlay opens
16
+ hideBackButton?: boolean; // Hide back button when directly selecting an action
17
+ }
18
+
19
+ const FieldActionsOverlay = React.forwardRef<
20
+ FieldActionsOverlayRef,
21
+ FieldActionsOverlayProps
22
+ >(
23
+ (
24
+ {
25
+ generatorButtons,
26
+ onActionClick,
27
+ onParameterizedActionExecute,
28
+ currentOverlay,
29
+ fieldId,
30
+ setCurrentOverlay,
31
+ preSelectedAction,
32
+ hideBackButton,
33
+ },
34
+ ref,
35
+ ) => {
36
+ const overlayRef = useRef<OverlayPanel>(null);
37
+ const [selectedParameterizedAction, setSelectedParameterizedAction] =
38
+ useState<FieldButton | null>(null);
39
+ const [parameterValues, setParameterValues] = useState<
40
+ Record<string, string>
41
+ >({});
42
+
43
+ const overlayId = fieldId + "_generators";
44
+
45
+ useEffect(() => {
46
+ if (currentOverlay !== overlayId) {
47
+ overlayRef.current?.hide();
48
+ resetParameterizedAction();
49
+ }
50
+ }, [currentOverlay, overlayId]);
51
+
52
+ // Auto-select preSelectedAction if provided (removed from useEffect)
53
+ // Now handled in the show function
54
+
55
+ function resetParameterizedAction(): void {
56
+ setSelectedParameterizedAction(null);
57
+ setParameterValues({});
58
+ }
59
+
60
+ function handleActionClick(action: FieldButton): void {
61
+ if (action.parameters && action.parameters.length > 0) {
62
+ setSelectedParameterizedAction(action);
63
+ // Initialize parameter values with defaults
64
+ const initialValues: Record<string, string> = {};
65
+ action.parameters.forEach((param) => {
66
+ initialValues[param.id] = param.defaultValue || "";
67
+ });
68
+ setParameterValues(initialValues);
69
+ } else {
70
+ onActionClick(action);
71
+ overlayRef.current?.hide();
72
+ }
73
+ }
74
+
75
+ function executeParameterizedAction(): void {
76
+ if (selectedParameterizedAction) {
77
+ onParameterizedActionExecute(
78
+ selectedParameterizedAction,
79
+ parameterValues,
80
+ );
81
+ resetParameterizedAction();
82
+ overlayRef.current?.hide();
83
+ }
84
+ }
85
+
86
+ function goBackToActionList(): void {
87
+ resetParameterizedAction();
88
+ }
89
+
90
+ function cancelParameterizedAction(): void {
91
+ resetParameterizedAction();
92
+ overlayRef.current?.hide();
93
+ }
94
+
95
+ function updateParameterValue(paramId: string, value: string): void {
96
+ setParameterValues((prev) => ({ ...prev, [paramId]: value }));
97
+ }
98
+
99
+ function areRequiredParametersFilled(): boolean {
100
+ if (!selectedParameterizedAction?.parameters) return true;
101
+
102
+ return selectedParameterizedAction.parameters.every((param) => {
103
+ if (!param.required) return true;
104
+ const value = parameterValues[param.id] || "";
105
+ return value.trim().length > 0;
106
+ });
107
+ }
108
+
109
+ function renderParameterInput(
110
+ param: FieldButtonParameter,
111
+ shouldAutoFocus: boolean = false,
112
+ ): React.ReactNode {
113
+ const value = parameterValues[param.id] || "";
114
+ const commonProps = {
115
+ value,
116
+ onChange: (
117
+ e: React.ChangeEvent<
118
+ HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
119
+ >,
120
+ ) => updateParameterValue(param.id, e.target.value),
121
+ onKeyDown: (e: React.KeyboardEvent) => {
122
+ if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
123
+ e.preventDefault();
124
+ if (areRequiredParametersFilled()) {
125
+ executeParameterizedAction();
126
+ }
127
+ } else if (e.key === "Escape") {
128
+ e.preventDefault();
129
+ goBackToActionList();
130
+ }
131
+ },
132
+ className: "w-full rounded border p-2 text-xs",
133
+ placeholder: param.placeholder || "",
134
+ autoFocus: shouldAutoFocus,
135
+ };
136
+
137
+ switch (param.type) {
138
+ case "textarea":
139
+ return (
140
+ <textarea
141
+ {...commonProps}
142
+ rows={param.rows || 3}
143
+ className={commonProps.className + " resize-none"}
144
+ />
145
+ );
146
+ case "number":
147
+ return <input {...commonProps} type="number" />;
148
+ case "select":
149
+ return (
150
+ <select {...commonProps}>
151
+ <option value="">
152
+ {param.placeholder || "Select an option..."}
153
+ </option>
154
+ {param.options?.map((option) => (
155
+ <option key={option.value} value={option.value}>
156
+ {option.label}
157
+ </option>
158
+ ))}
159
+ </select>
160
+ );
161
+ case "text":
162
+ default:
163
+ return <input {...commonProps} type="text" />;
164
+ }
165
+ }
166
+
167
+ function show(event: any, actionToSelect?: FieldButton): void {
168
+ // Set overlay state first, then show
169
+ setCurrentOverlay(overlayId);
170
+
171
+ // Check if this is a synthetic event (from context menu) or real event (from button click)
172
+ if (
173
+ event &&
174
+ event.isTrusted === false &&
175
+ event.target &&
176
+ event.target.style
177
+ ) {
178
+ // This is likely our synthetic event with a positioned target element
179
+ overlayRef.current?.toggle(event, event.target);
180
+ } else {
181
+ // This is a normal event, use standard positioning
182
+ overlayRef.current?.toggle(event);
183
+ }
184
+
185
+ // Use the passed actionToSelect or fall back to preSelectedAction prop
186
+ const actionToAutoSelect = actionToSelect || preSelectedAction;
187
+
188
+ // Auto-select the action after overlay is shown
189
+ if (
190
+ actionToAutoSelect &&
191
+ actionToAutoSelect.parameters &&
192
+ actionToAutoSelect.parameters.length > 0
193
+ ) {
194
+ // Use longer timeout to ensure overlay is stable
195
+ setTimeout(() => {
196
+ handleActionClick(actionToAutoSelect);
197
+ }, 50);
198
+ } else {
199
+ console.log(
200
+ "Not auto-selecting - actionToAutoSelect:",
201
+ actionToAutoSelect,
202
+ );
203
+ }
204
+ }
205
+
206
+ function hide(): void {
207
+ overlayRef.current?.hide();
208
+ }
209
+
210
+ React.useImperativeHandle(ref, () => ({
211
+ show,
212
+ hide,
213
+ }));
214
+
215
+ return (
216
+ <OverlayPanel ref={overlayRef} className="p-1">
217
+ {selectedParameterizedAction ? (
218
+ <div className="min-w-64 p-2">
219
+ <div className="mb-2">
220
+ <div className="mb-2 flex items-center">
221
+ {!hideBackButton && (
222
+ <button
223
+ className="mr-2 text-xs hover:text-gray-400"
224
+ onClick={goBackToActionList}
225
+ >
226
+ <i className="pi pi-arrow-left" />
227
+ </button>
228
+ )}
229
+ <span className="text-xs font-semibold">
230
+ {selectedParameterizedAction.label}
231
+ </span>
232
+ </div>
233
+ <div className="mb-3 text-xs text-gray-600">
234
+ {selectedParameterizedAction.description}
235
+ </div>
236
+
237
+ {selectedParameterizedAction.parameters?.map((param, index) => (
238
+ <div key={param.id} className="mb-3">
239
+ <label className="mb-1 block text-xs font-medium">
240
+ {param.label}
241
+ {param.required && (
242
+ <span className="ml-1 text-red-500">*</span>
243
+ )}
244
+ </label>
245
+ {renderParameterInput(param, index === 0)}
246
+ </div>
247
+ ))}
248
+
249
+ <div className="mt-1 text-xs text-gray-500">
250
+ Ctrl+Enter to execute, Esc to cancel
251
+ </div>
252
+ </div>
253
+ <div className="flex gap-2">
254
+ <button
255
+ className="rounded bg-blue-500 px-3 py-1 text-xs text-white hover:bg-blue-600 disabled:cursor-not-allowed disabled:opacity-50"
256
+ onClick={executeParameterizedAction}
257
+ disabled={!areRequiredParametersFilled()}
258
+ >
259
+ Execute
260
+ </button>
261
+ <button
262
+ className="rounded bg-gray-300 px-3 py-1 text-xs text-gray-700 hover:bg-gray-400"
263
+ onClick={cancelParameterizedAction}
264
+ >
265
+ Cancel
266
+ </button>
267
+ </div>
268
+ </div>
269
+ ) : (
270
+ <>
271
+ {generatorButtons?.map((x) => (
272
+ <button
273
+ key={x.id}
274
+ className="block p-1 text-xs hover:text-gray-400"
275
+ onClick={() => handleActionClick(x)}
276
+ >
277
+ {x.icon && <i className={x.icon + " mr-2 text-xs"} />}
278
+ {x.label}
279
+ </button>
280
+ ))}
281
+ </>
282
+ )}
283
+ </OverlayPanel>
284
+ );
285
+ },
286
+ );
287
+
288
+ // Export methods to be used by parent component
289
+ export interface FieldActionsOverlayRef {
290
+ show: (event: any, actionToSelect?: FieldButton) => void;
291
+ hide: () => void;
292
+ }
293
+
294
+ FieldActionsOverlay.displayName = "FieldActionsOverlay";
295
+
296
+ export { FieldActionsOverlay };