canopycms 0.0.57 → 0.0.58

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 (215) hide show
  1. package/dist/ai/json-to-markdown.js +74 -3
  2. package/dist/ai/json-to-markdown.js.map +1 -1
  3. package/dist/api/__test__/mock-client.d.ts +9 -5
  4. package/dist/api/__test__/mock-client.d.ts.map +1 -1
  5. package/dist/api/__test__/mock-client.js +15 -7
  6. package/dist/api/__test__/mock-client.js.map +1 -1
  7. package/dist/api/assets.d.ts +100 -36
  8. package/dist/api/assets.d.ts.map +1 -1
  9. package/dist/api/assets.js +338 -51
  10. package/dist/api/assets.js.map +1 -1
  11. package/dist/api/client.d.ts +16 -5
  12. package/dist/api/client.d.ts.map +1 -1
  13. package/dist/api/client.js +24 -6
  14. package/dist/api/client.js.map +1 -1
  15. package/dist/api/entries.d.ts +4 -4
  16. package/dist/api/index.d.ts +1 -1
  17. package/dist/api/index.d.ts.map +1 -1
  18. package/dist/api/index.js.map +1 -1
  19. package/dist/api/route-builder.d.ts +9 -0
  20. package/dist/api/route-builder.d.ts.map +1 -1
  21. package/dist/api/route-builder.js +1 -0
  22. package/dist/api/route-builder.js.map +1 -1
  23. package/dist/api/schema.d.ts +4 -4
  24. package/dist/api/types.d.ts +11 -1
  25. package/dist/api/types.d.ts.map +1 -1
  26. package/dist/assets/asset-prefixes.d.ts +31 -0
  27. package/dist/assets/asset-prefixes.d.ts.map +1 -0
  28. package/dist/assets/asset-prefixes.js +20 -0
  29. package/dist/assets/asset-prefixes.js.map +1 -0
  30. package/dist/assets/asset-src.d.ts +23 -0
  31. package/dist/assets/asset-src.d.ts.map +1 -0
  32. package/dist/assets/asset-src.js +28 -0
  33. package/dist/assets/asset-src.js.map +1 -0
  34. package/dist/assets/asset-url.d.ts +35 -0
  35. package/dist/assets/asset-url.d.ts.map +1 -0
  36. package/dist/assets/asset-url.js +77 -0
  37. package/dist/assets/asset-url.js.map +1 -0
  38. package/dist/assets/factory.d.ts +18 -0
  39. package/dist/assets/factory.d.ts.map +1 -0
  40. package/dist/assets/factory.js +42 -0
  41. package/dist/assets/factory.js.map +1 -0
  42. package/dist/assets/finalize.d.ts +36 -0
  43. package/dist/assets/finalize.d.ts.map +1 -0
  44. package/dist/assets/finalize.js +72 -0
  45. package/dist/assets/finalize.js.map +1 -0
  46. package/dist/assets/index.d.ts +20 -0
  47. package/dist/assets/index.d.ts.map +1 -0
  48. package/dist/assets/index.js +19 -0
  49. package/dist/assets/index.js.map +1 -0
  50. package/dist/assets/keys.d.ts +56 -0
  51. package/dist/assets/keys.d.ts.map +1 -0
  52. package/dist/assets/keys.js +88 -0
  53. package/dist/assets/keys.js.map +1 -0
  54. package/dist/assets/pipeline.d.ts +50 -0
  55. package/dist/assets/pipeline.d.ts.map +1 -0
  56. package/dist/assets/pipeline.js +202 -0
  57. package/dist/assets/pipeline.js.map +1 -0
  58. package/dist/assets/store-local.d.ts +84 -0
  59. package/dist/assets/store-local.d.ts.map +1 -0
  60. package/dist/assets/store-local.js +254 -0
  61. package/dist/assets/store-local.js.map +1 -0
  62. package/dist/assets/store-s3.d.ts +71 -0
  63. package/dist/assets/store-s3.d.ts.map +1 -0
  64. package/dist/assets/store-s3.js +183 -0
  65. package/dist/assets/store-s3.js.map +1 -0
  66. package/dist/assets/svg-sanitizer.d.ts +37 -0
  67. package/dist/assets/svg-sanitizer.d.ts.map +1 -0
  68. package/dist/assets/svg-sanitizer.js +222 -0
  69. package/dist/assets/svg-sanitizer.js.map +1 -0
  70. package/dist/assets/transform-directives.d.ts +97 -0
  71. package/dist/assets/transform-directives.d.ts.map +1 -0
  72. package/dist/assets/transform-directives.js +267 -0
  73. package/dist/assets/transform-directives.js.map +1 -0
  74. package/dist/assets/transform.d.ts +51 -0
  75. package/dist/assets/transform.d.ts.map +1 -0
  76. package/dist/assets/transform.js +190 -0
  77. package/dist/assets/transform.js.map +1 -0
  78. package/dist/assets/types.d.ts +82 -0
  79. package/dist/assets/types.d.ts.map +1 -0
  80. package/dist/assets/types.js +10 -0
  81. package/dist/assets/types.js.map +1 -0
  82. package/dist/authorization/groups/schema.d.ts +2 -2
  83. package/dist/authorization/permissions/schema.d.ts +2 -2
  84. package/dist/cli/generate-ai-content.js +92 -7
  85. package/dist/cli/init.js +16 -4
  86. package/dist/config/helpers.d.ts.map +1 -1
  87. package/dist/config/helpers.js +2 -1
  88. package/dist/config/helpers.js.map +1 -1
  89. package/dist/config/index.d.ts +2 -2
  90. package/dist/config/index.d.ts.map +1 -1
  91. package/dist/config/index.js +1 -1
  92. package/dist/config/index.js.map +1 -1
  93. package/dist/config/schemas/config.d.ts +10 -0
  94. package/dist/config/schemas/config.d.ts.map +1 -1
  95. package/dist/config/schemas/field.d.ts +38 -3
  96. package/dist/config/schemas/field.d.ts.map +1 -1
  97. package/dist/config/schemas/field.js +18 -0
  98. package/dist/config/schemas/field.js.map +1 -1
  99. package/dist/config/schemas/media.d.ts +8 -0
  100. package/dist/config/schemas/media.d.ts.map +1 -1
  101. package/dist/config/schemas/media.js +9 -0
  102. package/dist/config/schemas/media.js.map +1 -1
  103. package/dist/config/types.d.ts +43 -3
  104. package/dist/config/types.d.ts.map +1 -1
  105. package/dist/config/types.js +4 -1
  106. package/dist/config/types.js.map +1 -1
  107. package/dist/editor/CanopyEditor.d.ts.map +1 -1
  108. package/dist/editor/CanopyEditor.js +1 -1
  109. package/dist/editor/CanopyEditor.js.map +1 -1
  110. package/dist/editor/Editor.d.ts +2 -0
  111. package/dist/editor/Editor.d.ts.map +1 -1
  112. package/dist/editor/Editor.js +82 -80
  113. package/dist/editor/Editor.js.map +1 -1
  114. package/dist/editor/FormRenderer.d.ts.map +1 -1
  115. package/dist/editor/FormRenderer.js +9 -0
  116. package/dist/editor/FormRenderer.js.map +1 -1
  117. package/dist/editor/components/EditorSidebar.d.ts +6 -1
  118. package/dist/editor/components/EditorSidebar.d.ts.map +1 -1
  119. package/dist/editor/components/EditorSidebar.js +4 -3
  120. package/dist/editor/components/EditorSidebar.js.map +1 -1
  121. package/dist/editor/context/AssetContext.d.ts +25 -0
  122. package/dist/editor/context/AssetContext.d.ts.map +1 -0
  123. package/dist/editor/context/AssetContext.js +26 -0
  124. package/dist/editor/context/AssetContext.js.map +1 -0
  125. package/dist/editor/context/index.d.ts +1 -0
  126. package/dist/editor/context/index.d.ts.map +1 -1
  127. package/dist/editor/context/index.js +1 -0
  128. package/dist/editor/context/index.js.map +1 -1
  129. package/dist/editor/fields/ImageField.d.ts +22 -0
  130. package/dist/editor/fields/ImageField.d.ts.map +1 -0
  131. package/dist/editor/fields/ImageField.js +100 -0
  132. package/dist/editor/fields/ImageField.js.map +1 -0
  133. package/dist/editor/fields/MarkdownField.d.ts.map +1 -1
  134. package/dist/editor/fields/MarkdownField.js +30 -4
  135. package/dist/editor/fields/MarkdownField.js.map +1 -1
  136. package/dist/editor/fields/MdxImageDialog.d.ts +16 -0
  137. package/dist/editor/fields/MdxImageDialog.d.ts.map +1 -0
  138. package/dist/editor/fields/MdxImageDialog.js +73 -0
  139. package/dist/editor/fields/MdxImageDialog.js.map +1 -0
  140. package/dist/editor/media/AssetCard.d.ts +21 -0
  141. package/dist/editor/media/AssetCard.d.ts.map +1 -0
  142. package/dist/editor/media/AssetCard.js +41 -0
  143. package/dist/editor/media/AssetCard.js.map +1 -0
  144. package/dist/editor/media/CropStep.d.ts +26 -0
  145. package/dist/editor/media/CropStep.d.ts.map +1 -0
  146. package/dist/editor/media/CropStep.js +38 -0
  147. package/dist/editor/media/CropStep.js.map +1 -0
  148. package/dist/editor/media/MediaLibrary.d.ts +22 -0
  149. package/dist/editor/media/MediaLibrary.d.ts.map +1 -0
  150. package/dist/editor/media/MediaLibrary.js +17 -0
  151. package/dist/editor/media/MediaLibrary.js.map +1 -0
  152. package/dist/editor/media/MediaLibraryBody.d.ts +17 -0
  153. package/dist/editor/media/MediaLibraryBody.d.ts.map +1 -0
  154. package/dist/editor/media/MediaLibraryBody.js +133 -0
  155. package/dist/editor/media/MediaLibraryBody.js.map +1 -0
  156. package/dist/editor/media/crop-math.d.ts +37 -0
  157. package/dist/editor/media/crop-math.d.ts.map +1 -0
  158. package/dist/editor/media/crop-math.js +62 -0
  159. package/dist/editor/media/crop-math.js.map +1 -0
  160. package/dist/editor/media/upload-asset.d.ts +31 -0
  161. package/dist/editor/media/upload-asset.d.ts.map +1 -0
  162. package/dist/editor/media/upload-asset.js +56 -0
  163. package/dist/editor/media/upload-asset.js.map +1 -0
  164. package/dist/editor/media/upload-constants.d.ts +27 -0
  165. package/dist/editor/media/upload-constants.d.ts.map +1 -0
  166. package/dist/editor/media/upload-constants.js +40 -0
  167. package/dist/editor/media/upload-constants.js.map +1 -0
  168. package/dist/editor/media/useAssetUpload.d.ts +19 -0
  169. package/dist/editor/media/useAssetUpload.d.ts.map +1 -0
  170. package/dist/editor/media/useAssetUpload.js +53 -0
  171. package/dist/editor/media/useAssetUpload.js.map +1 -0
  172. package/dist/editor/media/xhr-upload.d.ts +20 -0
  173. package/dist/editor/media/xhr-upload.d.ts.map +1 -0
  174. package/dist/editor/media/xhr-upload.js +42 -0
  175. package/dist/editor/media/xhr-upload.js.map +1 -0
  176. package/dist/editor/theme.d.ts +2 -1
  177. package/dist/editor/theme.d.ts.map +1 -1
  178. package/dist/editor/theme.js +1 -0
  179. package/dist/editor/theme.js.map +1 -1
  180. package/dist/entry-schema.d.ts +19 -0
  181. package/dist/entry-schema.d.ts.map +1 -1
  182. package/dist/entry-schema.js.map +1 -1
  183. package/dist/http/handler.d.ts +5 -2
  184. package/dist/http/handler.d.ts.map +1 -1
  185. package/dist/http/handler.js +13 -4
  186. package/dist/http/handler.js.map +1 -1
  187. package/dist/http/index.d.ts +2 -2
  188. package/dist/http/index.d.ts.map +1 -1
  189. package/dist/http/index.js +1 -1
  190. package/dist/http/index.js.map +1 -1
  191. package/dist/http/router.d.ts +14 -1
  192. package/dist/http/router.d.ts.map +1 -1
  193. package/dist/http/router.js +4 -1
  194. package/dist/http/router.js.map +1 -1
  195. package/dist/http/types.d.ts +40 -0
  196. package/dist/http/types.d.ts.map +1 -1
  197. package/dist/http/types.js +9 -0
  198. package/dist/http/types.js.map +1 -1
  199. package/dist/index.d.ts +3 -0
  200. package/dist/index.d.ts.map +1 -1
  201. package/dist/index.js +4 -0
  202. package/dist/index.js.map +1 -1
  203. package/dist/schema/schema-store.d.ts +2 -2
  204. package/dist/server.d.ts +45 -0
  205. package/dist/server.d.ts.map +1 -1
  206. package/dist/server.js +41 -0
  207. package/dist/server.js.map +1 -1
  208. package/dist/validation/entry-validator.d.ts.map +1 -1
  209. package/dist/validation/entry-validator.js +56 -1
  210. package/dist/validation/entry-validator.js.map +1 -1
  211. package/package.json +13 -1
  212. package/dist/asset-store.d.ts +0 -32
  213. package/dist/asset-store.d.ts.map +0 -1
  214. package/dist/asset-store.js +0 -85
  215. package/dist/asset-store.js.map +0 -1
@@ -0,0 +1,26 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ /**
4
+ * Asset Context
5
+ *
6
+ * Carries `media.publicBaseUrl` (see CanopyClientConfig.assetBaseUrl) down to
7
+ * every asset-URL-building component - MediaLibrary, ImageField, and the MDX
8
+ * image dialog. A context (rather than a prop) because the MDX dialog is
9
+ * rendered deep inside MDXEditor's lazy-loaded internals via `imagePlugin`'s
10
+ * `ImageDialog` param, with no prop channel of its own (the same reason
11
+ * `EntryLinkContext` exists for the entry-link toolbar button). Unlike
12
+ * `ApiClientContext`, reading this without a provider is safe and intentional:
13
+ * no provider means root-relative URLs, which is the correct default for the
14
+ * common case (editor and site share an origin).
15
+ */
16
+ import { createContext, useContext, useMemo } from 'react';
17
+ const AssetContext = createContext({});
18
+ export function AssetContextProvider({ baseUrl, children }) {
19
+ const value = useMemo(() => ({ baseUrl }), [baseUrl]);
20
+ return _jsx(AssetContext.Provider, { value: value, children: children });
21
+ }
22
+ /** Safe to call outside a provider - returns `{ baseUrl: undefined }` (root-relative URLs). */
23
+ export function useAssetContext() {
24
+ return useContext(AssetContext);
25
+ }
26
+ //# sourceMappingURL=AssetContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssetContext.js","sourceRoot":"","sources":["../../../src/editor/context/AssetContext.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;;;GAYG;AAEH,OAAc,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAOjE,MAAM,YAAY,GAAG,aAAa,CAAoB,EAAE,CAAC,CAAA;AAMzD,MAAM,UAAU,oBAAoB,CAAC,EAAE,OAAO,EAAE,QAAQ,EAA6B;IACnF,MAAM,KAAK,GAAG,OAAO,CAAoB,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;IACxE,OAAO,KAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAAyB,CAAA;AAChF,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,eAAe;IAC7B,OAAO,UAAU,CAAC,YAAY,CAAC,CAAA;AACjC,CAAC"}
@@ -16,5 +16,6 @@
16
16
  * ```
17
17
  */
18
18
  export { ApiClientProvider, useApiClient, useOptionalApiClient, type ApiClient, type ApiClientProviderProps, } from './ApiClientContext';
19
+ export { AssetContextProvider, useAssetContext, type AssetContextValue, type AssetContextProviderProps, } from './AssetContext';
19
20
  export { EditorStateProvider, useEditorState, useEditorLoading, useEditorModals, useEditorPreview, type EditorState, type EditorStateActions, type EditorStateContextValue, type EditorStateProviderProps, type LoadingState, type ModalState, type PreviewState, } from './EditorStateContext';
20
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/editor/context/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,oBAAoB,EACpB,KAAK,SAAS,EACd,KAAK,sBAAsB,GAC5B,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,wBAAwB,EAC7B,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,sBAAsB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/editor/context/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,oBAAoB,EACpB,KAAK,SAAS,EACd,KAAK,sBAAsB,GAC5B,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,GAC/B,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,wBAAwB,EAC7B,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,sBAAsB,CAAA"}
@@ -16,5 +16,6 @@
16
16
  * ```
17
17
  */
18
18
  export { ApiClientProvider, useApiClient, useOptionalApiClient, } from './ApiClientContext.js';
19
+ export { AssetContextProvider, useAssetContext, } from './AssetContext.js';
19
20
  export { EditorStateProvider, useEditorState, useEditorLoading, useEditorModals, useEditorPreview, } from './EditorStateContext.js';
20
21
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/editor/context/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,oBAAoB,GAGrB,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GAQjB,MAAM,sBAAsB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/editor/context/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,oBAAoB,GAGrB,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EACL,oBAAoB,EACpB,eAAe,GAGhB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GAQjB,MAAM,sBAAsB,CAAA"}
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import type { ImageFieldValue } from '../../config';
3
+ export interface ImageFieldErrors {
4
+ src?: string;
5
+ alt?: string;
6
+ crop?: string;
7
+ }
8
+ export interface ImageFieldProps {
9
+ id?: string;
10
+ label?: string;
11
+ value: ImageFieldValue | undefined;
12
+ onChange: (value: ImageFieldValue | undefined) => void;
13
+ /** "W:H" aspect ratio - when set, picking/uploading a new image opens the crop step before the value commits, and a "Crop" button appears on the filled state. */
14
+ aspect?: string;
15
+ /** Allow empty alt text. Default: required (accessibility). */
16
+ altOptional?: boolean;
17
+ dataCanopyField?: string;
18
+ errors?: ImageFieldErrors;
19
+ }
20
+ export declare const ImageField: React.FC<ImageFieldProps>;
21
+ export default ImageField;
22
+ //# sourceMappingURL=ImageField.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImageField.d.ts","sourceRoot":"","sources":["../../../src/editor/fields/ImageField.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA6C,MAAM,OAAO,CAAA;AASjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAQnD,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,eAAe,GAAG,SAAS,CAAA;IAClC,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,GAAG,SAAS,KAAK,IAAI,CAAA;IACtD,kKAAkK;IAClK,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,+DAA+D;IAC/D,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,MAAM,CAAC,EAAE,gBAAgB,CAAA;CAC1B;AAOD,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAsOhD,CAAA;AAED,eAAe,UAAU,CAAA"}
@@ -0,0 +1,100 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useId, useRef, useState } from 'react';
4
+ import { Alert, Button, Group, Stack, Text, TextInput } from '@mantine/core';
5
+ import { Dropzone } from '@mantine/dropzone';
6
+ import { IconAlertCircle, IconPhoto, IconUpload } from '@tabler/icons-react';
7
+ import { assetUrl } from '../../assets/asset-url.js';
8
+ import { useAssetContext } from '../context/index.js';
9
+ import { CropStep } from '../media/CropStep.js';
10
+ import { parseAspectRatio } from '../media/crop-math.js';
11
+ import { MediaLibrary } from '../media/MediaLibrary.js';
12
+ import { useAssetUpload } from '../media/useAssetUpload.js';
13
+ import { ACCEPTED_IMAGE_MIME_TYPES, MAX_UPLOAD_BYTES } from '../media/upload-constants.js';
14
+ const PREVIEW_WIDTH = 320;
15
+ export const ImageField = ({ id, label, value, onChange, aspect, altOptional, dataCanopyField, errors, }) => {
16
+ const generatedId = useId();
17
+ const inputId = id ?? generatedId;
18
+ const { baseUrl } = useAssetContext();
19
+ const upload = useAssetUpload();
20
+ const [pickerOpen, setPickerOpen] = useState(false);
21
+ const [cropRequest, setCropRequest] = useState(null);
22
+ // Dropzone-level rejections (wrong type/too large) never reach useAssetUpload
23
+ // (Dropzone filters them out before onDrop fires), so they need their own
24
+ // error slot rather than piggybacking on upload.error.
25
+ const [dropError, setDropError] = useState(null);
26
+ const altInputRef = useRef(null);
27
+ const justCommittedRef = useRef(false);
28
+ const aspectRatio = parseAspectRatio(aspect);
29
+ const hasValue = !!value?.src;
30
+ // Focus the alt input right after a new image commits (pick or upload),
31
+ // so the editor's next keystroke goes straight into the field most likely
32
+ // to need attention.
33
+ useEffect(() => {
34
+ if (justCommittedRef.current) {
35
+ justCommittedRef.current = false;
36
+ altInputRef.current?.focus();
37
+ }
38
+ }, [value?.src]);
39
+ const commitAsset = (asset, crop) => {
40
+ justCommittedRef.current = true;
41
+ onChange({
42
+ src: asset.src,
43
+ alt: '',
44
+ ...(asset.width !== undefined ? { width: asset.width } : {}),
45
+ ...(asset.height !== undefined ? { height: asset.height } : {}),
46
+ ...(crop ? { crop } : {}),
47
+ });
48
+ };
49
+ const handleAssetReady = (asset) => {
50
+ setPickerOpen(false);
51
+ if (aspectRatio !== undefined) {
52
+ setCropRequest({ kind: 'new', asset });
53
+ }
54
+ else {
55
+ commitAsset(asset);
56
+ }
57
+ };
58
+ const handleDrop = async (files) => {
59
+ const file = files[0];
60
+ if (!file)
61
+ return;
62
+ const asset = await upload.upload(file);
63
+ if (asset)
64
+ handleAssetReady(asset);
65
+ };
66
+ const handleReject = (rejections) => {
67
+ setDropError(rejections[0]?.errors[0]?.message ?? 'File rejected');
68
+ };
69
+ const handleAltChange = (nextAlt) => {
70
+ if (!value)
71
+ return;
72
+ onChange({ ...value, alt: nextAlt });
73
+ };
74
+ const handleRemove = () => {
75
+ onChange(undefined);
76
+ };
77
+ const handleCropConfirm = (rect) => {
78
+ if (cropRequest?.kind === 'new') {
79
+ commitAsset(cropRequest.asset, rect);
80
+ }
81
+ else if (cropRequest?.kind === 'existing' && value) {
82
+ onChange({ ...value, crop: rect });
83
+ }
84
+ setCropRequest(null);
85
+ };
86
+ const cropImageSrc = cropRequest?.kind === 'new'
87
+ ? assetUrl({ src: cropRequest.asset.src }, { baseUrl })
88
+ : cropRequest?.kind === 'existing' && value
89
+ ? assetUrl({ src: value.src }, { baseUrl })
90
+ : '';
91
+ const cropInitial = cropRequest?.kind === 'existing' ? value?.crop : undefined;
92
+ return (_jsxs(Stack, { gap: 4, "data-canopy-field": dataCanopyField, "data-testid": `image-field-${dataCanopyField}`, children: [label && (_jsx(Text, { size: "sm", fw: 500, children: label })), !hasValue ? (_jsxs(Stack, { gap: "xs", children: [_jsx(Dropzone, { onDrop: (files) => void handleDrop(files), onReject: handleReject, maxSize: MAX_UPLOAD_BYTES, accept: ACCEPTED_IMAGE_MIME_TYPES, loading: upload.uploading, multiple: false, "data-testid": `image-field-dropzone-${dataCanopyField}`, children: _jsxs(Group, { justify: "center", gap: "xs", py: "xs", style: { pointerEvents: 'none' }, children: [_jsx(IconUpload, { size: 18 }), _jsx(Text, { size: "xs", children: "Drop an image here, or click to browse" })] }) }), _jsx(Group, { justify: "center", children: _jsx(Button, { variant: "light", size: "xs", leftSection: _jsx(IconPhoto, { size: 14 }), onClick: () => setPickerOpen(true), "data-testid": `image-field-browse-library-${dataCanopyField}`, children: "Browse library" }) }), (upload.error || dropError) && (_jsx(Alert, { icon: _jsx(IconAlertCircle, { size: 16 }), color: "red", children: upload.error || dropError })), errors?.src && (_jsx(Text, { size: "xs", c: "red", children: errors.src }))] })) : (_jsxs(Stack, { gap: "xs", children: [_jsx("img", { src: assetUrl({ src: value.src }, { width: PREVIEW_WIDTH, crop: value.crop, baseUrl }), alt: value.alt, style: {
93
+ maxWidth: PREVIEW_WIDTH,
94
+ maxHeight: PREVIEW_WIDTH,
95
+ borderRadius: 'var(--mantine-radius-sm)',
96
+ display: 'block',
97
+ } }), errors?.src && (_jsx(Text, { size: "xs", c: "red", children: errors.src })), _jsx(TextInput, { id: inputId, ref: altInputRef, label: "Alt text", required: !altOptional, value: value.alt, onChange: (event) => handleAltChange(event.currentTarget.value), error: errors?.alt, size: "sm", "data-testid": `image-field-alt-${dataCanopyField}` }), _jsxs(Group, { gap: "xs", children: [_jsx(Button, { variant: "light", size: "xs", onClick: () => setPickerOpen(true), "data-testid": `image-field-replace-${dataCanopyField}`, children: "Replace" }), aspectRatio !== undefined && (_jsx(Button, { variant: "light", size: "xs", onClick: () => setCropRequest({ kind: 'existing' }), "data-testid": `image-field-crop-${dataCanopyField}`, children: "Crop" })), _jsx(Button, { variant: "subtle", color: "red", size: "xs", onClick: handleRemove, "data-testid": `image-field-remove-${dataCanopyField}`, children: "Remove" })] }), errors?.crop && (_jsx(Text, { size: "xs", c: "red", children: errors.crop }))] })), _jsx(MediaLibrary, { opened: pickerOpen, onClose: () => setPickerOpen(false), mode: "picker", onSelect: handleAssetReady }), aspectRatio !== undefined && (_jsx(CropStep, { opened: cropRequest !== null, onClose: () => setCropRequest(null), imageSrc: cropImageSrc, aspect: aspectRatio, initialCrop: cropInitial, onConfirm: handleCropConfirm }))] }));
98
+ };
99
+ export default ImageField;
100
+ //# sourceMappingURL=ImageField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImageField.js","sourceRoot":"","sources":["../../../src/editor/fields/ImageField.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"MarkdownField.d.ts","sourceRoot":"","sources":["../../../src/editor/fields/MarkdownField.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA0D,MAAM,OAAO,CAAA;AAO9E,MAAM,WAAW,kBAAkB;IACjC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAiKD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA2CtD,CAAA;AAED,eAAe,aAAa,CAAA"}
1
+ {"version":3,"file":"MarkdownField.d.ts","sourceRoot":"","sources":["../../../src/editor/fields/MarkdownField.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA0D,MAAM,OAAO,CAAA;AAU9E,MAAM,WAAW,kBAAkB;IACjC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAmLD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA+DtD,CAAA;AAED,eAAe,aAAa,CAAA"}
@@ -3,14 +3,29 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
3
3
  import React, { Suspense, useId, useRef, useCallback, useEffect } from 'react';
4
4
  import { Text, Textarea } from '@mantine/core';
5
5
  import { InsertEntryLink } from './entry-link/index.js';
6
+ import { MdxImageDialog } from './MdxImageDialog.js';
7
+ import { useApiClient } from '../context/index.js';
8
+ import { uploadAsset } from '../media/upload-asset.js';
6
9
  const MDXEditorLazy = React.lazy(async () => {
7
- const [{ MDXEditor }, { headingsPlugin, listsPlugin, quotePlugin, thematicBreakPlugin, markdownShortcutPlugin, linkPlugin, linkDialogPlugin, imagePlugin, tablePlugin, toolbarPlugin, codeBlockPlugin, codeMirrorPlugin, BoldItalicUnderlineToggles, BlockTypeSelect, ListsToggle, CreateLink, InsertImage, InsertTable, InsertThematicBreak, CodeToggle, InsertCodeBlock, UndoRedo, Separator, insertMarkdown$, usePublisher, },] = await Promise.all([import('@mdxeditor/editor'), import('@mdxeditor/editor')]);
10
+ const [{ MDXEditor }, { headingsPlugin, listsPlugin, quotePlugin, thematicBreakPlugin, markdownShortcutPlugin, linkPlugin, linkDialogPlugin, imagePlugin, tablePlugin, toolbarPlugin, codeBlockPlugin, codeMirrorPlugin, BoldItalicUnderlineToggles, BlockTypeSelect, ListsToggle, CreateLink, InsertImage, InsertTable, InsertThematicBreak, CodeToggle, InsertCodeBlock, UndoRedo, Separator, insertMarkdown$, usePublisher, useCellValues, saveImage$, closeImageDialog$, imageDialogState$, },] = await Promise.all([import('@mdxeditor/editor'), import('@mdxeditor/editor')]);
8
11
  /** Toolbar wrapper that provides insertMarkdown to InsertEntryLink */
9
12
  const EntryLinkToolbarButton = () => {
10
13
  const insertMarkdown = usePublisher(insertMarkdown$);
11
14
  return _jsx(InsertEntryLink, { onInsert: insertMarkdown });
12
15
  };
13
- const WrappedEditor = ({ markdown, onChange, editorRef }) => {
16
+ /**
17
+ * Bridges mdxeditor's realm cells (only reachable once this lazy chunk has
18
+ * loaded) into MdxImageDialog's plain-props interface, so that component
19
+ * itself never imports `@mdxeditor/editor` at runtime. Same pattern as
20
+ * `EntryLinkToolbarButton` above.
21
+ */
22
+ const MdxImageDialogBridge = () => {
23
+ const [state] = useCellValues(imageDialogState$);
24
+ const saveImage = usePublisher(saveImage$);
25
+ const closeImageDialog = usePublisher(closeImageDialog$);
26
+ return _jsx(MdxImageDialog, { state: state, onSave: saveImage, onClose: closeImageDialog });
27
+ };
28
+ const WrappedEditor = ({ markdown, onChange, editorRef, imageUploadHandler }) => {
14
29
  return (_jsx(MDXEditor, { ref: editorRef, markdown: markdown, onChange: onChange, plugins: [
15
30
  headingsPlugin(),
16
31
  listsPlugin(),
@@ -19,7 +34,7 @@ const MDXEditorLazy = React.lazy(async () => {
19
34
  markdownShortcutPlugin(),
20
35
  linkPlugin(),
21
36
  linkDialogPlugin(),
22
- imagePlugin(),
37
+ imagePlugin({ imageUploadHandler, ImageDialog: MdxImageDialogBridge }),
23
38
  tablePlugin(),
24
39
  codeBlockPlugin({ defaultCodeBlockLanguage: '' }),
25
40
  codeMirrorPlugin({
@@ -86,6 +101,17 @@ export const MarkdownField = ({ id, label, value, onChange, dataCanopyField, })
86
101
  const inputId = id ?? generatedId;
87
102
  const editorRef = useRef(null);
88
103
  const lastExternalValue = useRef(value);
104
+ const apiClient = useApiClient();
105
+ // Drives both MDXEditor's own drag/drop/paste upload flow and the Upload
106
+ // tab in our custom image dialog (MdxImageDialog) via the SAME presign/
107
+ // finalize-or-proxied pipeline used everywhere else in the editor (see
108
+ // media/upload-asset.ts). Stable across renders (memoized on the API
109
+ // client, which ApiClientProvider itself memoizes) so MDXEditor's plugin
110
+ // list doesn't churn on every keystroke.
111
+ const imageUploadHandler = useCallback(async (file) => {
112
+ const asset = await uploadAsset(apiClient, file);
113
+ return asset.src;
114
+ }, [apiClient]);
89
115
  // Sync external value changes into the editor (e.g., undo, reset, load)
90
116
  useEffect(() => {
91
117
  if (value !== lastExternalValue.current && editorRef.current) {
@@ -97,7 +123,7 @@ export const MarkdownField = ({ id, label, value, onChange, dataCanopyField, })
97
123
  lastExternalValue.current = newValue;
98
124
  onChange(newValue);
99
125
  }, [onChange]);
100
- return (_jsxs("div", { id: inputId, "data-canopy-field": dataCanopyField, className: "canopy-markdown-field", children: [label && (_jsx(Text, { size: "sm", fw: 500, mb: 4, children: label })), _jsx(EditorContentStyles, {}), _jsx("div", { style: editorWrapperStyle, children: _jsx(Suspense, { fallback: _jsx(FallbackTextarea, { value: value, onChange: onChange }), children: _jsx(MDXEditorLazy, { markdown: value, onChange: handleChange, editorRef: editorRef }) }) })] }));
126
+ return (_jsxs("div", { id: inputId, "data-canopy-field": dataCanopyField, className: "canopy-markdown-field", children: [label && (_jsx(Text, { size: "sm", fw: 500, mb: 4, children: label })), _jsx(EditorContentStyles, {}), _jsx("div", { style: editorWrapperStyle, children: _jsx(Suspense, { fallback: _jsx(FallbackTextarea, { value: value, onChange: onChange }), children: _jsx(MDXEditorLazy, { markdown: value, onChange: handleChange, editorRef: editorRef, imageUploadHandler: imageUploadHandler }) }) })] }));
101
127
  };
102
128
  export default MarkdownField;
103
129
  //# sourceMappingURL=MarkdownField.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MarkdownField.js","sourceRoot":"","sources":["../../../src/editor/fields/MarkdownField.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAE9E,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAG9C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAU9C,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;IAC1C,MAAM,CACJ,EAAE,SAAS,EAAE,EACb,EACE,cAAc,EACd,WAAW,EACX,WAAW,EACX,mBAAmB,EACnB,sBAAsB,EACtB,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,0BAA0B,EAC1B,eAAe,EACf,WAAW,EACX,UAAU,EACV,WAAW,EACX,WAAW,EACX,mBAAmB,EACnB,UAAU,EACV,eAAe,EACf,QAAQ,EACR,SAAS,EACT,eAAe,EACf,YAAY,GACb,EACF,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAA;IAEjF,sEAAsE;IACtE,MAAM,sBAAsB,GAAa,GAAG,EAAE;QAC5C,MAAM,cAAc,GAAG,YAAY,CAAC,eAAe,CAAC,CAAA;QACpD,OAAO,KAAC,eAAe,IAAC,QAAQ,EAAE,cAAc,GAAI,CAAA;IACtD,CAAC,CAAA;IAED,MAAM,aAAa,GAId,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE;QACzC,OAAO,CACL,KAAC,SAAS,IACR,GAAG,EAAE,SAAS,EACd,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE;gBACP,cAAc,EAAE;gBAChB,WAAW,EAAE;gBACb,WAAW,EAAE;gBACb,mBAAmB,EAAE;gBACrB,sBAAsB,EAAE;gBACxB,UAAU,EAAE;gBACZ,gBAAgB,EAAE;gBAClB,WAAW,EAAE;gBACb,WAAW,EAAE;gBACb,eAAe,CAAC,EAAE,wBAAwB,EAAE,EAAE,EAAE,CAAC;gBACjD,gBAAgB,CAAC;oBACf,kBAAkB,EAAE;wBAClB,EAAE,EAAE,YAAY;wBAChB,EAAE,EAAE,YAAY;wBAChB,EAAE,EAAE,YAAY;wBAChB,GAAG,EAAE,KAAK;wBACV,GAAG,EAAE,KAAK;wBACV,GAAG,EAAE,KAAK;wBACV,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,MAAM;wBACZ,MAAM,EAAE,QAAQ;wBAChB,IAAI,EAAE,MAAM;wBACZ,QAAQ,EAAE,UAAU;qBACrB;iBACF,CAAC;gBACF,aAAa,CAAC;oBACZ,eAAe,EAAE,GAAG,EAAE,CAAC,CACrB,8BACE,KAAC,QAAQ,KAAG,EACZ,KAAC,SAAS,KAAG,EACb,KAAC,0BAA0B,KAAG,EAC9B,KAAC,UAAU,KAAG,EACd,KAAC,SAAS,KAAG,EACb,KAAC,eAAe,KAAG,EACnB,KAAC,SAAS,KAAG,EACb,KAAC,WAAW,KAAG,EACf,KAAC,SAAS,KAAG,EACb,KAAC,UAAU,KAAG,EACd,KAAC,sBAAsB,KAAG,EAC1B,KAAC,WAAW,KAAG,EACf,KAAC,WAAW,KAAG,EACf,KAAC,mBAAmB,KAAG,EACvB,KAAC,eAAe,KAAG,IAClB,CACJ;iBACF,CAAC;aACH,EACD,wBAAwB,EAAC,oBAAoB,GAC7C,CACH,CAAA;IACH,CAAC,CAAA;IAED,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,CAAA;AACnC,CAAC,CAAC,CAAA;AAEF,sHAAsH;AACtH,MAAM,kBAAkB,GAAwB;IAC9C,UAAU,EAAE,MAAM;IAClB,MAAM,EAAE,gDAAgD;IACxD,YAAY,EAAE,+BAA+B;IAC7C,QAAQ,EAAE,QAAQ;CACnB,CAAA;AAED;;;GAGG;AACH,MAAM,mBAAmB,GAAa,GAAG,EAAE,CAAC,CAC1C,0BAAQ;;;;;;;;;;;;;;;;;;;;;;;GAuBP,GAAS,CACX,CAAA;AAED,MAAM,gBAAgB,GAA6D,CAAC,EAClF,KAAK,EACL,QAAQ,GACT,EAAE,EAAE,CAAC,CACJ,KAAC,QAAQ,IACP,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,EAChD,WAAW,EAAC,4BAA4B,EACxC,QAAQ,QACR,OAAO,EAAE,CAAC,EACV,IAAI,EAAC,IAAI,EACT,QAAQ,SACR,CACH,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAiC,CAAC,EAC1D,EAAE,EACF,KAAK,EACL,KAAK,EACL,QAAQ,EACR,eAAe,GAChB,EAAE,EAAE;IACH,MAAM,WAAW,GAAG,KAAK,EAAE,CAAA;IAC3B,MAAM,OAAO,GAAG,EAAE,IAAI,WAAW,CAAA;IACjC,MAAM,SAAS,GAAG,MAAM,CAAmB,IAAI,CAAC,CAAA;IAChD,MAAM,iBAAiB,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAEvC,wEAAwE;IACxE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,KAAK,KAAK,iBAAiB,CAAC,OAAO,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;YAC7D,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;YACpC,iBAAiB,CAAC,OAAO,GAAG,KAAK,CAAA;QACnC,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;IAEX,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,QAAgB,EAAE,EAAE;QACnB,iBAAiB,CAAC,OAAO,GAAG,QAAQ,CAAA;QACpC,QAAQ,CAAC,QAAQ,CAAC,CAAA;IACpB,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAA;IAED,OAAO,CACL,eAAK,EAAE,EAAE,OAAO,uBAAqB,eAAe,EAAE,SAAS,EAAC,uBAAuB,aACpF,KAAK,IAAI,CACR,KAAC,IAAI,IAAC,IAAI,EAAC,IAAI,EAAC,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,YAC3B,KAAK,GACD,CACR,EACD,KAAC,mBAAmB,KAAG,EACvB,cAAK,KAAK,EAAE,kBAAkB,YAC5B,KAAC,QAAQ,IAAC,QAAQ,EAAE,KAAC,gBAAgB,IAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,GAAI,YACxE,KAAC,aAAa,IAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,GAAI,GACvE,GACP,IACF,CACP,CAAA;AACH,CAAC,CAAA;AAED,eAAe,aAAa,CAAA"}
1
+ {"version":3,"file":"MarkdownField.js","sourceRoot":"","sources":["../../../src/editor/fields/MarkdownField.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import type { EditingImageDialogState, InactiveImageDialogState, NewImageDialogState, SaveImageParameters } from '@mdxeditor/editor';
3
+ export type MdxImageDialogState = InactiveImageDialogState | NewImageDialogState | EditingImageDialogState;
4
+ export interface MdxImageDialogProps {
5
+ state: MdxImageDialogState;
6
+ onSave: (params: SaveImageParameters) => void;
7
+ onClose: () => void;
8
+ }
9
+ /**
10
+ * Custom MDXEditor image dialog (Upload / From library / By URL), replacing
11
+ * the stock upload-or-URL dialog. Wired in via `imagePlugin({ ImageDialog })`
12
+ * in MarkdownField.tsx.
13
+ */
14
+ export declare const MdxImageDialog: React.FC<MdxImageDialogProps>;
15
+ export default MdxImageDialog;
16
+ //# sourceMappingURL=MdxImageDialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MdxImageDialog.d.ts","sourceRoot":"","sources":["../../../src/editor/fields/MdxImageDialog.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAA;AAalD,OAAO,KAAK,EACV,uBAAuB,EACvB,wBAAwB,EACxB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,mBAAmB,CAAA;AAO1B,MAAM,MAAM,mBAAmB,GAC3B,wBAAwB,GACxB,mBAAmB,GACnB,uBAAuB,CAAA;AAE3B,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,mBAAmB,CAAA;IAC1B,MAAM,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAA;IAC7C,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAMD;;;;GAIG;AACH,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA+JxD,CAAA;AAED,eAAe,cAAc,CAAA"}
@@ -0,0 +1,73 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState } from 'react';
4
+ import { Alert, Button, Group, Modal, Progress, Stack, Tabs, Text, TextInput } from '@mantine/core';
5
+ import { Dropzone } from '@mantine/dropzone';
6
+ import { IconAlertCircle, IconUpload } from '@tabler/icons-react';
7
+ import { MediaLibraryBody } from '../media/MediaLibraryBody.js';
8
+ import { useAssetUpload } from '../media/useAssetUpload.js';
9
+ import { ACCEPTED_IMAGE_MIME_TYPES, MAX_UPLOAD_BYTES } from '../media/upload-constants.js';
10
+ const LIBRARY_PANEL_HEIGHT = 360;
11
+ /**
12
+ * Custom MDXEditor image dialog (Upload / From library / By URL), replacing
13
+ * the stock upload-or-URL dialog. Wired in via `imagePlugin({ ImageDialog })`
14
+ * in MarkdownField.tsx.
15
+ */
16
+ export const MdxImageDialog = ({ state, onSave, onClose }) => {
17
+ const [tab, setTab] = useState('upload');
18
+ const [altText, setAltText] = useState('');
19
+ const [urlValue, setUrlValue] = useState('');
20
+ const [dropError, setDropError] = useState(null);
21
+ const upload = useAssetUpload();
22
+ const opened = state.type !== 'inactive';
23
+ useEffect(() => {
24
+ if (state.type === 'editing') {
25
+ setAltText(state.initialValues.altText ?? '');
26
+ setUrlValue(state.initialValues.src ?? '');
27
+ // Editing an existing image: show its current src/alt on the URL tab
28
+ // rather than defaulting to Upload, which would suggest replacing it.
29
+ setTab('url');
30
+ }
31
+ else {
32
+ setAltText('');
33
+ setUrlValue('');
34
+ setTab('upload');
35
+ }
36
+ setDropError(null);
37
+ upload.reset();
38
+ // Reset local state whenever the dialog's target state changes identity
39
+ // (opened for a new insert, opened to edit a different node, or closed).
40
+ // eslint-disable-next-line react-hooks/exhaustive-deps
41
+ }, [state]);
42
+ const handleSave = (src) => {
43
+ onSave({ src, altText });
44
+ onClose();
45
+ };
46
+ const handleDrop = async (files) => {
47
+ const file = files[0];
48
+ if (!file)
49
+ return;
50
+ const asset = await upload.upload(file);
51
+ if (asset)
52
+ handleSave(asset.src);
53
+ };
54
+ const handleReject = (rejections) => {
55
+ setDropError(rejections[0]?.errors[0]?.message ?? 'File rejected');
56
+ };
57
+ const handlePickFromLibrary = (asset) => {
58
+ handleSave(asset.src);
59
+ };
60
+ const handleUrlSubmit = () => {
61
+ const trimmed = urlValue.trim();
62
+ if (!trimmed)
63
+ return;
64
+ handleSave(trimmed);
65
+ };
66
+ return (_jsx(Modal, { opened: opened, onClose: onClose, title: "Insert image", size: "lg", overlayProps: { blur: 2 }, "data-testid": "mdx-image-dialog", children: _jsxs(Stack, { gap: "sm", children: [_jsx(TextInput, { label: "Alt text", value: altText, onChange: (event) => setAltText(event.currentTarget.value), "data-testid": "mdx-image-dialog-alt" }), _jsxs(Tabs, { value: tab, onChange: (next) => {
67
+ if (next)
68
+ setTab(next);
69
+ }, children: [_jsxs(Tabs.List, { children: [_jsx(Tabs.Tab, { value: "upload", "data-testid": "mdx-image-dialog-tab-upload", children: "Upload" }), _jsx(Tabs.Tab, { value: "library", "data-testid": "mdx-image-dialog-tab-library", children: "From library" }), _jsx(Tabs.Tab, { value: "url", "data-testid": "mdx-image-dialog-tab-url", children: "By URL" })] }), _jsx(Tabs.Panel, { value: "upload", pt: "sm", children: _jsxs(Stack, { gap: "xs", children: [_jsx(Dropzone, { onDrop: (files) => void handleDrop(files), onReject: handleReject, maxSize: MAX_UPLOAD_BYTES, accept: ACCEPTED_IMAGE_MIME_TYPES, loading: upload.uploading, multiple: false, "data-testid": "mdx-image-dialog-dropzone", children: _jsxs(Group, { justify: "center", gap: "xs", py: "sm", style: { pointerEvents: 'none' }, children: [_jsx(IconUpload, { size: 20 }), _jsx(Text, { size: "sm", children: "Drop an image here, or click to browse" })] }) }), upload.uploading &&
70
+ (upload.progress !== null ? (_jsx(Progress, { value: upload.progress * 100, size: "sm" })) : (_jsx(Progress, { value: 100, size: "sm", animated: true }))), (upload.error || dropError) && (_jsx(Alert, { icon: _jsx(IconAlertCircle, { size: 16 }), color: "red", children: upload.error || dropError }))] }) }), _jsx(Tabs.Panel, { value: "library", pt: "sm", children: _jsx("div", { style: { height: LIBRARY_PANEL_HEIGHT }, children: _jsx(MediaLibraryBody, { opened: tab === 'library', mode: "picker", onSelect: handlePickFromLibrary }) }) }), _jsx(Tabs.Panel, { value: "url", pt: "sm", children: _jsxs(Stack, { gap: "xs", children: [_jsx(TextInput, { label: "Image URL", placeholder: "https://example.com/image.png", value: urlValue, onChange: (event) => setUrlValue(event.currentTarget.value), "data-testid": "mdx-image-dialog-url" }), _jsx(Group, { justify: "flex-end", children: _jsx(Button, { onClick: handleUrlSubmit, disabled: !urlValue.trim(), "data-testid": "mdx-image-dialog-url-submit", children: "Insert" }) })] }) })] }), _jsx(Group, { justify: "flex-end", children: _jsx(Button, { variant: "default", onClick: onClose, children: "Cancel" }) })] }) }));
71
+ };
72
+ export default MdxImageDialog;
73
+ //# sourceMappingURL=MdxImageDialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MdxImageDialog.js","sourceRoot":"","sources":["../../../src/editor/fields/MdxImageDialog.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import type { AssetRecord } from '../../api';
3
+ export interface AssetCardProps {
4
+ asset: AssetRecord;
5
+ /** `media.publicBaseUrl` - see AssetContext. */
6
+ baseUrl?: string;
7
+ /** Present in picker mode - clicking the card selects the asset. */
8
+ onSelect?: (asset: AssetRecord) => void;
9
+ /** Present only for admins in manage mode - renders the trash button. */
10
+ onDelete?: (asset: AssetRecord) => void;
11
+ }
12
+ /**
13
+ * One thumbnail card in the MediaLibrary grid. Raster and svg assets both go
14
+ * through `assetUrl()` unmodified - for svg (a static, non-transform src)
15
+ * `assetUrl` ignores the `width` option and just applies `baseUrl`, which is
16
+ * exactly the behavior wanted here. PDFs have no image to preview, so they
17
+ * render a file-type icon instead.
18
+ */
19
+ export declare const AssetCard: React.FC<AssetCardProps>;
20
+ export default AssetCard;
21
+ //# sourceMappingURL=AssetCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssetCard.d.ts","sourceRoot":"","sources":["../../../src/editor/media/AssetCard.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAG5C,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,WAAW,CAAA;IAClB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAA;IACvC,yEAAyE;IACzE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAA;CACxC;AAID;;;;;;GAMG;AACH,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CA2E9C,CAAA;AAED,eAAe,SAAS,CAAA"}
@@ -0,0 +1,41 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { ActionIcon, Card, Text, Tooltip } from '@mantine/core';
4
+ import { IconFileTypePdf, IconTrash } from '@tabler/icons-react';
5
+ import { assetUrl } from '../../assets/asset-url.js';
6
+ const THUMBNAIL_WIDTH = 160;
7
+ /**
8
+ * One thumbnail card in the MediaLibrary grid. Raster and svg assets both go
9
+ * through `assetUrl()` unmodified - for svg (a static, non-transform src)
10
+ * `assetUrl` ignores the `width` option and just applies `baseUrl`, which is
11
+ * exactly the behavior wanted here. PDFs have no image to preview, so they
12
+ * render a file-type icon instead.
13
+ */
14
+ export const AssetCard = ({ asset, baseUrl, onSelect, onDelete }) => {
15
+ const uploadedDate = new Date(asset.uploadedAt).toLocaleDateString();
16
+ const handleKeyDown = (event) => {
17
+ if (!onSelect)
18
+ return;
19
+ if (event.key === 'Enter' || event.key === ' ') {
20
+ event.preventDefault();
21
+ onSelect(asset);
22
+ }
23
+ };
24
+ return (_jsxs(Card, { withBorder: true, radius: "md", padding: "xs", "data-testid": `asset-card-${asset.hash32}`, style: { position: 'relative', cursor: onSelect ? 'pointer' : undefined }, onClick: onSelect ? () => onSelect(asset) : undefined,
25
+ // Selection is otherwise a bare click handler on a non-interactive
26
+ // element, unreachable from the keyboard - role="button" + tabIndex
27
+ // makes it focusable and announced correctly, and onKeyDown mirrors
28
+ // native <button> Enter/Space activation.
29
+ role: onSelect ? 'button' : undefined, tabIndex: onSelect ? 0 : undefined, onKeyDown: onSelect ? handleKeyDown : undefined, children: [onDelete && (_jsx(ActionIcon, { variant: "filled", color: "red", size: "sm", radius: "xl", style: { position: 'absolute', top: 4, right: 4, zIndex: 1 }, "aria-label": `Delete ${asset.filename}`, "data-testid": `asset-card-delete-${asset.hash32}`, onClick: (event) => {
30
+ event.stopPropagation();
31
+ onDelete(asset);
32
+ }, children: _jsx(IconTrash, { size: 14 }) })), _jsx(Card.Section, { children: asset.kind === 'pdf' ? (_jsx("div", { style: {
33
+ height: 100,
34
+ display: 'flex',
35
+ alignItems: 'center',
36
+ justifyContent: 'center',
37
+ background: 'var(--mantine-color-gray-1)',
38
+ }, children: _jsx(IconFileTypePdf, { size: 40, stroke: 1.5 }) })) : (_jsx("img", { src: assetUrl(asset, { width: THUMBNAIL_WIDTH, baseUrl }), alt: asset.filename, style: { width: '100%', height: 100, objectFit: 'cover', display: 'block' } })) }), _jsx(Tooltip, { label: asset.filename, openDelay: 400, children: _jsx(Text, { size: "xs", fw: 500, truncate: true, mt: 4, children: asset.slug }) }), _jsx(Text, { size: "xs", c: "dimmed", children: uploadedDate })] }));
39
+ };
40
+ export default AssetCard;
41
+ //# sourceMappingURL=AssetCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssetCard.js","sourceRoot":"","sources":["../../../src/editor/media/AssetCard.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import type { CropRect } from '../../assets/transform-directives';
3
+ export interface CropStepProps {
4
+ opened: boolean;
5
+ onClose: () => void;
6
+ /** Full-frame image src to crop - `assetUrl()` with no crop directive, so the user always crops the original frame. */
7
+ imageSrc: string;
8
+ /** Numeric aspect ratio (width/height) parsed from the field config's "W:H" string. */
9
+ aspect: number;
10
+ /** Existing crop rect, if re-cropping - seeds react-easy-crop's initial selection (best effort). */
11
+ initialCrop?: CropRect;
12
+ onConfirm: (rect: CropRect) => void;
13
+ }
14
+ /**
15
+ * react-easy-crop wrapped in a Modal for the ImageField crop step. Percentage
16
+ * -> normalized-rect conversion is delegated to crop-math.ts's pure,
17
+ * independently-unit-tested `cropAreaPercentToRect`.
18
+ *
19
+ * The pan/zoom/pending-selection state lives in `CropStepBody`, mounted only
20
+ * while `opened` and keyed on `imageSrc` - so a fresh crop session always
21
+ * starts from fresh state (React remounts on key change) without an effect
22
+ * that would otherwise need to call `setState` synchronously to reset it.
23
+ */
24
+ export declare const CropStep: React.FC<CropStepProps>;
25
+ export default CropStep;
26
+ //# sourceMappingURL=CropStep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CropStep.d.ts","sourceRoot":"","sources":["../../../src/editor/media/CropStep.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmB,MAAM,OAAO,CAAA;AAKvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAA;AAGjE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,OAAO,CAAA;IACf,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,uHAAuH;IACvH,QAAQ,EAAE,MAAM,CAAA;IAChB,uFAAuF;IACvF,MAAM,EAAE,MAAM,CAAA;IACd,oGAAoG;IACpG,WAAW,CAAC,EAAE,QAAQ,CAAA;IACtB,SAAS,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAA;CACpC;AAMD;;;;;;;;;GASG;AACH,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA6B5C,CAAA;AAqED,eAAe,QAAQ,CAAA"}
@@ -0,0 +1,38 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ import { Button, Group, Modal, Slider, Stack, Text } from '@mantine/core';
5
+ import Cropper from 'react-easy-crop';
6
+ import { cropAreaPercentToRect, cropRectToAreaPercent } from './crop-math.js';
7
+ const MIN_ZOOM = 1;
8
+ const MAX_ZOOM = 3;
9
+ const ZOOM_STEP = 0.05;
10
+ /**
11
+ * react-easy-crop wrapped in a Modal for the ImageField crop step. Percentage
12
+ * -> normalized-rect conversion is delegated to crop-math.ts's pure,
13
+ * independently-unit-tested `cropAreaPercentToRect`.
14
+ *
15
+ * The pan/zoom/pending-selection state lives in `CropStepBody`, mounted only
16
+ * while `opened` and keyed on `imageSrc` - so a fresh crop session always
17
+ * starts from fresh state (React remounts on key change) without an effect
18
+ * that would otherwise need to call `setState` synchronously to reset it.
19
+ */
20
+ export const CropStep = ({ opened, onClose, imageSrc, aspect, initialCrop, onConfirm, }) => {
21
+ return (_jsx(Modal, { opened: opened, onClose: onClose, title: "Crop image", size: "lg", overlayProps: { blur: 2 }, "data-testid": "crop-step-modal", children: opened && (_jsx(CropStepBody, { imageSrc: imageSrc, aspect: aspect, initialCrop: initialCrop, onConfirm: onConfirm, onClose: onClose }, imageSrc)) }));
22
+ };
23
+ const CropStepBody = ({ imageSrc, aspect, initialCrop, onConfirm, onClose, }) => {
24
+ const [crop, setCrop] = useState({ x: 0, y: 0 });
25
+ const [zoom, setZoom] = useState(1);
26
+ const [pendingArea, setPendingArea] = useState(null);
27
+ const handleConfirm = () => {
28
+ if (!pendingArea)
29
+ return;
30
+ const rect = cropAreaPercentToRect(pendingArea);
31
+ if (rect)
32
+ onConfirm(rect);
33
+ };
34
+ const initialCroppedAreaPercentages = initialCrop ? cropRectToAreaPercent(initialCrop) : undefined;
35
+ return (_jsxs(Stack, { gap: "md", children: [_jsx("div", { style: { position: 'relative', width: '100%', height: 360, background: '#000' }, children: _jsx(Cropper, { image: imageSrc, crop: crop, zoom: zoom, aspect: aspect, initialCroppedAreaPercentages: initialCroppedAreaPercentages, onCropChange: setCrop, onZoomChange: setZoom, onCropComplete: (croppedArea) => setPendingArea(croppedArea) }) }), _jsxs(Group, { gap: "sm", align: "center", children: [_jsx(Text, { size: "sm", w: 50, children: "Zoom" }), _jsx(Slider, { style: { flex: 1 }, min: MIN_ZOOM, max: MAX_ZOOM, step: ZOOM_STEP, value: zoom, onChange: setZoom, label: (value) => `${value.toFixed(2)}x` })] }), _jsxs(Group, { justify: "flex-end", children: [_jsx(Button, { variant: "default", onClick: onClose, children: "Cancel" }), _jsx(Button, { onClick: handleConfirm, disabled: !pendingArea, "data-testid": "crop-step-apply", children: "Apply crop" })] })] }));
36
+ };
37
+ export default CropStep;
38
+ //# sourceMappingURL=CropStep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CropStep.js","sourceRoot":"","sources":["../../../src/editor/media/CropStep.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import type { AssetRecord } from '../../api';
3
+ export interface MediaLibraryProps {
4
+ opened: boolean;
5
+ onClose: () => void;
6
+ /**
7
+ * 'manage': right-side Drawer opened from the EditorSidebar Settings menu.
8
+ * 'picker': Modal used by ImageField ("Browse library"/"Replace") and the
9
+ * MDX image dialog's "From library" tab.
10
+ */
11
+ mode: 'manage' | 'picker';
12
+ /** Required in picker mode - called with the chosen asset when a card is clicked. */
13
+ onSelect?: (asset: AssetRecord) => void;
14
+ }
15
+ /**
16
+ * One component, two presentations, sharing the same grid/upload/filter/
17
+ * pagination/delete core (MediaLibraryBody) - see
18
+ * .claude/future-tasks/assets-media-system.md "MediaManager design".
19
+ */
20
+ export declare const MediaLibrary: React.FC<MediaLibraryProps>;
21
+ export default MediaLibrary;
22
+ //# sourceMappingURL=MediaLibrary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaLibrary.d.ts","sourceRoot":"","sources":["../../../src/editor/media/MediaLibrary.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAG5C,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,OAAO,CAAA;IACf,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB;;;;OAIG;IACH,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAA;IACzB,qFAAqF;IACrF,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAA;CACxC;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAqCpD,CAAA;AAED,eAAe,YAAY,CAAA"}