@alpaca-editor/core 1.0.3992 → 1.0.3995

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 (190) hide show
  1. package/dist/components/ui/copy-button.d.ts +10 -0
  2. package/dist/components/ui/copy-button.js +33 -0
  3. package/dist/components/ui/copy-button.js.map +1 -0
  4. package/dist/components/ui/sonner.d.ts +3 -0
  5. package/dist/components/ui/sonner.js +14 -0
  6. package/dist/components/ui/sonner.js.map +1 -0
  7. package/dist/config/config.js +4 -16
  8. package/dist/config/config.js.map +1 -1
  9. package/dist/config/types.d.ts +6 -3
  10. package/dist/editor/ComponentInfo.js +2 -2
  11. package/dist/editor/ComponentInfo.js.map +1 -1
  12. package/dist/editor/ContentTree.d.ts +2 -1
  13. package/dist/editor/ContentTree.js +4 -8
  14. package/dist/editor/ContentTree.js.map +1 -1
  15. package/dist/editor/FieldListField.js +3 -10
  16. package/dist/editor/FieldListField.js.map +1 -1
  17. package/dist/editor/ItemInfo.js +3 -3
  18. package/dist/editor/ItemInfo.js.map +1 -1
  19. package/dist/editor/ai/Agents.d.ts +6 -0
  20. package/dist/editor/ai/Agents.js +48 -0
  21. package/dist/editor/ai/Agents.js.map +1 -0
  22. package/dist/editor/ai/AiTerminal.js +4 -2
  23. package/dist/editor/ai/AiTerminal.js.map +1 -1
  24. package/dist/editor/client/EditorClient.js +48 -91
  25. package/dist/editor/client/EditorClient.js.map +1 -1
  26. package/dist/editor/client/editContext.d.ts +3 -2
  27. package/dist/editor/client/editContext.js.map +1 -1
  28. package/dist/editor/commands/itemCommands.js +5 -24
  29. package/dist/editor/commands/itemCommands.js.map +1 -1
  30. package/dist/editor/component-designer/ComponentEditor.js +3 -5
  31. package/dist/editor/component-designer/ComponentEditor.js.map +1 -1
  32. package/dist/editor/field-types/InternalLinkFieldEditor.js +20 -25
  33. package/dist/editor/field-types/InternalLinkFieldEditor.js.map +1 -1
  34. package/dist/editor/field-types/RichTextEditor.d.ts +4 -3
  35. package/dist/editor/field-types/RichTextEditor.js +16 -3
  36. package/dist/editor/field-types/RichTextEditor.js.map +1 -1
  37. package/dist/editor/field-types/RichTextEditorComponent.d.ts +6 -5
  38. package/dist/editor/field-types/RichTextEditorComponent.js +59 -60
  39. package/dist/editor/field-types/RichTextEditorComponent.js.map +1 -1
  40. package/dist/editor/field-types/TreeListEditor.js +7 -5
  41. package/dist/editor/field-types/TreeListEditor.js.map +1 -1
  42. package/dist/editor/field-types/richtext/components/EditorDropdown.d.ts +11 -0
  43. package/dist/editor/field-types/richtext/components/EditorDropdown.js +83 -0
  44. package/dist/editor/field-types/richtext/components/EditorDropdown.js.map +1 -0
  45. package/dist/editor/field-types/richtext/components/ReactSlate.d.ts +5 -0
  46. package/dist/editor/field-types/richtext/components/ReactSlate.js +562 -0
  47. package/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -0
  48. package/dist/editor/field-types/richtext/components/ToolbarButton.d.ts +3 -0
  49. package/dist/editor/field-types/richtext/components/ToolbarButton.js +13 -0
  50. package/dist/editor/field-types/richtext/components/ToolbarButton.js.map +1 -0
  51. package/dist/editor/field-types/richtext/config/pluginFactory.d.ts +17 -0
  52. package/dist/editor/field-types/richtext/config/pluginFactory.js +14 -0
  53. package/dist/editor/field-types/richtext/config/pluginFactory.js.map +1 -0
  54. package/dist/editor/field-types/richtext/hooks/useProfileCache.d.ts +68 -0
  55. package/dist/editor/field-types/richtext/hooks/useProfileCache.js +208 -0
  56. package/dist/editor/field-types/richtext/hooks/useProfileCache.js.map +1 -0
  57. package/dist/editor/field-types/richtext/hooks/useRichTextProfile.d.ts +25 -0
  58. package/dist/editor/field-types/richtext/hooks/useRichTextProfile.js +64 -0
  59. package/dist/editor/field-types/richtext/hooks/useRichTextProfile.js.map +1 -0
  60. package/dist/editor/field-types/richtext/index.d.ts +5 -0
  61. package/dist/editor/field-types/richtext/index.js +6 -0
  62. package/dist/editor/field-types/richtext/index.js.map +1 -0
  63. package/dist/editor/field-types/richtext/types.d.ts +139 -0
  64. package/dist/editor/field-types/richtext/types.js +107 -0
  65. package/dist/editor/field-types/richtext/types.js.map +1 -0
  66. package/dist/editor/field-types/richtext/utils/conversion.d.ts +5 -0
  67. package/dist/editor/field-types/richtext/utils/conversion.js +539 -0
  68. package/dist/editor/field-types/richtext/utils/conversion.js.map +1 -0
  69. package/dist/editor/field-types/richtext/utils/plugins.d.ts +97 -0
  70. package/dist/editor/field-types/richtext/utils/plugins.js +272 -0
  71. package/dist/editor/field-types/richtext/utils/plugins.js.map +1 -0
  72. package/dist/editor/field-types/richtext/utils/profileMapper.d.ts +38 -0
  73. package/dist/editor/field-types/richtext/utils/profileMapper.js +366 -0
  74. package/dist/editor/field-types/richtext/utils/profileMapper.js.map +1 -0
  75. package/dist/editor/field-types/richtext/utils/profileServiceCache.d.ts +37 -0
  76. package/dist/editor/field-types/richtext/utils/profileServiceCache.js +117 -0
  77. package/dist/editor/field-types/richtext/utils/profileServiceCache.js.map +1 -0
  78. package/dist/editor/media-selector/AiImageSearch.js +2 -5
  79. package/dist/editor/media-selector/AiImageSearch.js.map +1 -1
  80. package/dist/editor/media-selector/MediaFolderBrowser.js +2 -5
  81. package/dist/editor/media-selector/MediaFolderBrowser.js.map +1 -1
  82. package/dist/editor/media-selector/TreeSelector.js +2 -5
  83. package/dist/editor/media-selector/TreeSelector.js.map +1 -1
  84. package/dist/editor/menubar/FavoritesControls.d.ts +8 -0
  85. package/dist/editor/menubar/FavoritesControls.js +124 -0
  86. package/dist/editor/menubar/FavoritesControls.js.map +1 -0
  87. package/dist/editor/menubar/ItemLanguageVersion.js +2 -1
  88. package/dist/editor/menubar/ItemLanguageVersion.js.map +1 -1
  89. package/dist/editor/menubar/PageSelector.js +3 -6
  90. package/dist/editor/menubar/PageSelector.js.map +1 -1
  91. package/dist/editor/reviews/reviewCommands.js +3 -8
  92. package/dist/editor/reviews/reviewCommands.js.map +1 -1
  93. package/dist/editor/services/contentService.d.ts +8 -0
  94. package/dist/editor/services/contentService.js +3 -0
  95. package/dist/editor/services/contentService.js.map +1 -1
  96. package/dist/editor/services/favouritesService.d.ts +33 -0
  97. package/dist/editor/services/favouritesService.js +22 -0
  98. package/dist/editor/services/favouritesService.js.map +1 -0
  99. package/dist/editor/sidebar/ComponentTree.js +7 -1
  100. package/dist/editor/sidebar/ComponentTree.js.map +1 -1
  101. package/dist/editor/sidebar/Debug.js +2 -2
  102. package/dist/editor/sidebar/Debug.js.map +1 -1
  103. package/dist/editor/sidebar/SEOInfo.js +4 -15
  104. package/dist/editor/sidebar/SEOInfo.js.map +1 -1
  105. package/dist/editor/ui/ItemSearch.js +2 -5
  106. package/dist/editor/ui/ItemSearch.js.map +1 -1
  107. package/dist/editor/ui/PerfectTree.d.ts +4 -2
  108. package/dist/editor/ui/PerfectTree.js +16 -7
  109. package/dist/editor/ui/PerfectTree.js.map +1 -1
  110. package/dist/editor/ui/Section.js +1 -1
  111. package/dist/editor/utils/itemutils.js +3 -1
  112. package/dist/editor/utils/itemutils.js.map +1 -1
  113. package/dist/editor/utils/keyboardNavigation.d.ts +32 -0
  114. package/dist/editor/utils/keyboardNavigation.js +156 -0
  115. package/dist/editor/utils/keyboardNavigation.js.map +1 -0
  116. package/dist/editor/views/ItemEditor.js +10 -3
  117. package/dist/editor/views/ItemEditor.js.map +1 -1
  118. package/dist/page-wizard/PageWizard.d.ts +2 -2
  119. package/dist/page-wizard/steps/ContentStep.js +7 -7
  120. package/dist/page-wizard/steps/ContentStep.js.map +1 -1
  121. package/dist/page-wizard/steps/schema.js +4 -2
  122. package/dist/page-wizard/steps/schema.js.map +1 -1
  123. package/dist/page-wizard/steps/usePageCreator.js +1 -1
  124. package/dist/page-wizard/steps/usePageCreator.js.map +1 -1
  125. package/dist/revision.d.ts +2 -2
  126. package/dist/revision.js +2 -2
  127. package/dist/splash-screen/NewPage.js +7 -10
  128. package/dist/splash-screen/NewPage.js.map +1 -1
  129. package/dist/styles.css +34 -5
  130. package/package.json +6 -1
  131. package/src/components/ui/copy-button.tsx +75 -0
  132. package/src/components/ui/sonner.tsx +25 -0
  133. package/src/config/config.tsx +5 -19
  134. package/src/config/types.ts +6 -3
  135. package/src/editor/ComponentInfo.tsx +5 -4
  136. package/src/editor/ContentTree.tsx +5 -6
  137. package/src/editor/FieldListField.tsx +4 -25
  138. package/src/editor/ItemInfo.tsx +5 -5
  139. package/src/editor/ai/Agents.tsx +125 -0
  140. package/src/editor/ai/AiTerminal.tsx +4 -0
  141. package/src/editor/client/EditorClient.tsx +58 -119
  142. package/src/editor/client/editContext.ts +3 -2
  143. package/src/editor/commands/itemCommands.tsx +10 -25
  144. package/src/editor/component-designer/ComponentEditor.tsx +8 -10
  145. package/src/editor/field-types/InternalLinkFieldEditor.tsx +73 -69
  146. package/src/editor/field-types/RichTextEditor.tsx +40 -3
  147. package/src/editor/field-types/RichTextEditorComponent.tsx +74 -77
  148. package/src/editor/field-types/TreeListEditor.tsx +7 -7
  149. package/src/editor/field-types/richtext/components/EditorDropdown.css +81 -0
  150. package/src/editor/field-types/richtext/components/EditorDropdown.tsx +165 -0
  151. package/src/editor/field-types/richtext/components/ReactSlate.css +161 -0
  152. package/src/editor/field-types/richtext/components/ReactSlate.tsx +801 -0
  153. package/src/editor/field-types/richtext/components/ToolbarButton.tsx +23 -0
  154. package/src/editor/field-types/richtext/config/pluginFactory.tsx +22 -0
  155. package/src/editor/field-types/richtext/hooks/useProfileCache.ts +270 -0
  156. package/src/editor/field-types/richtext/hooks/useRichTextProfile.ts +94 -0
  157. package/src/editor/field-types/richtext/index.ts +5 -0
  158. package/src/editor/field-types/richtext/types.ts +269 -0
  159. package/src/editor/field-types/richtext/utils/conversion.ts +589 -0
  160. package/src/editor/field-types/richtext/utils/plugins.ts +346 -0
  161. package/src/editor/field-types/richtext/utils/profileMapper.ts +424 -0
  162. package/src/editor/field-types/richtext/utils/profileServiceCache.ts +154 -0
  163. package/src/editor/media-selector/AiImageSearch.tsx +2 -5
  164. package/src/editor/media-selector/MediaFolderBrowser.tsx +2 -5
  165. package/src/editor/media-selector/TreeSelector.tsx +2 -5
  166. package/src/editor/menubar/FavoritesControls.tsx +250 -0
  167. package/src/editor/menubar/ItemLanguageVersion.tsx +3 -1
  168. package/src/editor/menubar/PageSelector.tsx +76 -75
  169. package/src/editor/reviews/reviewCommands.tsx +3 -8
  170. package/src/editor/services/contentService.ts +12 -0
  171. package/src/editor/services/favouritesService.ts +60 -0
  172. package/src/editor/sidebar/ComponentTree.tsx +12 -1
  173. package/src/editor/sidebar/Debug.tsx +4 -3
  174. package/src/editor/sidebar/SEOInfo.tsx +6 -16
  175. package/src/editor/ui/ItemSearch.tsx +2 -5
  176. package/src/editor/ui/PerfectTree.tsx +19 -6
  177. package/src/editor/ui/Section.tsx +1 -1
  178. package/src/editor/utils/{itemutils.ts → itemutils.tsx} +12 -12
  179. package/src/editor/utils/keyboardNavigation.ts +234 -0
  180. package/src/editor/views/ItemEditor.tsx +22 -1
  181. package/src/page-wizard/PageWizard.tsx +2 -2
  182. package/src/page-wizard/steps/ContentStep.tsx +7 -9
  183. package/src/page-wizard/steps/schema.ts +10 -7
  184. package/src/page-wizard/steps/usePageCreator.ts +1 -0
  185. package/src/revision.ts +2 -2
  186. package/src/splash-screen/NewPage.tsx +28 -24
  187. package/dist/editor/ui/CopyToClipboardButton.d.ts +0 -3
  188. package/dist/editor/ui/CopyToClipboardButton.js +0 -16
  189. package/dist/editor/ui/CopyToClipboardButton.js.map +0 -1
  190. package/src/editor/ui/CopyToClipboardButton.tsx +0 -24
@@ -81,6 +81,8 @@ export interface TreeProps<T = any> {
81
81
  enableKeyboardSearch?: boolean;
82
82
  /** Time in ms before search is cleared (default: 1500) */
83
83
  searchClearDelay?: number;
84
+ /** Whether to disable automatic selection when expanding nodes (even during search) */
85
+ disableAutoSelectOnExpand?: boolean;
84
86
  }
85
87
 
86
88
  /**
@@ -580,6 +582,7 @@ export const PerfectTree = <T,>({
580
582
  scrollToSelected = false,
581
583
  enableKeyboardSearch = false,
582
584
  searchClearDelay = 1500,
585
+ disableAutoSelectOnExpand = false,
583
586
  }: TreeProps<T>) => {
584
587
  const [searchTerm, setSearchTerm] = useState("");
585
588
  const [isFocused, setIsFocused] = useState(false);
@@ -590,18 +593,21 @@ export const PerfectTree = <T,>({
590
593
  (node: TreeNode<T>) => {
591
594
  const isCurrentlyExpanded = expandedKeys.includes(node.key);
592
595
 
593
- // If the node is being expanded (not collapsed), clear the search filter and select the node
596
+ // If the node is being expanded (not collapsed) and there's an active search filter
594
597
  if (!isCurrentlyExpanded) {
598
+ // Only select the node for quick navigation if there's an active search filter
599
+ // and auto-selection is not disabled
600
+ if (searchTerm && onSelect && !disableAutoSelectOnExpand) {
601
+ onSelect(node.key, {} as React.MouseEvent);
602
+ }
603
+
604
+ // Clear the search filter
595
605
  setSearchTerm("");
596
606
  // Clear any pending search timeout
597
607
  if (searchTimeoutRef.current) {
598
608
  clearTimeout(searchTimeoutRef.current);
599
609
  searchTimeoutRef.current = null;
600
610
  }
601
- // Select the node being expanded for quick navigation
602
- if (onSelect) {
603
- onSelect(node.key, {} as React.MouseEvent);
604
- }
605
611
  }
606
612
 
607
613
  if (onToggleExpand) {
@@ -613,7 +619,14 @@ export const PerfectTree = <T,>({
613
619
  onLazyLoad(node);
614
620
  }
615
621
  },
616
- [onToggleExpand, onLazyLoad, expandedKeys, onSelect],
622
+ [
623
+ onToggleExpand,
624
+ onLazyLoad,
625
+ expandedKeys,
626
+ onSelect,
627
+ searchTerm,
628
+ disableAutoSelectOnExpand,
629
+ ],
617
630
  );
618
631
 
619
632
  const handleSelect = useCallback(
@@ -18,7 +18,7 @@ export function Section({
18
18
  open
19
19
  ? "border-blue-500 bg-gray-600"
20
20
  : "border-gray-400 bg-gray-400 hover:border-gray-300 hover:bg-gray-500",
21
- "flex cursor-pointer items-center justify-between border-l-[8px] px-3 py-2 text-xs text-white transition-all duration-200 ease-in-out",
21
+ "flex cursor-pointer items-center justify-between border-l-[7px] px-3 py-2 text-xs text-white transition-all duration-200 ease-in-out",
22
22
  )}
23
23
  onClick={() => setOpen(!open)}
24
24
  >
@@ -1,20 +1,21 @@
1
1
  import { getCreateAndSwitchToNewVersionCommand } from "../commands/createVersionCommand";
2
2
  import { Language } from "../pageModel";
3
3
  import { EditContextType } from "../client/editContext";
4
+ import { TriangleAlert } from "lucide-react";
4
5
 
5
6
  export const confirmCreateVersion = (
6
7
  editContext: EditContextType,
7
- language: Language
8
+ language: Language,
8
9
  ) => {
9
- editContext.confirm({
10
- message:
11
- "This page has no version in language " +
12
- language.name +
13
- " (" +
14
- language.languageCode +
15
- "). Do you want to create a new version?",
16
- header: "Create Language Version?",
17
- icon: "pi pi-exclamation-triangle",
10
+ editContext.confirm({
11
+ message:
12
+ "This page has no version in language " +
13
+ language.name +
14
+ " (" +
15
+ language.languageCode +
16
+ "). Do you want to create a new version?",
17
+ header: "Create Language Version?",
18
+ icon: <TriangleAlert strokeWidth={1} className="h-4 w-4" />,
18
19
  acceptLabel: "Yes, create version",
19
20
  rejectLabel: "No",
20
21
  accept: async () => {
@@ -23,7 +24,6 @@ export const confirmCreateVersion = (
23
24
  language: language.languageCode,
24
25
  }),
25
26
  });
26
- },
27
27
  },
28
- );
28
+ });
29
29
  };
@@ -0,0 +1,234 @@
1
+ import { EditContextType } from "../client/editContext";
2
+ import { EditorConfiguration } from "../../config/types";
3
+ import { ItemDescriptor, FullItem } from "../pageModel";
4
+ import { HistoryEntry } from "../../types";
5
+ import { useDebouncedCallback } from "use-debounce";
6
+ import { useCallback } from "react";
7
+
8
+ export interface KeyboardNavigationDependencies {
9
+ editContextRef: React.MutableRefObject<EditContextType | undefined>;
10
+ operations: any;
11
+ pageViewContext: any;
12
+ configuration: EditorConfiguration;
13
+ contentEditorItem: FullItem | undefined;
14
+ browseHistory: HistoryEntry[];
15
+ loadItem: (
16
+ itemToLoad: ItemDescriptor | string,
17
+ options?: { addToBrowseHistory?: boolean; skipViewChange?: boolean },
18
+ ) => Promise<FullItem | undefined>;
19
+ showInfoToast: (props: { summary?: string; details?: string }) => void;
20
+ showErrorToast: (props: { summary?: string; details?: string }) => void;
21
+ executeCommand: (params: {
22
+ command: any;
23
+ data?: any;
24
+ event?: React.SyntheticEvent;
25
+ }) => Promise<any>;
26
+ }
27
+
28
+ export function useKeyboardNavigation(deps: KeyboardNavigationDependencies) {
29
+ const {
30
+ editContextRef,
31
+ operations,
32
+ pageViewContext,
33
+ configuration,
34
+ contentEditorItem,
35
+ browseHistory,
36
+ loadItem,
37
+ showInfoToast,
38
+ executeCommand,
39
+ } = deps;
40
+
41
+ const handleKeyDownDebounced = useDebouncedCallback(
42
+ async (event: KeyboardEvent) => {
43
+ if (!event.key) return;
44
+
45
+ if (event.ctrlKey && event.key === "z") {
46
+ await operations.undo();
47
+ }
48
+ if (event.ctrlKey && event.key === "y") {
49
+ await operations.redo();
50
+ }
51
+ if (event.ctrlKey && event.key === "F11") {
52
+ event.preventDefault();
53
+ pageViewContext.setFullscreen(false);
54
+ }
55
+
56
+ // History Navigation (Alt + Arrow keys, Alt + Shift + Arrow keys for favorites only)
57
+ if (
58
+ event.altKey &&
59
+ (event.key === "ArrowLeft" || event.key === "ArrowRight")
60
+ ) {
61
+ event.preventDefault();
62
+ const currentItem = contentEditorItem;
63
+ if (!currentItem) return;
64
+
65
+ let historyToNavigate = browseHistory;
66
+
67
+ // If Shift is also pressed, filter history to only include favorites
68
+ if (event.shiftKey) {
69
+ if (editContextRef.current?.favorites) {
70
+ const favoriteIds = new Set(
71
+ editContextRef.current.favorites.map(
72
+ (fav: any) => `${fav.itemId}:${fav.language}`,
73
+ ),
74
+ );
75
+
76
+ historyToNavigate = browseHistory.filter((historyItem) =>
77
+ favoriteIds.has(`${historyItem.id}:${historyItem.language}`),
78
+ );
79
+
80
+ if (historyToNavigate.length === 0) {
81
+ showInfoToast({
82
+ summary: "Navigation",
83
+ details: "No favorite items found in browse history",
84
+ });
85
+ return;
86
+ }
87
+ } else {
88
+ showInfoToast({
89
+ summary: "Navigation",
90
+ details: "Favorites not loaded yet",
91
+ });
92
+ return;
93
+ }
94
+ }
95
+
96
+ const currentIndex = historyToNavigate.findIndex(
97
+ (x) => x.id === currentItem.id && x.language === currentItem.language,
98
+ );
99
+
100
+ if (
101
+ event.key === "ArrowLeft" &&
102
+ currentIndex < historyToNavigate.length - 1
103
+ ) {
104
+ // Go forward in history
105
+ const historyItem = historyToNavigate[currentIndex + 1];
106
+ if (historyItem) {
107
+ loadItem(
108
+ {
109
+ id: historyItem.id,
110
+ language: historyItem.language,
111
+ version: historyItem.version || 0,
112
+ },
113
+ { addToBrowseHistory: false },
114
+ );
115
+ }
116
+ } else if (event.key === "ArrowRight" && currentIndex > 0) {
117
+ // Go back in history
118
+ const historyItem = historyToNavigate[currentIndex - 1];
119
+ if (historyItem) {
120
+ loadItem(
121
+ {
122
+ id: historyItem.id,
123
+ language: historyItem.language,
124
+ version: historyItem.version || 0,
125
+ },
126
+ { addToBrowseHistory: false },
127
+ );
128
+ }
129
+ }
130
+ return;
131
+ }
132
+
133
+ // Quick access to favorites (Ctrl + 1-9)
134
+ if (event.altKey && /^[1-9]$/.test(event.key)) {
135
+ event.preventDefault();
136
+ const index = parseInt(event.key) - 1;
137
+
138
+ // Use favorites from editContext
139
+ if (editContextRef.current?.favorites) {
140
+ const favorites = editContextRef.current.favorites;
141
+ if (favorites[index]) {
142
+ const favorite = favorites[index];
143
+ loadItem({
144
+ id: favorite.itemId,
145
+ language: favorite.language,
146
+ version: 0,
147
+ });
148
+ } else {
149
+ showInfoToast({
150
+ summary: "Favorites",
151
+ details: `No favorite item at position ${event.key}`,
152
+ });
153
+ }
154
+ } else {
155
+ showInfoToast({
156
+ summary: "Favorites",
157
+ details: "Favorites not loaded yet",
158
+ });
159
+ }
160
+ return;
161
+ }
162
+
163
+ // Command execution
164
+ const command = configuration.commands.allItemCommands.find(
165
+ (x) => x.keyBinding === event.key,
166
+ );
167
+
168
+ if (command) {
169
+ event.preventDefault();
170
+ const contentEditorItem = editContextRef.current?.contentEditorItem;
171
+ if (!contentEditorItem) return;
172
+
173
+ const items =
174
+ editContextRef.current?.selection?.map((x) => ({
175
+ id: x,
176
+ language: contentEditorItem.language,
177
+ version: 0,
178
+ })) || [];
179
+
180
+ if (!items.length) items.push(contentEditorItem.descriptor);
181
+
182
+ if (items.length > 0) {
183
+ const fullItems =
184
+ await editContextRef.current?.itemsRepository.getItems(items);
185
+ executeCommand({
186
+ command,
187
+ data: {
188
+ items: fullItems,
189
+ },
190
+ });
191
+ }
192
+ }
193
+ },
194
+ 50,
195
+ );
196
+
197
+ const handleKeyDown = useCallback(
198
+ async (event: KeyboardEvent) => {
199
+ if (event.key === "Insert") {
200
+ event.preventDefault();
201
+ event.stopPropagation();
202
+ editContextRef.current?.setInsertMode((x) => !x);
203
+ }
204
+
205
+ if (event.ctrlKey && event.key === "s") {
206
+ event.preventDefault();
207
+ event.stopPropagation();
208
+ return;
209
+ }
210
+
211
+ const target = event.target as HTMLElement;
212
+ const isTyping =
213
+ target instanceof HTMLInputElement ||
214
+ target instanceof HTMLTextAreaElement ||
215
+ target.isContentEditable;
216
+
217
+ if (
218
+ (event.ctrlKey && event.key === "z") ||
219
+ (event.ctrlKey && event.key === "y")
220
+ ) {
221
+ if (!isTyping) {
222
+ event.preventDefault();
223
+ event.stopPropagation();
224
+ handleKeyDownDebounced(event);
225
+ }
226
+ return;
227
+ }
228
+ handleKeyDownDebounced(event);
229
+ },
230
+ [handleKeyDownDebounced, editContextRef],
231
+ );
232
+
233
+ return { handleKeyDown };
234
+ }
@@ -5,6 +5,7 @@ import { ItemInfo } from "../ItemInfo";
5
5
  import { useEditContext } from "../client/editContext";
6
6
  import { PageViewContext } from "../page-viewer/pageViewContext";
7
7
  import { FullItem } from "../pageModel";
8
+ import { LanguageSelector } from "../menubar/LanguageSelector";
8
9
 
9
10
  export function ItemEditor({
10
11
  item,
@@ -43,7 +44,7 @@ export function ItemEditor({
43
44
  )}
44
45
 
45
46
  {editContext.itemVersions.length === 0 && (
46
- <div className="flex justify-center p-4">
47
+ <div className="flex flex-col items-center gap-4 p-4">
47
48
  <Button
48
49
  onClick={async () => {
49
50
  await editContext.operations.createVersion(item.descriptor);
@@ -51,6 +52,26 @@ export function ItemEditor({
51
52
  >
52
53
  Create First Version ({item.language})
53
54
  </Button>
55
+
56
+ {/* Show LanguageSelector if other languages are available */}
57
+ {editContext.itemLanguages.length > 1 && (
58
+ <div className="flex flex-col items-center gap-2">
59
+ <div className="text-sm text-gray-600">
60
+ Or select a different language:
61
+ </div>
62
+ <LanguageSelector
63
+ selectedLanguage={item.language}
64
+ onLanguageSelected={(language) => {
65
+ editContext.loadItem({
66
+ id: item.descriptor.id,
67
+ language: language.languageCode,
68
+ version: 0,
69
+ });
70
+ }}
71
+ showAllLanguagesSwitch={false}
72
+ />
73
+ </div>
74
+ )}
54
75
  </div>
55
76
  )}
56
77
  </div>
@@ -36,8 +36,8 @@ export type SchemaField = {
36
36
  export type WizardSchemaComponent = {
37
37
  type: string;
38
38
  fields: WizardSchemaField[];
39
- availableParentPlaceholders?: string[];
40
- allowedChildrenComponentTypes: string[];
39
+ validParentPlaceholders?: string[];
40
+ allowedChildrenComponentTypes?: string[];
41
41
  allowedOnRoot: boolean;
42
42
  };
43
43
 
@@ -472,7 +472,6 @@ export function ContentStep({
472
472
  return;
473
473
  }
474
474
  }
475
- console.log("Wiping components 2");
476
475
  editContextRef.current?.itemsRepository.clear();
477
476
  modifiedFieldsContext?.clear();
478
477
  setInternalState((prev: any) => ({
@@ -488,10 +487,9 @@ export function ContentStep({
488
487
 
489
488
  pageLoadedRef.current = false;
490
489
 
491
- console.log("Wiping components 3");
492
490
  editContextRef.current?.requestRefresh("immediate");
493
491
  await waitForPageLoaded();
494
- console.log("Wiping components 4");
492
+ console.log("Page loaded after wipe");
495
493
  }
496
494
 
497
495
  // Parse schema if it's a string
@@ -509,11 +507,11 @@ export function ContentStep({
509
507
  const localAbortController = new AbortController();
510
508
  setAbortController(localAbortController);
511
509
 
512
- // Get the existing page model
513
- const existingPageModel = await convertToAiPageModel(
514
- editContextRef.current?.page!,
515
- editContextRef.current!,
516
- );
510
+ // Get the existing page model; TODO make optional
511
+ const existingPageModel = undefined; // await convertToAiPageModel(
512
+ //editContextRef.current?.page!,
513
+ //editContextRef.current!,
514
+ //);
517
515
 
518
516
  console.log("Existing page model: ", existingPageModel);
519
517
 
@@ -525,7 +523,7 @@ export function ContentStep({
525
523
  Generate a descriptive name for each component including the topic.
526
524
  Only use component types that are in the page schema.
527
525
  Keep existing components with their ids. Leave id field empty for new components.
528
- Existing page model: ${JSON.stringify(existingPageModel)}
526
+ ${existingPageModel && `Existing page model: ${JSON.stringify(existingPageModel)}`}
529
527
  Fill empty fields of existing components before you insert new components.
530
528
  Component types: ${JSON.stringify(
531
529
  filteredSchema,
@@ -15,7 +15,7 @@ type WizardSchemaComponentAccumulator = {
15
15
 
16
16
  export function convertPageSchemaToWizardComponents(
17
17
  pageSchema: PageSchema,
18
- whitelist: string[]
18
+ whitelist: string[],
19
19
  ): WizardSchemaComponent[] {
20
20
  const componentMap = new Map<string, WizardSchemaComponentAccumulator>();
21
21
 
@@ -31,7 +31,7 @@ export function convertPageSchemaToWizardComponents(
31
31
  component: SchemaComponent,
32
32
  parentPlaceholder: string,
33
33
  isRoot: boolean,
34
- parentAccumulator?: WizardSchemaComponentAccumulator
34
+ parentAccumulator?: WizardSchemaComponentAccumulator,
35
35
  ): void {
36
36
  const isAllowed = whitelist.includes(component.type);
37
37
  let currentAccumulator: WizardSchemaComponentAccumulator | undefined =
@@ -86,13 +86,16 @@ export function convertPageSchemaToWizardComponents(
86
86
  const wizardComponent: WizardSchemaComponent = {
87
87
  type: acc.type,
88
88
  fields: acc.fields,
89
- allowedChildrenComponentTypes: Array.from(acc.validChildComponentTypes),
89
+ allowedChildrenComponentTypes:
90
+ acc.validChildComponentTypes.size > 0
91
+ ? Array.from(acc.validChildComponentTypes)
92
+ : undefined,
90
93
  allowedOnRoot: acc.allowedOnRoot,
91
94
  };
92
95
  // Only include validParentPlaceholders if there is more than one.
93
96
  if (acc.validParentPlaceholders.size > 1) {
94
- wizardComponent.availableParentPlaceholders = Array.from(
95
- acc.validParentPlaceholders
97
+ wizardComponent.validParentPlaceholders = Array.from(
98
+ acc.validParentPlaceholders,
96
99
  );
97
100
  }
98
101
  wizardComponents.push(wizardComponent);
@@ -114,7 +117,7 @@ export function convertPageSchemaToWizardComponents(
114
117
  export function getPlaceholder(
115
118
  schema: PageSchema,
116
119
  parentComponentType: string,
117
- childComponentType: string
120
+ childComponentType: string,
118
121
  ): string | undefined {
119
122
  // Check for the special case where we want to place at the root level.
120
123
  if (parentComponentType.toLowerCase() === "root") {
@@ -145,7 +148,7 @@ export function getPlaceholder(
145
148
  for (const placeholder of component.placeholders) {
146
149
  if (
147
150
  placeholder.components.some(
148
- (child) => child.type === childComponentType
151
+ (child) => child.type === childComponentType,
149
152
  )
150
153
  ) {
151
154
  return placeholder.name;
@@ -226,6 +226,7 @@ export function usePageCreator(
226
226
  typeId,
227
227
  component.type,
228
228
  componentMap,
229
+ fieldsMap,
229
230
  );
230
231
  continue;
231
232
  }
package/src/revision.ts CHANGED
@@ -1,2 +1,2 @@
1
- export const version = "1.0.3992";
2
- export const buildDate = "2025-07-10 01:51:42";
1
+ export const version = "1.0.3995";
2
+ export const buildDate = "2025-07-12 10:36:17";
@@ -24,6 +24,7 @@ import { CardConnector } from "../components/ui/CardConnector";
24
24
  import { Logo } from "../editor/ui/Icons";
25
25
  import { ActionButton } from "../components/ActionButton";
26
26
  import { FilePenLine, Palette } from "lucide-react";
27
+ import { toast } from "sonner";
27
28
 
28
29
  export function NewPage({ selectedItemId }: { selectedItemId?: string }) {
29
30
  const [selectedItem, setSelectedItem] = useState<ItemDescriptor | null>(null);
@@ -126,11 +127,7 @@ export function NewPage({ selectedItemId }: { selectedItemId?: string }) {
126
127
  editContext?.switchView("page-editor");
127
128
  if (result.data) editContext?.loadItem(result.data);
128
129
  } else {
129
- editContext!.showToast({
130
- severity: "error",
131
- summary: "Error",
132
- detail: "Failed to create item",
133
- });
130
+ toast.error("Failed to create item");
134
131
  }
135
132
  };
136
133
 
@@ -167,26 +164,33 @@ export function NewPage({ selectedItemId }: { selectedItemId?: string }) {
167
164
  Open Existing
168
165
  </ActionButton>
169
166
  </div>
170
- </div>
171
- <div className="flex flex-1 flex-col md:flex-row"> <div className={`tour-pick-location w-full md:w-1/2 ${
172
- selectedItem ? 'h-full md:h-full' : ''
173
- }`}><Card
167
+ </div>
168
+ <div className="flex flex-1 flex-col md:flex-row">
169
+ {" "}
170
+ <div
171
+ className={`tour-pick-location w-full md:w-1/2 ${
172
+ selectedItem ? "h-full md:h-full" : ""
173
+ }`}
174
+ >
175
+ <Card
174
176
  icon={<i className="pi pi-map-marker text-sm"></i>}
175
177
  title="Pick Location"
176
178
  description="Select where to create your new page"
177
179
  noPadding
178
- className={selectedItem ? 'h-full' : 'h-auto'}
180
+ className={selectedItem ? "h-full" : "h-auto"}
179
181
  >
180
- <div className={`px-4 pb-4 md:px-6 ${
181
- selectedItem ? 'h-full' : ''
182
- }`}>
183
- <div className={`relative ${
184
- selectedItem ? 'h-full' : ''
185
- }`}> <div className={`overflow-auto ${
186
- selectedItem
187
- ? 'absolute inset-0'
188
- : 'min-h-[300px] md:min-h-[400px]'
189
- }`}>
182
+ <div
183
+ className={`px-4 pb-4 md:px-6 ${selectedItem ? "h-full" : ""}`}
184
+ >
185
+ <div className={`relative ${selectedItem ? "h-full" : ""}`}>
186
+ {" "}
187
+ <div
188
+ className={`overflow-auto ${
189
+ selectedItem
190
+ ? "absolute inset-0"
191
+ : "min-h-[300px] md:min-h-[400px]"
192
+ }`}
193
+ >
190
194
  <ScrollingContentTree
191
195
  selectedItemId={selectedItem?.id || selectedItemId}
192
196
  onSelectionChange={(selection) => {
@@ -199,13 +203,11 @@ export function NewPage({ selectedItemId }: { selectedItemId?: string }) {
199
203
  </div>
200
204
  </Card>
201
205
  </div>
202
-
203
206
  {/* Card Connector - only visible when location is selected */}
204
207
  {selectedItem && <CardConnector />}
205
-
206
208
  {/* Second card - only visible when location is selected */}
207
209
  {selectedItem && (
208
- <div className="flex w-full flex-col h-auto md:w-1/2">
210
+ <div className="flex h-auto w-full flex-col md:w-1/2">
209
211
  <Card
210
212
  icon={<Palette className="h-4 w-4" />}
211
213
  title="Choose Template or Wizard"
@@ -228,7 +230,9 @@ export function NewPage({ selectedItemId }: { selectedItemId?: string }) {
228
230
  ? "bg-theme-secondary-light border-theme-secondary"
229
231
  : "bg-white",
230
232
  )}
231
- > {
233
+ >
234
+ {" "}
235
+ {
232
236
  <img
233
237
  src={getAbsoluteIconUrl(option.icon)}
234
238
  alt={option.name}
@@ -1,3 +0,0 @@
1
- export declare function CopyToClipboardButton({ text }: {
2
- text: string;
3
- }): import("react/jsx-runtime").JSX.Element;
@@ -1,16 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx } from "react/jsx-runtime";
3
- import { Copy } from "lucide-react";
4
- import { useEditContext } from "../client/editContext";
5
- export function CopyToClipboardButton({ text }) {
6
- const editContext = useEditContext();
7
- const handleCopyToClipboard = (text) => {
8
- navigator.clipboard.writeText(text);
9
- editContext.showToast({
10
- summary: "Copied to clipboard",
11
- severity: "success",
12
- });
13
- };
14
- return (_jsx("span", { className: "cursor-pointer", onClick: () => handleCopyToClipboard(text), children: _jsx(Copy, { size: 14, strokeWidth: 1 }) }));
15
- }
16
- //# sourceMappingURL=CopyToClipboardButton.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CopyToClipboardButton.js","sourceRoot":"","sources":["../../../src/editor/ui/CopyToClipboardButton.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,UAAU,qBAAqB,CAAC,EAAE,IAAI,EAAoB;IAC9D,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,MAAM,qBAAqB,GAAG,CAAC,IAAY,EAAE,EAAE;QAC7C,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACpC,WAAY,CAAC,SAAS,CAAC;YACrB,OAAO,EAAE,qBAAqB;YAC9B,QAAQ,EAAE,SAAS;SACpB,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,OAAO,CACL,eACE,SAAS,EAAC,gBAAgB,EAC1B,OAAO,EAAE,GAAG,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,YAE1C,KAAC,IAAI,IAAC,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,GAAI,GAC7B,CACR,CAAC;AACJ,CAAC"}
@@ -1,24 +0,0 @@
1
- "use client";
2
-
3
- import { Copy } from "lucide-react";
4
- import { useEditContext } from "../client/editContext";
5
-
6
- export function CopyToClipboardButton({ text }: { text: string }) {
7
- const editContext = useEditContext();
8
- const handleCopyToClipboard = (text: string) => {
9
- navigator.clipboard.writeText(text);
10
- editContext!.showToast({
11
- summary: "Copied to clipboard",
12
- severity: "success",
13
- });
14
- };
15
-
16
- return (
17
- <span
18
- className="cursor-pointer"
19
- onClick={() => handleCopyToClipboard(text)}
20
- >
21
- <Copy size={14} strokeWidth={1} />
22
- </span>
23
- );
24
- }