camox 0.0.0 → 0.1.2-alpha.2

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 (255) hide show
  1. package/LICENSE.md +110 -0
  2. package/dist/components/AuthGate.d.ts +7 -0
  3. package/dist/components/AuthGate.d.ts.map +1 -0
  4. package/dist/core/components/AddBlockControlBar.d.ts +9 -0
  5. package/dist/core/components/AddBlockControlBar.d.ts.map +1 -0
  6. package/dist/core/components/AddBlockControlBar.js +65 -0
  7. package/dist/core/components/lexical/InlineContentEditable.d.ts +7 -0
  8. package/dist/core/components/lexical/InlineContentEditable.d.ts.map +1 -0
  9. package/dist/core/components/lexical/InlineContentEditable.js +40 -0
  10. package/dist/core/components/lexical/InlineLexicalEditor.d.ts +12 -0
  11. package/dist/core/components/lexical/InlineLexicalEditor.d.ts.map +1 -0
  12. package/dist/core/components/lexical/InlineLexicalEditor.js +133 -0
  13. package/dist/core/components/lexical/InlineParagraphNode.d.ts +10 -0
  14. package/dist/core/components/lexical/InlineParagraphNode.d.ts.map +1 -0
  15. package/dist/core/components/lexical/InlineParagraphNode.js +34 -0
  16. package/dist/core/components/lexical/SelectionBroadcaster.d.ts +6 -0
  17. package/dist/core/components/lexical/SelectionBroadcaster.d.ts.map +1 -0
  18. package/dist/core/components/lexical/SelectionBroadcaster.js +62 -0
  19. package/dist/core/components/lexical/SidebarLexicalEditor.d.ts +9 -0
  20. package/dist/core/components/lexical/SidebarLexicalEditor.d.ts.map +1 -0
  21. package/dist/core/components/lexical/editorConfig.d.ts +4 -0
  22. package/dist/core/components/lexical/editorConfig.d.ts.map +1 -0
  23. package/dist/core/components/lexical/editorConfig.js +24 -0
  24. package/dist/core/createApp.d.ts +373 -0
  25. package/dist/core/createApp.d.ts.map +1 -0
  26. package/dist/core/createApp.js +40 -0
  27. package/dist/core/createBlock.d.ts +947 -0
  28. package/dist/core/createBlock.d.ts.map +1 -0
  29. package/dist/core/createBlock.js +873 -0
  30. package/dist/core/createLayout.d.ts +78 -0
  31. package/dist/core/createLayout.d.ts.map +1 -0
  32. package/dist/core/createLayout.js +73 -0
  33. package/dist/core/hooks/useFieldSelection.d.ts +11 -0
  34. package/dist/core/hooks/useFieldSelection.d.ts.map +1 -0
  35. package/dist/core/hooks/useFieldSelection.js +25 -0
  36. package/dist/core/hooks/useIsEditable.d.ts +2 -0
  37. package/dist/core/hooks/useIsEditable.d.ts.map +1 -0
  38. package/dist/core/hooks/useIsEditable.js +12 -0
  39. package/dist/core/hooks/useOverlayMessage.d.ts +10 -0
  40. package/dist/core/hooks/useOverlayMessage.d.ts.map +1 -0
  41. package/dist/core/hooks/useOverlayMessage.js +37 -0
  42. package/dist/core/lib/contentType.d.ts +165 -0
  43. package/dist/core/lib/contentType.d.ts.map +1 -0
  44. package/dist/core/lib/contentType.js +148 -0
  45. package/dist/core/lib/fieldTypes.d.ts +85 -0
  46. package/dist/core/lib/fieldTypes.d.ts.map +1 -0
  47. package/dist/core/lib/lexicalReact.d.ts +3 -0
  48. package/dist/core/lib/lexicalReact.d.ts.map +1 -0
  49. package/dist/core/lib/lexicalReact.js +24 -0
  50. package/dist/core/lib/lexicalState.d.ts +10 -0
  51. package/dist/core/lib/lexicalState.d.ts.map +1 -0
  52. package/dist/core/lib/lexicalState.js +38 -0
  53. package/dist/core/lib/modifierFormats.d.ts +9 -0
  54. package/dist/core/lib/modifierFormats.d.ts.map +1 -0
  55. package/dist/core/lib/modifierFormats.js +8 -0
  56. package/dist/core/lib/modifiers.d.ts +12 -0
  57. package/dist/core/lib/modifiers.d.ts.map +1 -0
  58. package/dist/core/lib/modifiers.js +27 -0
  59. package/dist/features/content/CamoxContent.d.ts +2 -0
  60. package/dist/features/content/CamoxContent.d.ts.map +1 -0
  61. package/dist/features/content/CamoxContent.js +100 -0
  62. package/dist/features/content/components/AssetCard.d.ts +10 -0
  63. package/dist/features/content/components/AssetCard.d.ts.map +1 -0
  64. package/dist/features/content/components/AssetCard.js +41 -0
  65. package/dist/features/content/components/AssetCardSkeleton.d.ts +2 -0
  66. package/dist/features/content/components/AssetCardSkeleton.d.ts.map +1 -0
  67. package/dist/features/content/components/AssetCardSkeleton.js +11 -0
  68. package/dist/features/content/components/ContentSidebar.d.ts +2 -0
  69. package/dist/features/content/components/ContentSidebar.d.ts.map +1 -0
  70. package/dist/features/content/components/ContentSidebar.js +15 -0
  71. package/dist/features/content/components/UploadDropZone.d.ts +9 -0
  72. package/dist/features/content/components/UploadDropZone.d.ts.map +1 -0
  73. package/dist/features/content/components/UploadDropZone.js +51 -0
  74. package/dist/features/content/components/UploadProgressDrawer.d.ts +11 -0
  75. package/dist/features/content/components/UploadProgressDrawer.d.ts.map +1 -0
  76. package/dist/features/content/components/UploadProgressDrawer.js +72 -0
  77. package/dist/features/preview/CamoxPreview.d.ts +124 -0
  78. package/dist/features/preview/CamoxPreview.d.ts.map +1 -0
  79. package/dist/features/preview/CamoxPreview.js +253 -0
  80. package/dist/features/preview/components/AddBlockSheet.d.ts +3 -0
  81. package/dist/features/preview/components/AddBlockSheet.d.ts.map +1 -0
  82. package/dist/features/preview/components/AddBlockSheet.js +121 -0
  83. package/dist/features/preview/components/AgentChatSheet.d.ts +3 -0
  84. package/dist/features/preview/components/AgentChatSheet.d.ts.map +1 -0
  85. package/dist/features/preview/components/AgentChatSheet.js +24 -0
  86. package/dist/features/preview/components/AssetFieldEditor.d.ts +18 -0
  87. package/dist/features/preview/components/AssetFieldEditor.d.ts.map +1 -0
  88. package/dist/features/preview/components/AssetFieldEditor.js +139 -0
  89. package/dist/features/preview/components/AssetLightbox.d.ts +9 -0
  90. package/dist/features/preview/components/AssetLightbox.d.ts.map +1 -0
  91. package/dist/features/preview/components/AssetLightbox.js +421 -0
  92. package/dist/features/preview/components/AssetPickerGrid.d.ts +11 -0
  93. package/dist/features/preview/components/AssetPickerGrid.d.ts.map +1 -0
  94. package/dist/features/preview/components/AssetPickerGrid.js +92 -0
  95. package/dist/features/preview/components/BlockActionsPopover.d.ts +15 -0
  96. package/dist/features/preview/components/BlockActionsPopover.d.ts.map +1 -0
  97. package/dist/features/preview/components/BlockActionsPopover.js +506 -0
  98. package/dist/features/preview/components/CreatePageSheet.d.ts +3 -0
  99. package/dist/features/preview/components/CreatePageSheet.d.ts.map +1 -0
  100. package/dist/features/preview/components/CreatePageSheet.js +159 -0
  101. package/dist/features/preview/components/DebouncedFieldEditor.d.ts +10 -0
  102. package/dist/features/preview/components/DebouncedFieldEditor.d.ts.map +1 -0
  103. package/dist/features/preview/components/DebouncedFieldEditor.js +51 -0
  104. package/dist/features/preview/components/EditPageSheet.d.ts +3 -0
  105. package/dist/features/preview/components/EditPageSheet.d.ts.map +1 -0
  106. package/dist/features/preview/components/EditPageSheet.js +352 -0
  107. package/dist/features/preview/components/ItemFieldsEditor.d.ts +29 -0
  108. package/dist/features/preview/components/ItemFieldsEditor.d.ts.map +1 -0
  109. package/dist/features/preview/components/ItemFieldsEditor.js +308 -0
  110. package/dist/features/preview/components/LinkFieldEditor.d.ts +8 -0
  111. package/dist/features/preview/components/LinkFieldEditor.d.ts.map +1 -0
  112. package/dist/features/preview/components/LinkFieldEditor.js +190 -0
  113. package/dist/features/preview/components/MultipleAssetFieldEditor.d.ts +10 -0
  114. package/dist/features/preview/components/MultipleAssetFieldEditor.d.ts.map +1 -0
  115. package/dist/features/preview/components/MultipleAssetFieldEditor.js +232 -0
  116. package/dist/features/preview/components/OverlayTracker.d.ts +6 -0
  117. package/dist/features/preview/components/OverlayTracker.d.ts.map +1 -0
  118. package/dist/features/preview/components/OverlayTracker.js +41 -0
  119. package/dist/features/preview/components/Overlays.d.ts +6 -0
  120. package/dist/features/preview/components/Overlays.d.ts.map +1 -0
  121. package/dist/features/preview/components/Overlays.js +58 -0
  122. package/dist/features/preview/components/PageContentSheet.d.ts +3 -0
  123. package/dist/features/preview/components/PageContentSheet.d.ts.map +1 -0
  124. package/dist/features/preview/components/PageContentSheet.js +492 -0
  125. package/dist/features/preview/components/PageLocationFieldset.d.ts +14 -0
  126. package/dist/features/preview/components/PageLocationFieldset.d.ts.map +1 -0
  127. package/dist/features/preview/components/PageLocationFieldset.js +77 -0
  128. package/dist/features/preview/components/PagePicker.d.ts +3 -0
  129. package/dist/features/preview/components/PagePicker.d.ts.map +1 -0
  130. package/dist/features/preview/components/PagePicker.js +185 -0
  131. package/dist/features/preview/components/PageTree.d.ts +3 -0
  132. package/dist/features/preview/components/PageTree.d.ts.map +1 -0
  133. package/dist/features/preview/components/PageTree.js +410 -0
  134. package/dist/features/preview/components/PeekedBlock.d.ts +6 -0
  135. package/dist/features/preview/components/PeekedBlock.d.ts.map +1 -0
  136. package/dist/features/preview/components/PeekedBlock.js +95 -0
  137. package/dist/features/preview/components/PreviewPanel.d.ts +12 -0
  138. package/dist/features/preview/components/PreviewPanel.d.ts.map +1 -0
  139. package/dist/features/preview/components/PreviewPanel.js +192 -0
  140. package/dist/features/preview/components/PreviewSideSheet.d.ts +13 -0
  141. package/dist/features/preview/components/PreviewSideSheet.d.ts.map +1 -0
  142. package/dist/features/preview/components/PreviewSideSheet.js +28 -0
  143. package/dist/features/preview/components/PreviewToolbar.d.ts +2 -0
  144. package/dist/features/preview/components/PreviewToolbar.d.ts.map +1 -0
  145. package/dist/features/preview/components/PreviewToolbar.js +79 -0
  146. package/dist/features/preview/components/RepeatableItemsList.d.ts +14 -0
  147. package/dist/features/preview/components/RepeatableItemsList.d.ts.map +1 -0
  148. package/dist/features/preview/components/RepeatableItemsList.js +366 -0
  149. package/dist/features/preview/components/ShikiMarkdown.d.ts +4 -0
  150. package/dist/features/preview/components/ShikiMarkdown.d.ts.map +1 -0
  151. package/dist/features/preview/components/ShikiMarkdown.js +37 -0
  152. package/dist/features/preview/components/TextFormatToolbar.d.ts +2 -0
  153. package/dist/features/preview/components/TextFormatToolbar.d.ts.map +1 -0
  154. package/dist/features/preview/components/TextFormatToolbar.js +73 -0
  155. package/dist/features/preview/components/UnlinkAssetButton.d.ts +9 -0
  156. package/dist/features/preview/components/UnlinkAssetButton.d.ts.map +1 -0
  157. package/dist/features/preview/components/UnlinkAssetButton.js +55 -0
  158. package/dist/features/preview/overlayConstants.d.ts +19 -0
  159. package/dist/features/preview/overlayConstants.d.ts.map +1 -0
  160. package/dist/features/preview/overlayConstants.js +21 -0
  161. package/dist/features/preview/overlayMessages.d.ts +62 -0
  162. package/dist/features/preview/overlayMessages.d.ts.map +1 -0
  163. package/dist/features/preview/overlayMessages.js +9 -0
  164. package/dist/features/preview/previewConstants.d.ts +2 -0
  165. package/dist/features/preview/previewConstants.d.ts.map +1 -0
  166. package/dist/features/preview/previewStore.d.ts +116 -0
  167. package/dist/features/preview/previewStore.d.ts.map +1 -0
  168. package/dist/features/preview/previewStore.js +321 -0
  169. package/dist/features/provider/CamoxProvider.d.ts +11 -0
  170. package/dist/features/provider/CamoxProvider.d.ts.map +1 -0
  171. package/dist/features/provider/CamoxProvider.js +73 -0
  172. package/dist/features/provider/actionsStore.d.ts +39 -0
  173. package/dist/features/provider/actionsStore.d.ts.map +1 -0
  174. package/dist/features/provider/actionsStore.js +35 -0
  175. package/dist/features/provider/components/CamoxAppContext.d.ts +371 -0
  176. package/dist/features/provider/components/CamoxAppContext.d.ts.map +1 -0
  177. package/dist/features/provider/components/CamoxAppContext.js +17 -0
  178. package/dist/features/provider/components/CommandPalette.d.ts +3 -0
  179. package/dist/features/provider/components/CommandPalette.d.ts.map +1 -0
  180. package/dist/features/provider/components/CommandPalette.js +127 -0
  181. package/dist/features/provider/useAdminShortcuts.d.ts +5 -0
  182. package/dist/features/provider/useAdminShortcuts.d.ts.map +1 -0
  183. package/dist/features/provider/useAdminShortcuts.js +83 -0
  184. package/dist/features/routes/ogRoute.d.ts +7 -0
  185. package/dist/features/routes/ogRoute.d.ts.map +1 -0
  186. package/dist/features/routes/ogRoute.js +19 -0
  187. package/dist/features/routes/pageRoute.d.ts +135 -0
  188. package/dist/features/routes/pageRoute.d.ts.map +1 -0
  189. package/dist/features/routes/pageRoute.js +112 -0
  190. package/dist/features/studio/CamoxStudio.d.ts +7 -0
  191. package/dist/features/studio/CamoxStudio.d.ts.map +1 -0
  192. package/dist/features/studio/CamoxStudio.js +24 -0
  193. package/dist/features/studio/components/Navbar.d.ts +4 -0
  194. package/dist/features/studio/components/Navbar.d.ts.map +1 -0
  195. package/dist/features/studio/components/Navbar.js +95 -0
  196. package/dist/features/studio/components/ProjectMenu.d.ts +2 -0
  197. package/dist/features/studio/components/ProjectMenu.d.ts.map +1 -0
  198. package/dist/features/studio/components/ProjectMenu.js +132 -0
  199. package/dist/features/studio/components/UserButton.d.ts +2 -0
  200. package/dist/features/studio/components/UserButton.d.ts.map +1 -0
  201. package/dist/features/studio/components/UserButton.js +96 -0
  202. package/dist/features/studio/studioStore.d.ts +17 -0
  203. package/dist/features/studio/studioStore.d.ts.map +1 -0
  204. package/dist/features/studio/studioStore.js +44 -0
  205. package/dist/features/studio/useTheme.d.ts +9 -0
  206. package/dist/features/studio/useTheme.d.ts.map +1 -0
  207. package/dist/features/studio/useTheme.js +98 -0
  208. package/dist/features/vite/appGeneration.d.ts +4 -0
  209. package/dist/features/vite/appGeneration.d.ts.map +1 -0
  210. package/dist/features/vite/appGeneration.js +67 -0
  211. package/dist/features/vite/blockBoilerplate.d.ts +3 -0
  212. package/dist/features/vite/blockBoilerplate.d.ts.map +1 -0
  213. package/dist/features/vite/blockBoilerplate.js +59 -0
  214. package/dist/features/vite/convexSync.d.ts +6 -0
  215. package/dist/features/vite/convexSync.d.ts.map +1 -0
  216. package/dist/features/vite/convexSync.js +98 -0
  217. package/dist/features/vite/definitionsSync.d.ts +11 -0
  218. package/dist/features/vite/definitionsSync.d.ts.map +1 -0
  219. package/dist/features/vite/definitionsSync.js +157 -0
  220. package/dist/features/vite/routeGeneration.d.ts +4 -0
  221. package/dist/features/vite/routeGeneration.d.ts.map +1 -0
  222. package/dist/features/vite/routeGeneration.js +194 -0
  223. package/dist/features/vite/skillGeneration.d.ts +4 -0
  224. package/dist/features/vite/skillGeneration.d.ts.map +1 -0
  225. package/dist/features/vite/skillGeneration.js +69 -0
  226. package/dist/features/vite/utils.d.ts +2 -0
  227. package/dist/features/vite/utils.d.ts.map +1 -0
  228. package/dist/features/vite/utils.js +10 -0
  229. package/dist/features/vite/vite.d.ts +18 -0
  230. package/dist/features/vite/vite.d.ts.map +1 -0
  231. package/dist/features/vite/vite.js +77 -0
  232. package/dist/hooks/use-file-upload.d.ts +22 -0
  233. package/dist/hooks/use-file-upload.d.ts.map +1 -0
  234. package/dist/hooks/use-marquee-selection.d.ts +17 -0
  235. package/dist/hooks/use-marquee-selection.d.ts.map +1 -0
  236. package/dist/lib/analytics-client.d.ts +3 -0
  237. package/dist/lib/analytics-client.d.ts.map +1 -0
  238. package/dist/lib/analytics.d.ts +3 -0
  239. package/dist/lib/analytics.d.ts.map +1 -0
  240. package/dist/lib/analytics.js +24 -0
  241. package/dist/lib/auth.d.ts +3683 -0
  242. package/dist/lib/auth.d.ts.map +1 -0
  243. package/dist/lib/convex-site.d.ts +3 -0
  244. package/dist/lib/convex-site.d.ts.map +1 -0
  245. package/dist/lib/utils.d.ts +40 -0
  246. package/dist/lib/utils.d.ts.map +1 -0
  247. package/dist/studio.css +2 -0
  248. package/package.json +123 -10
  249. package/server/api.d.ts +1 -0
  250. package/server/api.js +1 -0
  251. package/server/dataModel.d.ts +1 -0
  252. package/server/dataModel.js +1 -0
  253. package/skills/camox-block/SKILL.md +357 -0
  254. package/skills/camox-layout/SKILL.md +181 -0
  255. package/index.js +0 -3
@@ -0,0 +1,308 @@
1
+ import { previewStore } from "../previewStore.js";
2
+ import { RepeatableItemsList } from "./RepeatableItemsList.js";
3
+ import { Input } from "@camox/ui/input";
4
+ import { Label } from "@camox/ui/label";
5
+ import * as React from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { FileIcon, ImageIcon, Images, Link2 } from "lucide-react";
8
+ import { useForm } from "@tanstack/react-form";
9
+ import { SidebarLexicalEditor } from "@/core/components/lexical/SidebarLexicalEditor";
10
+ import { isLexicalState, plainTextToLexicalState } from "@/core/lib/lexicalState";
11
+ //#region src/features/preview/components/ItemFieldsEditor.tsx
12
+ var formatFieldName = (fieldName) => {
13
+ return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase()).trim();
14
+ };
15
+ var getSchemaFieldsInOrder = (schema) => {
16
+ const properties = schema?.properties;
17
+ if (!properties) return [];
18
+ return Object.keys(properties).map((fieldName) => {
19
+ const prop = properties[fieldName];
20
+ return {
21
+ name: fieldName,
22
+ fieldType: prop.fieldType,
23
+ label: prop.title,
24
+ minItems: prop.minItems,
25
+ maxItems: prop.maxItems,
26
+ arrayItemType: prop.arrayItemType
27
+ };
28
+ });
29
+ };
30
+ var ItemFieldsEditor = ({ schema, data, blockId, itemId, parentItemId, parentFieldName, onFieldChange, postToIframe }) => {
31
+ const fields = React.useMemo(() => getSchemaFieldsInOrder(schema), [schema]);
32
+ const timerRef = React.useRef(null);
33
+ const focusedFieldIdRef = React.useRef(null);
34
+ const getFieldId = (fieldName) => {
35
+ if (itemId && parentItemId && parentFieldName) return `${blockId}__${parentItemId}:${parentFieldName}:${parseInt(itemId.slice(4), 10)}__${fieldName}`;
36
+ if (itemId) return `${blockId}__${itemId}__${fieldName}`;
37
+ return `${blockId}__${fieldName}`;
38
+ };
39
+ const scalarFields = React.useMemo(() => {
40
+ return fields.filter((f) => f.fieldType === "String" || f.fieldType === "Embed").map((f) => f.name);
41
+ }, [fields]);
42
+ const defaultValues = React.useMemo(() => {
43
+ const values = {};
44
+ for (const fieldName of scalarFields) {
45
+ const raw = data[fieldName] ?? "";
46
+ if (fields.find((f) => f.name === fieldName)?.fieldType === "String" && raw && !isLexicalState(raw)) values[fieldName] = plainTextToLexicalState(raw);
47
+ else values[fieldName] = raw;
48
+ }
49
+ return values;
50
+ }, [
51
+ data,
52
+ scalarFields,
53
+ fields
54
+ ]);
55
+ const form = useForm({ defaultValues });
56
+ React.useEffect(() => {
57
+ form.update({ defaultValues });
58
+ }, [defaultValues, form]);
59
+ React.useEffect(() => {
60
+ return () => {
61
+ if (timerRef.current) clearTimeout(timerRef.current);
62
+ if (focusedFieldIdRef.current) postToIframe({
63
+ type: "CAMOX_FOCUS_FIELD_END",
64
+ fieldId: focusedFieldIdRef.current
65
+ });
66
+ };
67
+ }, [postToIframe]);
68
+ const handleScalarChange = (fieldName, value, fieldApi) => {
69
+ fieldApi.handleChange(value);
70
+ if (timerRef.current) clearTimeout(timerRef.current);
71
+ timerRef.current = window.setTimeout(() => {
72
+ onFieldChange(fieldName, value);
73
+ }, 500);
74
+ };
75
+ const handleFieldFocus = (fieldName) => {
76
+ const fieldId = getFieldId(fieldName);
77
+ focusedFieldIdRef.current = fieldId;
78
+ postToIframe({
79
+ type: "CAMOX_FOCUS_FIELD",
80
+ fieldId
81
+ });
82
+ };
83
+ const handleFieldBlur = (fieldName) => {
84
+ const fieldId = getFieldId(fieldName);
85
+ focusedFieldIdRef.current = null;
86
+ postToIframe({
87
+ type: "CAMOX_FOCUS_FIELD_END",
88
+ fieldId
89
+ });
90
+ };
91
+ return /* @__PURE__ */ jsx("form", {
92
+ className: "space-y-4 px-4 py-4",
93
+ children: fields.map((field) => {
94
+ const label = field.label ?? formatFieldName(field.name);
95
+ const fieldId = getFieldId(field.name);
96
+ if (field.fieldType === "String") return /* @__PURE__ */ jsx(form.Field, {
97
+ name: field.name,
98
+ children: (fieldApi) => /* @__PURE__ */ jsxs("div", {
99
+ className: "space-y-2",
100
+ onMouseEnter: () => postToIframe({
101
+ type: "CAMOX_HOVER_FIELD",
102
+ fieldId
103
+ }),
104
+ onMouseLeave: () => postToIframe({
105
+ type: "CAMOX_HOVER_FIELD_END",
106
+ fieldId
107
+ }),
108
+ children: [/* @__PURE__ */ jsx(Label, {
109
+ htmlFor: field.name,
110
+ children: label
111
+ }), /* @__PURE__ */ jsx(SidebarLexicalEditor, {
112
+ value: fieldApi.state.value,
113
+ onChange: (value) => handleScalarChange(field.name, value, fieldApi),
114
+ onFocus: () => handleFieldFocus(field.name),
115
+ onBlur: () => handleFieldBlur(field.name)
116
+ })]
117
+ })
118
+ }, field.name);
119
+ if (field.fieldType === "Embed") return /* @__PURE__ */ jsx(form.Field, {
120
+ name: field.name,
121
+ children: (fieldApi) => /* @__PURE__ */ jsxs("div", {
122
+ className: "space-y-2",
123
+ onMouseEnter: () => postToIframe({
124
+ type: "CAMOX_HOVER_FIELD",
125
+ fieldId
126
+ }),
127
+ onMouseLeave: () => postToIframe({
128
+ type: "CAMOX_HOVER_FIELD_END",
129
+ fieldId
130
+ }),
131
+ children: [/* @__PURE__ */ jsx(Label, {
132
+ htmlFor: field.name,
133
+ children: label
134
+ }), /* @__PURE__ */ jsx(Input, {
135
+ id: field.name,
136
+ type: "url",
137
+ value: fieldApi.state.value,
138
+ onChange: (e) => handleScalarChange(field.name, e.target.value, fieldApi),
139
+ onFocus: () => handleFieldFocus(field.name),
140
+ onBlur: () => handleFieldBlur(field.name)
141
+ })]
142
+ })
143
+ }, field.name);
144
+ if (field.fieldType === "Link") {
145
+ const linkValue = data[field.name];
146
+ const preview = linkValue?.text || linkValue?.href || "Empty link";
147
+ return /* @__PURE__ */ jsxs("div", {
148
+ className: "space-y-2",
149
+ onMouseEnter: () => postToIframe({
150
+ type: "CAMOX_HOVER_FIELD",
151
+ fieldId
152
+ }),
153
+ onMouseLeave: () => postToIframe({
154
+ type: "CAMOX_HOVER_FIELD_END",
155
+ fieldId
156
+ }),
157
+ children: [/* @__PURE__ */ jsx(Label, { children: label }), /* @__PURE__ */ jsxs("button", {
158
+ type: "button",
159
+ className: "hover:bg-accent/75 flex w-full items-center gap-2 rounded-lg px-2 py-2 text-left text-sm transition-colors",
160
+ onClick: () => previewStore.send({
161
+ type: "drillIntoLink",
162
+ fieldName: field.name
163
+ }),
164
+ children: [/* @__PURE__ */ jsx(Link2, { className: "text-muted-foreground h-4 w-4 shrink-0" }), /* @__PURE__ */ jsx("span", {
165
+ className: "truncate",
166
+ children: preview
167
+ })]
168
+ })]
169
+ }, field.name);
170
+ }
171
+ if (field.fieldType === "RepeatableObject" && field.arrayItemType === "Image") {
172
+ const count = (data[field.name] ?? []).length;
173
+ let preview;
174
+ if (count === 0) preview = "No images";
175
+ else if (count === 1) preview = "1 image";
176
+ else preview = `${count} images`;
177
+ return /* @__PURE__ */ jsxs("div", {
178
+ className: "space-y-2",
179
+ onMouseEnter: () => postToIframe({
180
+ type: "CAMOX_HOVER_REPEATER",
181
+ blockId,
182
+ fieldName: field.name
183
+ }),
184
+ onMouseLeave: () => postToIframe({
185
+ type: "CAMOX_HOVER_REPEATER_END",
186
+ blockId,
187
+ fieldName: field.name
188
+ }),
189
+ children: [/* @__PURE__ */ jsx(Label, { children: label }), /* @__PURE__ */ jsxs("button", {
190
+ type: "button",
191
+ className: "hover:bg-accent/75 flex w-full items-center gap-2 rounded-lg px-2 py-2 text-left text-sm transition-colors",
192
+ onClick: () => previewStore.send({
193
+ type: "drillIntoImage",
194
+ fieldName: field.name
195
+ }),
196
+ children: [/* @__PURE__ */ jsx(Images, { className: "text-muted-foreground h-4 w-4 shrink-0" }), /* @__PURE__ */ jsx("span", {
197
+ className: "truncate",
198
+ children: preview
199
+ })]
200
+ })]
201
+ }, field.name);
202
+ }
203
+ if (field.fieldType === "RepeatableObject" && field.arrayItemType === "File") {
204
+ const count = (data[field.name] ?? []).length;
205
+ let preview;
206
+ if (count === 0) preview = "No files";
207
+ else if (count === 1) preview = "1 file";
208
+ else preview = `${count} files`;
209
+ return /* @__PURE__ */ jsxs("div", {
210
+ className: "space-y-2",
211
+ onMouseEnter: () => postToIframe({
212
+ type: "CAMOX_HOVER_REPEATER",
213
+ blockId,
214
+ fieldName: field.name
215
+ }),
216
+ onMouseLeave: () => postToIframe({
217
+ type: "CAMOX_HOVER_REPEATER_END",
218
+ blockId,
219
+ fieldName: field.name
220
+ }),
221
+ children: [/* @__PURE__ */ jsx(Label, { children: label }), /* @__PURE__ */ jsxs("button", {
222
+ type: "button",
223
+ className: "hover:bg-accent/75 flex w-full items-center gap-2 rounded-lg px-2 py-2 text-left text-sm transition-colors",
224
+ onClick: () => previewStore.send({
225
+ type: "drillIntoFile",
226
+ fieldName: field.name
227
+ }),
228
+ children: [/* @__PURE__ */ jsx(FileIcon, { className: "text-muted-foreground h-4 w-4 shrink-0" }), /* @__PURE__ */ jsx("span", {
229
+ className: "truncate",
230
+ children: preview
231
+ })]
232
+ })]
233
+ }, field.name);
234
+ }
235
+ if (field.fieldType === "Image") {
236
+ const preview = data[field.name]?.filename || "No image";
237
+ return /* @__PURE__ */ jsxs("div", {
238
+ className: "space-y-2",
239
+ onMouseEnter: () => postToIframe({
240
+ type: "CAMOX_HOVER_FIELD",
241
+ fieldId
242
+ }),
243
+ onMouseLeave: () => postToIframe({
244
+ type: "CAMOX_HOVER_FIELD_END",
245
+ fieldId
246
+ }),
247
+ children: [/* @__PURE__ */ jsx(Label, { children: label }), /* @__PURE__ */ jsxs("button", {
248
+ type: "button",
249
+ className: "hover:bg-accent/75 flex w-full items-center gap-2 rounded-lg px-2 py-2 text-left text-sm transition-colors",
250
+ onClick: () => previewStore.send({
251
+ type: "drillIntoImage",
252
+ fieldName: field.name
253
+ }),
254
+ children: [/* @__PURE__ */ jsx(ImageIcon, { className: "text-muted-foreground h-4 w-4 shrink-0" }), /* @__PURE__ */ jsx("span", {
255
+ className: "truncate",
256
+ children: preview
257
+ })]
258
+ })]
259
+ }, field.name);
260
+ }
261
+ if (field.fieldType === "File") {
262
+ const preview = data[field.name]?.filename || "No file";
263
+ return /* @__PURE__ */ jsxs("div", {
264
+ className: "space-y-2",
265
+ onMouseEnter: () => postToIframe({
266
+ type: "CAMOX_HOVER_FIELD",
267
+ fieldId
268
+ }),
269
+ onMouseLeave: () => postToIframe({
270
+ type: "CAMOX_HOVER_FIELD_END",
271
+ fieldId
272
+ }),
273
+ children: [/* @__PURE__ */ jsx(Label, { children: label }), /* @__PURE__ */ jsxs("button", {
274
+ type: "button",
275
+ className: "hover:bg-accent/75 flex w-full items-center gap-2 rounded-lg px-2 py-2 text-left text-sm transition-colors",
276
+ onClick: () => previewStore.send({
277
+ type: "drillIntoFile",
278
+ fieldName: field.name
279
+ }),
280
+ children: [/* @__PURE__ */ jsx(FileIcon, { className: "text-muted-foreground h-4 w-4 shrink-0" }), /* @__PURE__ */ jsx("span", {
281
+ className: "truncate",
282
+ children: preview
283
+ })]
284
+ })]
285
+ }, field.name);
286
+ }
287
+ if (field.fieldType === "RepeatableObject") {
288
+ const items = data[field.name] ?? [];
289
+ const fieldSchema = schema?.properties?.[field.name];
290
+ return /* @__PURE__ */ jsxs("div", {
291
+ className: "space-y-2",
292
+ children: [/* @__PURE__ */ jsx(Label, { children: label }), /* @__PURE__ */ jsx(RepeatableItemsList, {
293
+ items,
294
+ blockId,
295
+ fieldName: field.name,
296
+ minItems: field.minItems,
297
+ maxItems: field.maxItems,
298
+ schema: fieldSchema,
299
+ parentItemId: itemId
300
+ })]
301
+ }, field.name);
302
+ }
303
+ return null;
304
+ })
305
+ });
306
+ };
307
+ //#endregion
308
+ export { ItemFieldsEditor, formatFieldName };
@@ -0,0 +1,8 @@
1
+ interface LinkFieldEditorProps {
2
+ fieldName: string;
3
+ linkValue: Record<string, unknown>;
4
+ onSave: (fieldName: string, value: Record<string, unknown>) => void;
5
+ }
6
+ declare const LinkFieldEditor: ({ fieldName, linkValue: rawLinkValue, onSave }: LinkFieldEditorProps) => import("react/jsx-runtime").JSX.Element;
7
+ export { LinkFieldEditor };
8
+ //# sourceMappingURL=LinkFieldEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LinkFieldEditor.d.ts","sourceRoot":"","sources":["../../../../src/features/preview/components/LinkFieldEditor.tsx"],"names":[],"mappings":"AA0BA,UAAU,oBAAoB;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CACrE;AAUD,QAAA,MAAM,eAAe,GAAI,gDAAgD,oBAAoB,4CAwK5F,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,190 @@
1
+ import { Input } from "@camox/ui/input";
2
+ import { Label } from "@camox/ui/label";
3
+ import { Popover, PopoverContent, PopoverTrigger } from "@camox/ui/popover";
4
+ import { api } from "camox/server/api";
5
+ import { useQuery } from "convex/react";
6
+ import * as React from "react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ import { cn, formatPathSegment } from "@/lib/utils";
9
+ import { Button } from "@camox/ui/button";
10
+ import { Check, ChevronsUpDown } from "lucide-react";
11
+ import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@camox/ui/command";
12
+ import { Switch } from "@camox/ui/switch";
13
+ import { Tabs, TabsList, TabsTrigger } from "@camox/ui/tabs";
14
+ //#region src/features/preview/components/LinkFieldEditor.tsx
15
+ /** Normalize legacy links (no `type` field) into the union shape */
16
+ var normalizeLinkValue = (value) => {
17
+ if (!value.type) return {
18
+ type: "external",
19
+ ...value
20
+ };
21
+ return value;
22
+ };
23
+ var LinkFieldEditor = ({ fieldName, linkValue: rawLinkValue, onSave }) => {
24
+ const linkValue = normalizeLinkValue(rawLinkValue);
25
+ const timerRef = React.useRef(null);
26
+ const [text, setText] = React.useState(linkValue.text);
27
+ const [href, setHref] = React.useState(linkValue.type === "external" ? linkValue.href : "");
28
+ const linkValueRef = React.useRef(linkValue);
29
+ const [pagePickerOpen, setPagePickerOpen] = React.useState(false);
30
+ const pages = useQuery(api.pages.listPages);
31
+ const selectedPage = linkValue.type === "page" ? pages?.find((p) => p._id === linkValue.pageId) : null;
32
+ React.useEffect(() => {
33
+ linkValueRef.current = linkValue;
34
+ }, [linkValue]);
35
+ React.useEffect(() => {
36
+ setText(linkValue.text);
37
+ }, [linkValue.text]);
38
+ React.useEffect(() => {
39
+ if (linkValue.type === "external") setHref(linkValue.href);
40
+ }, [linkValue]);
41
+ React.useEffect(() => {
42
+ return () => {
43
+ if (timerRef.current) clearTimeout(timerRef.current);
44
+ };
45
+ }, []);
46
+ const handleTextChange = (value) => {
47
+ if (timerRef.current) clearTimeout(timerRef.current);
48
+ timerRef.current = window.setTimeout(() => {
49
+ onSave(fieldName, {
50
+ ...linkValueRef.current,
51
+ text: value
52
+ });
53
+ }, 500);
54
+ };
55
+ const handleHrefChange = (value) => {
56
+ if (timerRef.current) clearTimeout(timerRef.current);
57
+ timerRef.current = window.setTimeout(() => {
58
+ onSave(fieldName, {
59
+ ...linkValueRef.current,
60
+ href: value
61
+ });
62
+ }, 500);
63
+ };
64
+ const handleModeChange = (mode) => {
65
+ if (mode === "page") onSave(fieldName, {
66
+ type: "page",
67
+ text: linkValueRef.current.text,
68
+ pageId: "",
69
+ newTab: linkValueRef.current.newTab
70
+ });
71
+ else onSave(fieldName, {
72
+ type: "external",
73
+ text: linkValueRef.current.text,
74
+ href: "",
75
+ newTab: linkValueRef.current.newTab
76
+ });
77
+ };
78
+ const handlePageSelect = (pageId) => {
79
+ onSave(fieldName, {
80
+ type: "page",
81
+ text: linkValueRef.current.text,
82
+ pageId,
83
+ newTab: linkValueRef.current.newTab
84
+ });
85
+ setPagePickerOpen(false);
86
+ };
87
+ return /* @__PURE__ */ jsxs("form", {
88
+ className: "grid gap-3",
89
+ children: [
90
+ /* @__PURE__ */ jsxs("div", {
91
+ className: "grid gap-1.5",
92
+ children: [/* @__PURE__ */ jsx(Label, {
93
+ htmlFor: `${fieldName}-text`,
94
+ children: "Text"
95
+ }), /* @__PURE__ */ jsx(Input, {
96
+ id: `${fieldName}-text`,
97
+ value: text,
98
+ onChange: (e) => {
99
+ setText(e.target.value);
100
+ handleTextChange(e.target.value);
101
+ },
102
+ autoFocus: true
103
+ })]
104
+ }),
105
+ /* @__PURE__ */ jsxs("div", {
106
+ className: "grid gap-1.5",
107
+ children: [
108
+ /* @__PURE__ */ jsx(Label, { children: "Destination" }),
109
+ /* @__PURE__ */ jsx(Tabs, {
110
+ value: linkValue.type,
111
+ onValueChange: handleModeChange,
112
+ children: /* @__PURE__ */ jsxs(TabsList, {
113
+ className: "w-full",
114
+ children: [/* @__PURE__ */ jsx(TabsTrigger, {
115
+ value: "page",
116
+ children: "Page"
117
+ }), /* @__PURE__ */ jsx(TabsTrigger, {
118
+ value: "external",
119
+ children: "URL"
120
+ })]
121
+ })
122
+ }),
123
+ linkValue.type === "page" ? /* @__PURE__ */ jsxs(Popover, {
124
+ open: pagePickerOpen,
125
+ onOpenChange: setPagePickerOpen,
126
+ children: [/* @__PURE__ */ jsx(PopoverTrigger, {
127
+ asChild: true,
128
+ children: /* @__PURE__ */ jsxs(Button, {
129
+ variant: "outline",
130
+ role: "combobox",
131
+ className: "justify-between font-normal",
132
+ children: [selectedPage ? /* @__PURE__ */ jsx("span", {
133
+ className: "truncate",
134
+ children: selectedPage.metaTitle ?? formatPathSegment(selectedPage.pathSegment)
135
+ }) : /* @__PURE__ */ jsx("span", {
136
+ className: "text-muted-foreground",
137
+ children: "Select a page"
138
+ }), /* @__PURE__ */ jsx(ChevronsUpDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })]
139
+ })
140
+ }), /* @__PURE__ */ jsx(PopoverContent, {
141
+ align: "start",
142
+ className: "p-0",
143
+ children: /* @__PURE__ */ jsxs(Command, { children: [/* @__PURE__ */ jsx(CommandInput, {
144
+ placeholder: "Search page...",
145
+ className: "h-9"
146
+ }), /* @__PURE__ */ jsxs(CommandList, { children: [/* @__PURE__ */ jsx(CommandEmpty, { children: "No page found." }), /* @__PURE__ */ jsx(CommandGroup, { children: pages?.map((page) => /* @__PURE__ */ jsxs(CommandItem, {
147
+ value: page.fullPath,
148
+ onSelect: () => handlePageSelect(page._id),
149
+ children: [/* @__PURE__ */ jsx(Check, { className: cn("mr-2 size-4", selectedPage?._id === page._id ? "opacity-100" : "opacity-0") }), /* @__PURE__ */ jsxs("div", {
150
+ className: "flex flex-col",
151
+ children: [/* @__PURE__ */ jsx("span", { children: page.metaTitle ?? formatPathSegment(page.pathSegment) }), /* @__PURE__ */ jsx("span", {
152
+ className: "text-muted-foreground font-mono text-xs",
153
+ children: page.fullPath
154
+ })]
155
+ })]
156
+ }, page._id)) })] })] })
157
+ })]
158
+ }) : /* @__PURE__ */ jsx(Input, {
159
+ type: "url",
160
+ id: `${fieldName}-href`,
161
+ placeholder: "https://",
162
+ value: href,
163
+ onChange: (e) => {
164
+ setHref(e.target.value);
165
+ handleHrefChange(e.target.value);
166
+ }
167
+ })
168
+ ]
169
+ }),
170
+ /* @__PURE__ */ jsxs("div", {
171
+ className: "flex items-center gap-2",
172
+ children: [/* @__PURE__ */ jsx(Switch, {
173
+ id: `${fieldName}-newtab`,
174
+ checked: linkValue.newTab,
175
+ onCheckedChange: (checked) => {
176
+ onSave(fieldName, {
177
+ ...linkValueRef.current,
178
+ newTab: checked
179
+ });
180
+ }
181
+ }), /* @__PURE__ */ jsx(Label, {
182
+ htmlFor: `${fieldName}-newtab`,
183
+ children: "Open in new tab"
184
+ })]
185
+ })
186
+ ]
187
+ });
188
+ };
189
+ //#endregion
190
+ export { LinkFieldEditor };
@@ -0,0 +1,10 @@
1
+ import { Id } from 'camox/server/dataModel';
2
+ interface MultipleAssetFieldEditorProps {
3
+ fieldName: string;
4
+ assetType: "Image" | "File";
5
+ currentData: Record<string, unknown>;
6
+ blockId: Id<"blocks">;
7
+ }
8
+ declare const MultipleAssetFieldEditor: ({ fieldName, assetType, currentData, blockId, }: MultipleAssetFieldEditorProps) => import("react/jsx-runtime").JSX.Element;
9
+ export { MultipleAssetFieldEditor };
10
+ //# sourceMappingURL=MultipleAssetFieldEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MultipleAssetFieldEditor.d.ts","sourceRoot":"","sources":["../../../../src/features/preview/components/MultipleAssetFieldEditor.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAO,EAAE,EAAE,MAAM,wBAAwB,CAAC;AA2GtD,UAAU,6BAA6B;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,GAAG,MAAM,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC;CACvB;AAED,QAAA,MAAM,wBAAwB,GAAI,iDAK/B,6BAA6B,4CA8N/B,CAAC;AAEF,OAAO,EAAE,wBAAwB,EAAE,CAAC"}