@vertebr/react 0.11.0 → 0.13.0

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 (34) hide show
  1. package/dist/components/admin/AdminContent.d.ts.map +1 -1
  2. package/dist/components/admin/AdminContent.js +7 -10
  3. package/dist/components/admin/VertebrAdmin.d.ts.map +1 -1
  4. package/dist/components/admin/VertebrAdmin.js +6 -4
  5. package/dist/components/config/DescriptionInput.d.ts +3 -1
  6. package/dist/components/config/DescriptionInput.d.ts.map +1 -1
  7. package/dist/components/config/DescriptionInput.js +2 -2
  8. package/dist/components/config/DocumentAttachmentField.d.ts +17 -0
  9. package/dist/components/config/DocumentAttachmentField.d.ts.map +1 -0
  10. package/dist/components/config/DocumentAttachmentField.js +32 -0
  11. package/dist/components/config/ImagePickerModal.d.ts +12 -1
  12. package/dist/components/config/ImagePickerModal.d.ts.map +1 -1
  13. package/dist/components/config/ImagePickerModal.js +52 -23
  14. package/dist/components/config/MarkdownDocumentModal.d.ts +19 -0
  15. package/dist/components/config/MarkdownDocumentModal.d.ts.map +1 -0
  16. package/dist/components/config/MarkdownDocumentModal.js +34 -0
  17. package/dist/components/config/form/ConfigField.d.ts.map +1 -1
  18. package/dist/components/config/form/ConfigField.js +129 -15
  19. package/dist/components/config/form/RecordConfigForm.d.ts.map +1 -1
  20. package/dist/components/config/form/RecordConfigForm.js +24 -10
  21. package/dist/components/fonts/FontLibraryBoard.d.ts.map +1 -1
  22. package/dist/components/fonts/FontLibraryBoard.js +1 -1
  23. package/dist/components/gallery/GalleryBoard.d.ts.map +1 -1
  24. package/dist/components/gallery/GalleryBoard.js +37 -5
  25. package/dist/components/resources/ImageUploadControl.d.ts +3 -1
  26. package/dist/components/resources/ImageUploadControl.d.ts.map +1 -1
  27. package/dist/components/resources/ImageUploadControl.js +5 -3
  28. package/dist/lib/documents.d.ts +14 -0
  29. package/dist/lib/documents.d.ts.map +1 -0
  30. package/dist/lib/documents.js +42 -0
  31. package/dist/styles/form.css +28 -0
  32. package/dist/styles/gallery.css +237 -0
  33. package/dist/styles/modal.css +2 -1
  34. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"AdminContent.d.ts","sourceRoot":"","sources":["../../../src/components/admin/AdminContent.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AdminContent.d.ts","sourceRoot":"","sources":["../../../src/components/admin/AdminContent.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,aAAa,EACd,MAAM,iBAAiB,CAAC;AASzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAM9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,eAAe,GAAG,IAAI,CAAC;IAChC,SAAS,EAAE,SAAS,CAAC;IACrB,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;IAC9C,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW,EAAE,eAAe,GAAG,IAAI,CAAC;IACpC,cAAc,EAAE,OAAO,CAAC;IACxB,YAAY,EAAE,cAAc,CAAC;IAC7B,oBAAoB,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IACrD,gBAAgB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,WAAW,EAAE,eAAe,GAAG,IAAI,CAAC;IACpC,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,eAAe,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC5C,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,UAAU,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACvC,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,YAAY,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC1C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sBAAsB,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,eAAe,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,UAAU,EAAE,cAAc,GAAG,IAAI,CAAC;IAClC,aAAa,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IAC9C,aAAa,EAAE;QACb,aAAa,CAAC,EAAE;YACd,MAAM,EAAE,MAAM,EAAE,CAAC;YACjB,QAAQ,EAAE,MAAM,CAAC;SAClB,CAAC;QACF,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;QACxD,eAAe,CAAC,EAAE,CAChB,KAAK,EAAE,IAAI,EAAE,KACV,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;KACxC,CAAC;IACF,iBAAiB,EAAE;QACjB,KAAK,CAAC,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC;QACrC,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;QAC1D,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;KACtC,CAAC;CACH,CAAC;AAiLF,wBAAgB,YAAY,CAAC,EAC3B,MAAM,EACN,OAAO,EACP,SAAS,EACT,iBAAiB,EACjB,YAAY,EACZ,OAAO,EACP,eAAe,EACf,WAAW,EACX,cAAc,EACd,YAAY,EACZ,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,UAAU,EACV,aAAa,EACb,eAAe,EACf,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,iBAAiB,EACjB,eAAe,EACf,UAAU,EACV,aAAa,EACb,aAAa,EACb,iBAAiB,GAClB,EAAE,iBAAiB,+BAwUnB"}
@@ -85,11 +85,8 @@ export function AdminContent({ client, catalog, selection, onSelectionChange, au
85
85
  : "Unable to load catalog." }) }) }));
86
86
  }
87
87
  return (_jsx("div", { className: "vertebr-content", children: _jsxs("section", { className: "vertebr-panel", children: [selection?.kind === "overview" ? (_jsx(MetricsBoard, { label: metricsData?.label ?? catalog.metrics?.label, windowLabel: metricsData?.windowLabel, compareLabel: metricsData?.compareLabel, metrics: metricsData?.metrics ?? [], charts: metricsData?.charts ?? [], range: metricsRange, onRangeChange: onMetricsRangeChange, loading: metricsLoading, onRefresh: () => void onRefreshMetrics() })) : null, selection?.kind === "audit" ? (_jsx(AuditBoard, { client: client, label: catalog.audit?.label })) : null, selection?.kind === "sync" ? (_jsx(AdminSyncPage, { client: client, catalog: catalog })) : null, selection?.kind === "gallery" && galleryData ? (_jsx(GalleryBoard, { label: galleryData.label, items: galleryData.items, accept: galleryData.accept, maxBytes: galleryData.maxBytes, canDelete: galleryData.canDelete, loading: galleryLoading, onRefresh: () => void onRefreshGallery(), onUpload: async (files) => {
88
- if (files.length === 1 && files[0]) {
89
- await client.uploadGalleryFile(files[0]);
90
- }
91
- else {
92
- await client.uploadGalleryFiles(files);
88
+ for (const file of files) {
89
+ await client.uploadGalleryFile(file);
93
90
  }
94
91
  await onRefreshGallery();
95
92
  }, onDelete: galleryData.canDelete
@@ -192,12 +189,12 @@ export function AdminContent({ client, catalog, selection, onSelectionChange, au
192
189
  }
193
190
  : undefined, onUpload: resourceData.uploads
194
191
  ? async (field, files) => {
195
- if (files.length === 1 && files[0]) {
196
- const result = await client.uploadResourceFile(resourceData.id, field, files[0]);
197
- return [{ url: result.url, name: result.name }];
192
+ const uploaded = [];
193
+ for (const file of files) {
194
+ const result = await client.uploadResourceFile(resourceData.id, field, file);
195
+ uploaded.push({ url: result.url, name: result.name });
198
196
  }
199
- const result = await client.uploadResourceFiles(resourceData.id, field, files);
200
- return result.files;
197
+ return uploaded;
201
198
  }
202
199
  : undefined, ...galleryPicker })) : null, selection?.kind === "addons" ? (_jsx(AddonOverview, { client: client, catalog: catalog, onSelectAddon: (id) => onSelectionChange?.({ kind: "addon", id }) })) : null, selection?.kind === "config" && configData ? (_jsx(ConfigEditor, { client: client, catalog: catalog, configData: configData, isPageSelection: isPageSelection, previewPath: catalog.configs.find((item) => item.id === configData.id)
203
200
  ?.previewPath, relatedAddons: catalog.configs.find((item) => item.id === configData.id)
@@ -1 +1 @@
1
- {"version":3,"file":"VertebrAdmin.d.ts","sourceRoot":"","sources":["../../../src/components/admin/VertebrAdmin.tsx"],"names":[],"mappings":"AAwCA,OAAO,KAAK,EAGV,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD,wBAAgB,YAAY,CAAC,EAC3B,OAAsB,EACtB,QAAQ,EAAE,YAAY,EACtB,KAAuB,EACvB,aAA6B,EAC7B,eAAiC,EACjC,eAAiC,EACjC,sBAAgD,EAChD,cAAc,EACd,aAAa,EACb,SAAS,GACV,EAAE,iBAAiB,+BAguBnB"}
1
+ {"version":3,"file":"VertebrAdmin.d.ts","sourceRoot":"","sources":["../../../src/components/admin/VertebrAdmin.tsx"],"names":[],"mappings":"AAwCA,OAAO,KAAK,EAGV,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD,wBAAgB,YAAY,CAAC,EAC3B,OAAsB,EACtB,QAAQ,EAAE,YAAY,EACtB,KAAuB,EACvB,aAA6B,EAC7B,eAAiC,EACjC,eAAiC,EACjC,sBAAgD,EAChD,cAAc,EACd,aAAa,EACb,SAAS,GACV,EAAE,iBAAiB,+BAkuBnB"}
@@ -380,11 +380,13 @@ export function VertebrAdmin({ apiBase = "/admin/api", basePath: basePathProp, t
380
380
  return data.items;
381
381
  }, [client]);
382
382
  const uploadGallery = useCallback(async (files) => {
383
- if (files.length === 1 && files[0]) {
384
- const { item } = await client.uploadGalleryFile(files[0]);
385
- return [item];
383
+ // Upload one file per request — base64 bulk payloads easily exceed the
384
+ // host HTTP body limit when several product photos are selected.
385
+ const items = [];
386
+ for (const file of files) {
387
+ const { item } = await client.uploadGalleryFile(file);
388
+ items.push(item);
386
389
  }
387
- const { items } = await client.uploadGalleryFiles(files);
388
390
  return items;
389
391
  }, [client]);
390
392
  const galleryPicker = catalog?.gallery
@@ -13,6 +13,8 @@ export type DescriptionInputProps = {
13
13
  onBlur?: () => void;
14
14
  onChange: (next: string) => void;
15
15
  inputRef?: React.Ref<HTMLElement>;
16
+ /** Opens a document-style modal for focused policy editing. */
17
+ onOpenDocumentView?: () => void;
16
18
  };
17
- export declare function DescriptionInput({ id, name, value, readOnly, placeholder, recordImages, galleryUpload, onListGallery, onUploadGallery, onBlur, onChange, inputRef, }: DescriptionInputProps): import("react").JSX.Element;
19
+ export declare function DescriptionInput({ id, name, value, readOnly, placeholder, recordImages, galleryUpload, onListGallery, onUploadGallery, onBlur, onChange, inputRef, onOpenDocumentView, }: DescriptionInputProps): import("react").JSX.Element;
18
20
  //# sourceMappingURL=DescriptionInput.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DescriptionInput.d.ts","sourceRoot":"","sources":["../../../src/components/config/DescriptionInput.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAEvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD,MAAM,MAAM,qBAAqB,GAAG;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B,aAAa,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,GAAG,UAAU,CAAC,CAAC;IAChE,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7C,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5D,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;CACnC,CAAC;AAoCF,wBAAgB,gBAAgB,CAAC,EAC/B,EAAE,EACF,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,WAAoC,EACpC,YAAY,EACZ,aAAa,EACb,aAAa,EACb,eAAe,EACf,MAAM,EACN,QAAQ,EACR,QAAQ,GACT,EAAE,qBAAqB,+BA6RvB"}
1
+ {"version":3,"file":"DescriptionInput.d.ts","sourceRoot":"","sources":["../../../src/components/config/DescriptionInput.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAEvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD,MAAM,MAAM,qBAAqB,GAAG;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B,aAAa,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,GAAG,UAAU,CAAC,CAAC;IAChE,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7C,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5D,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAClC,+DAA+D;IAC/D,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;CACjC,CAAC;AAoCF,wBAAgB,gBAAgB,CAAC,EAC/B,EAAE,EACF,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,WAAoC,EACpC,YAAY,EACZ,aAAa,EACb,aAAa,EACb,eAAe,EACf,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,kBAAkB,GACnB,EAAE,qBAAqB,+BAqTvB"}
@@ -19,7 +19,7 @@ function assignRef(ref, node) {
19
19
  function ToolbarButton({ active, disabled, title, onClick, children, }) {
20
20
  return (_jsx("button", { type: "button", className: "vertebr-md-btn", "data-active": active || undefined, disabled: disabled, title: title, onMouseDown: (event) => event.preventDefault(), onClick: onClick, children: children }));
21
21
  }
22
- export function DescriptionInput({ id, name, value, readOnly, placeholder = "Write a description…", recordImages, galleryUpload, onListGallery, onUploadGallery, onBlur, onChange, inputRef, }) {
22
+ export function DescriptionInput({ id, name, value, readOnly, placeholder = "Write a description…", recordImages, galleryUpload, onListGallery, onUploadGallery, onBlur, onChange, inputRef, onOpenDocumentView, }) {
23
23
  const text = typeof value === "string" ? value : "";
24
24
  const onChangeRef = useRef(onChange);
25
25
  const onBlurRef = useRef(onBlur);
@@ -148,5 +148,5 @@ export function DescriptionInput({ id, name, value, readOnly, placeholder = "Wri
148
148
  rows: 3,
149
149
  cols: 3,
150
150
  withHeaderRow: true,
151
- }).run(), children: "Table" }), marks?.table ? (_jsxs(_Fragment, { children: [_jsx(ToolbarButton, { disabled: locked, title: "Add column", onClick: () => editor?.chain().focus().addColumnAfter().run(), children: "+Col" }), _jsx(ToolbarButton, { disabled: locked, title: "Add row", onClick: () => editor?.chain().focus().addRowAfter().run(), children: "+Row" }), _jsx(ToolbarButton, { disabled: locked, title: "Delete table", onClick: () => editor?.chain().focus().deleteTable().run(), children: "Del" })] })) : null, _jsx(ToolbarButton, { active: marks?.link, disabled: locked, title: "Link", onClick: setLink, children: "Link" }), _jsx(ToolbarButton, { disabled: locked, title: "Insert images", onClick: () => setPickerOpen(true), children: "Image" })] }), _jsx(EditorContent, { editor: editor }), _jsxs("p", { className: "vertebr-field-prose-meta", children: ["Markdown", _jsx("span", { "aria-hidden": "true", children: " \u00B7 " }), stats.words, " ", stats.words === 1 ? "word" : "words", _jsx("span", { "aria-hidden": "true", children: " \u00B7 " }), stats.characters, " ", stats.characters === 1 ? "character" : "characters"] }), pickerOpen ? (_jsx(ImagePickerModal, { recordImages: recordImages, galleryUpload: galleryUpload, onListGallery: onListGallery, onUploadGallery: onUploadGallery, onClose: () => setPickerOpen(false), onInsert: insertImages })) : null] }));
151
+ }).run(), children: "Table" }), marks?.table ? (_jsxs(_Fragment, { children: [_jsx(ToolbarButton, { disabled: locked, title: "Add column", onClick: () => editor?.chain().focus().addColumnAfter().run(), children: "+Col" }), _jsx(ToolbarButton, { disabled: locked, title: "Add row", onClick: () => editor?.chain().focus().addRowAfter().run(), children: "+Row" }), _jsx(ToolbarButton, { disabled: locked, title: "Delete table", onClick: () => editor?.chain().focus().deleteTable().run(), children: "Del" })] })) : null, _jsx(ToolbarButton, { active: marks?.link, disabled: locked, title: "Link", onClick: setLink, children: "Link" }), _jsx(ToolbarButton, { disabled: locked, title: "Insert images", onClick: () => setPickerOpen(true), children: "Image" }), onOpenDocumentView ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "vertebr-md-sep", "aria-hidden": "true" }), _jsx(ToolbarButton, { disabled: false, title: "Open document view", onClick: onOpenDocumentView, children: "Doc" })] })) : null] }), _jsx(EditorContent, { editor: editor }), _jsxs("p", { className: "vertebr-field-prose-meta", children: ["Markdown", _jsx("span", { "aria-hidden": "true", children: " \u00B7 " }), stats.words, " ", stats.words === 1 ? "word" : "words", _jsx("span", { "aria-hidden": "true", children: " \u00B7 " }), stats.characters, " ", stats.characters === 1 ? "character" : "characters", onOpenDocumentView ? (_jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": "true", children: " \u00B7 " }), _jsx("button", { type: "button", className: "vertebr-md-doc-link", onClick: onOpenDocumentView, children: "Open in document view" })] })) : null] }), pickerOpen ? (_jsx(ImagePickerModal, { recordImages: recordImages, galleryUpload: galleryUpload, onListGallery: onListGallery, onUploadGallery: onUploadGallery, onClose: () => setPickerOpen(false), onInsert: insertImages })) : null] }));
152
152
  }
@@ -0,0 +1,17 @@
1
+ export type DocumentAttachmentFieldProps = {
2
+ id: string;
3
+ label: string;
4
+ value: string;
5
+ readOnly?: boolean;
6
+ description?: string;
7
+ /** Sibling markdown body available for document-view editing. */
8
+ markdownBody?: string;
9
+ canPickFiles?: boolean;
10
+ canUpload?: boolean;
11
+ onChangeUrl: (next: string) => void;
12
+ onOpenPicker?: () => void;
13
+ onUploadFiles?: (files: File[]) => Promise<void>;
14
+ onEditMarkdown?: () => void;
15
+ };
16
+ export declare function DocumentAttachmentField({ id, label, value, readOnly, description, markdownBody, canPickFiles, canUpload, onChangeUrl, onOpenPicker, onUploadFiles, onEditMarkdown, }: DocumentAttachmentFieldProps): import("react").JSX.Element;
17
+ //# sourceMappingURL=DocumentAttachmentField.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DocumentAttachmentField.d.ts","sourceRoot":"","sources":["../../../src/components/config/DocumentAttachmentField.tsx"],"names":[],"mappings":"AAGA,MAAM,MAAM,4BAA4B,GAAG;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,EACtC,EAAE,EACF,KAAK,EACL,KAAK,EACL,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,WAAW,EACX,YAAY,EACZ,aAAa,EACb,cAAc,GACf,EAAE,4BAA4B,+BAqI9B"}
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useRef, useState } from "react";
3
+ import { pdfFileName } from "../../lib/documents";
4
+ export function DocumentAttachmentField({ id, label, value, readOnly, description, markdownBody, canPickFiles, canUpload, onChangeUrl, onOpenPicker, onUploadFiles, onEditMarkdown, }) {
5
+ const inputRef = useRef(null);
6
+ const [busy, setBusy] = useState(false);
7
+ const [showUrl, setShowUrl] = useState(() => Boolean(value.trim()));
8
+ const url = value.trim();
9
+ const hasPdf = Boolean(url);
10
+ const canEditMd = Boolean(onEditMarkdown && markdownBody !== undefined);
11
+ const handleFiles = async (files) => {
12
+ if (!files?.length || !onUploadFiles || readOnly)
13
+ return;
14
+ setBusy(true);
15
+ try {
16
+ await onUploadFiles([...files]);
17
+ setShowUrl(true);
18
+ }
19
+ finally {
20
+ setBusy(false);
21
+ if (inputRef.current)
22
+ inputRef.current.value = "";
23
+ }
24
+ };
25
+ return (_jsxs("div", { className: "vertebr-doc-attach", children: [_jsxs("div", { className: "vertebr-doc-attach-card", "data-has-file": hasPdf || undefined, children: [_jsxs("div", { className: "vertebr-doc-attach-main", children: [_jsx("div", { className: "vertebr-doc-attach-icon", "aria-hidden": "true", children: "PDF" }), _jsxs("div", { className: "vertebr-doc-attach-copy", children: [_jsx("p", { className: "vertebr-doc-attach-title", children: hasPdf ? pdfFileName(url) : "No PDF attached" }), _jsx("p", { className: "vertebr-doc-attach-hint", children: hasPdf
26
+ ? "Optional download for shoppers. Markdown remains the live policy."
27
+ : description?.trim() ||
28
+ "Optional PDF download. Markdown remains the live policy." })] })] }), _jsxs("div", { className: "vertebr-doc-attach-actions", children: [canEditMd ? (_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-primary", onClick: onEditMarkdown, children: "Edit document" })) : null, canPickFiles && !readOnly ? (_jsx("button", { type: "button", className: "vertebr-btn", onClick: onOpenPicker, disabled: busy, children: "Choose PDF" })) : null, canUpload && !readOnly ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: "vertebr-btn", disabled: busy, onClick: () => inputRef.current?.click(), children: busy ? "Uploading…" : "Upload" }), _jsx("input", { ref: inputRef, type: "file", accept: "application/pdf,.pdf", hidden: true, onChange: (event) => void handleFiles(event.target.files) })] })) : null, hasPdf ? (_jsx("a", { className: "vertebr-btn", href: url, target: "_blank", rel: "noreferrer", children: "Open" })) : null, hasPdf && !readOnly ? (_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet", onClick: () => {
29
+ onChangeUrl("");
30
+ setShowUrl(false);
31
+ }, children: "Remove" })) : null] })] }), !readOnly ? (showUrl ? (_jsxs("label", { className: "vertebr-doc-attach-url", htmlFor: id, children: [_jsxs("span", { children: [label, " URL"] }), _jsx("input", { id: id, type: "url", placeholder: "https://\u2026/policy.pdf", value: value, onChange: (event) => onChangeUrl(event.target.value) })] })) : (_jsx("button", { type: "button", className: "vertebr-doc-attach-url-toggle", onClick: () => setShowUrl(true), children: "Paste PDF URL" }))) : hasPdf ? (_jsxs("label", { className: "vertebr-doc-attach-url", htmlFor: id, children: [_jsxs("span", { children: [label, " URL"] }), _jsx("input", { id: id, type: "url", readOnly: true, value: value })] })) : null] }));
32
+ }
@@ -6,6 +6,8 @@ export type PickerImage = {
6
6
  name: string;
7
7
  source: "record" | "gallery" | "url";
8
8
  };
9
+ type Tab = "record" | "gallery";
10
+ type AssetKind = "image" | "document" | "any";
9
11
  export type ImagePickerModalProps = {
10
12
  recordImages?: RecordImage[];
11
13
  galleryUpload?: Pick<ResourceUploadMeta, "accept" | "maxBytes">;
@@ -13,6 +15,15 @@ export type ImagePickerModalProps = {
13
15
  onUploadGallery?: (files: File[]) => Promise<GalleryItem[]>;
14
16
  onClose: () => void;
15
17
  onInsert: (images: PickerImage[]) => void;
18
+ /** Dialog heading. @default "Choose images" */
19
+ title?: string;
20
+ /** Primary action label prefix. @default "Use" */
21
+ confirmLabel?: string;
22
+ /** Prefer Files tab when both product photos and gallery exist. */
23
+ defaultTab?: Tab;
24
+ /** Limit Files library to images or PDFs. @default "image" */
25
+ assetKind?: AssetKind;
16
26
  };
17
- export declare function ImagePickerModal({ recordImages, galleryUpload, onListGallery, onUploadGallery, onClose, onInsert, }: ImagePickerModalProps): import("react").JSX.Element;
27
+ export declare function ImagePickerModal({ recordImages, galleryUpload, onListGallery, onUploadGallery, onClose, onInsert, title, confirmLabel, defaultTab, assetKind, }: ImagePickerModalProps): import("react").ReactPortal;
28
+ export {};
18
29
  //# sourceMappingURL=ImagePickerModal.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ImagePickerModal.d.ts","sourceRoot":"","sources":["../../../src/components/config/ImagePickerModal.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAEvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,KAAK,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B,aAAa,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,GAAG,UAAU,CAAC,CAAC;IAChE,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7C,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5D,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,IAAI,CAAC;CAC3C,CAAC;AAIF,wBAAgB,gBAAgB,CAAC,EAC/B,YAAiB,EACjB,aAAa,EACb,aAAa,EACb,eAAe,EACf,OAAO,EACP,QAAQ,GACT,EAAE,qBAAqB,+BA4PvB"}
1
+ {"version":3,"file":"ImagePickerModal.d.ts","sourceRoot":"","sources":["../../../src/components/config/ImagePickerModal.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAGvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,KAAK,CAAC;CACtC,CAAC;AAEF,KAAK,GAAG,GAAG,QAAQ,GAAG,SAAS,CAAC;AAChC,KAAK,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,KAAK,CAAC;AAE9C,MAAM,MAAM,qBAAqB,GAAG;IAClC,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B,aAAa,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,GAAG,UAAU,CAAC,CAAC;IAChE,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7C,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5D,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,IAAI,CAAC;IAC1C,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,EAC/B,YAAiB,EACjB,aAAa,EACb,aAAa,EACb,eAAe,EACf,OAAO,EACP,QAAQ,EACR,KAAuB,EACvB,YAAoB,EACpB,UAAU,EACV,SAAmB,GACpB,EAAE,qBAAqB,+BAqSvB"}
@@ -1,9 +1,18 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useState } from "react";
3
+ import { createPortal } from "react-dom";
4
+ import { filterGalleryByKind, isPdfAsset } from "../../lib/documents";
3
5
  import { ImageUploadControl } from "../resources/ImageUploadControl";
4
- export function ImagePickerModal({ recordImages = [], galleryUpload, onListGallery, onUploadGallery, onClose, onInsert, }) {
6
+ export function ImagePickerModal({ recordImages = [], galleryUpload, onListGallery, onUploadGallery, onClose, onInsert, title = "Choose images", confirmLabel = "Use", defaultTab, assetKind = "image", }) {
5
7
  const hasGallery = Boolean(onListGallery);
6
- const [tab, setTab] = useState(recordImages.length ? "record" : "gallery");
8
+ const docsOnly = assetKind === "document";
9
+ const [tab, setTab] = useState(() => {
10
+ if (defaultTab)
11
+ return defaultTab;
12
+ if (!docsOnly && recordImages.length)
13
+ return "record";
14
+ return "gallery";
15
+ });
7
16
  const [gallery, setGallery] = useState([]);
8
17
  const [loading, setLoading] = useState(false);
9
18
  const [error, setError] = useState(null);
@@ -31,7 +40,7 @@ export function ImagePickerModal({ recordImages = [], galleryUpload, onListGalle
31
40
  void onListGallery()
32
41
  .then((items) => {
33
42
  if (!cancelled)
34
- setGallery(items);
43
+ setGallery(filterGalleryByKind(items, assetKind));
35
44
  })
36
45
  .catch((err) => {
37
46
  if (!cancelled) {
@@ -45,13 +54,15 @@ export function ImagePickerModal({ recordImages = [], galleryUpload, onListGalle
45
54
  return () => {
46
55
  cancelled = true;
47
56
  };
48
- }, [hasGallery, onListGallery]);
49
- const recordTiles = useMemo(() => recordImages.map((image) => ({
50
- id: `record:${image.id}`,
51
- url: image.url,
52
- name: image.name,
53
- source: "record",
54
- })), [recordImages]);
57
+ }, [hasGallery, onListGallery, assetKind]);
58
+ const recordTiles = useMemo(() => docsOnly
59
+ ? []
60
+ : recordImages.map((image) => ({
61
+ id: `record:${image.id}`,
62
+ url: image.url,
63
+ name: image.name,
64
+ source: "record",
65
+ })), [recordImages, docsOnly]);
55
66
  const galleryTiles = useMemo(() => gallery.map((item) => ({
56
67
  id: `gallery:${item.id}`,
57
68
  url: item.url,
@@ -61,6 +72,8 @@ export function ImagePickerModal({ recordImages = [], galleryUpload, onListGalle
61
72
  const tiles = tab === "record" ? recordTiles : galleryTiles;
62
73
  const picked = Object.values(selected);
63
74
  const canGalleryUpload = Boolean(galleryUpload && onUploadGallery);
75
+ const unit = docsOnly ? "document" : "image";
76
+ const units = docsOnly ? "documents" : "images";
64
77
  const toggle = (image) => {
65
78
  setSelected((current) => {
66
79
  const next = { ...current };
@@ -78,22 +91,33 @@ export function ImagePickerModal({ recordImages = [], galleryUpload, onListGalle
78
91
  const image = {
79
92
  id: `url:${href}`,
80
93
  url: href,
81
- name: "Image",
94
+ name: docsOnly ? "Document" : "Image",
82
95
  source: "url",
83
96
  };
84
97
  setSelected((current) => ({ ...current, [image.id]: image }));
85
98
  setUrl("");
86
99
  };
87
- return (_jsx("div", { className: "vertebr-modal-backdrop", role: "presentation", onClick: onClose, children: _jsxs("div", { className: "vertebr-modal", role: "dialog", "aria-modal": "true", "aria-label": "Insert images", onClick: (event) => event.stopPropagation(), children: [_jsxs("header", { className: "vertebr-modal-head", children: [_jsxs("div", { className: "vertebr-modal-heading", children: [_jsx("p", { className: "vertebr-modal-eyebrow", children: "Media" }), _jsx("h2", { children: "Insert images" })] }), _jsx("button", { type: "button", className: "vertebr-btn", onClick: onClose, children: "Close" })] }), _jsxs("div", { className: "vertebr-modal-body vertebr-picker-body", children: [recordImages.length > 0 && hasGallery ? (_jsxs("div", { className: "vertebr-picker-tabs", role: "tablist", children: [_jsxs("button", { type: "button", role: "tab", "aria-selected": tab === "record", "data-active": tab === "record" || undefined, onClick: () => setTab("record"), children: ["Product photos", _jsx("span", { children: recordTiles.length })] }), _jsxs("button", { type: "button", role: "tab", "aria-selected": tab === "gallery", "data-active": tab === "gallery" || undefined, onClick: () => setTab("gallery"), children: ["Gallery", _jsx("span", { children: loading ? "…" : galleryTiles.length })] })] })) : null, tab === "gallery" && canGalleryUpload ? (_jsx(ImageUploadControl, { meta: {
100
+ const galleryAccept = docsOnly && galleryUpload
101
+ ? {
102
+ ...galleryUpload,
103
+ accept: galleryUpload.accept.some((entry) => /pdf/i.test(entry))
104
+ ? galleryUpload.accept
105
+ : [...galleryUpload.accept, "application/pdf"],
106
+ }
107
+ : galleryUpload;
108
+ return createPortal(_jsx("div", { className: "vertebr-modal-backdrop", role: "presentation", onClick: onClose, children: _jsxs("div", { className: "vertebr-modal", role: "dialog", "aria-modal": "true", "aria-label": title, onClick: (event) => event.stopPropagation(), children: [_jsxs("header", { className: "vertebr-modal-head", children: [_jsxs("div", { className: "vertebr-modal-heading", children: [_jsx("p", { className: "vertebr-modal-eyebrow", children: docsOnly ? "Documents" : "Media" }), _jsx("h2", { children: title })] }), _jsx("button", { type: "button", className: "vertebr-btn", onClick: onClose, children: "Close" })] }), _jsxs("div", { className: "vertebr-modal-body vertebr-picker-body", children: [!docsOnly && recordImages.length > 0 && hasGallery ? (_jsxs("div", { className: "vertebr-picker-tabs", role: "tablist", children: [_jsxs("button", { type: "button", role: "tab", "aria-selected": tab === "record", "data-active": tab === "record" || undefined, onClick: () => setTab("record"), children: ["Product photos", _jsx("span", { children: recordTiles.length })] }), _jsxs("button", { type: "button", role: "tab", "aria-selected": tab === "gallery", "data-active": tab === "gallery" || undefined, onClick: () => setTab("gallery"), children: ["Files", _jsx("span", { children: loading ? "…" : galleryTiles.length })] })] })) : null, tab === "gallery" && canGalleryUpload && galleryAccept ? (_jsx(ImageUploadControl, { meta: {
88
109
  field: "gallery",
89
- accept: galleryUpload.accept,
90
- maxBytes: galleryUpload.maxBytes,
91
- }, multiple: true, label: "Drop images to add them to the gallery", onUpload: async (files) => {
110
+ accept: galleryAccept.accept,
111
+ maxBytes: galleryAccept.maxBytes,
112
+ }, multiple: true, showOptimizeHint: !docsOnly, label: docsOnly
113
+ ? "Drop PDFs to add them to Files"
114
+ : "Drop images to add them to Files", onUpload: async (files) => {
92
115
  const items = await onUploadGallery(files);
93
- setGallery((current) => [...items, ...current]);
116
+ const kept = filterGalleryByKind(items, assetKind);
117
+ setGallery((current) => [...kept, ...current]);
94
118
  setSelected((current) => {
95
119
  const next = { ...current };
96
- for (const item of items) {
120
+ for (const item of kept) {
97
121
  const image = {
98
122
  id: `gallery:${item.id}`,
99
123
  url: item.url,
@@ -104,17 +128,22 @@ export function ImagePickerModal({ recordImages = [], galleryUpload, onListGalle
104
128
  }
105
129
  return next;
106
130
  });
107
- } })) : null, _jsxs("label", { className: "vertebr-field", children: [_jsx("span", { children: "Or paste an image URL" }), _jsxs("div", { className: "vertebr-picker-url", children: [_jsx("input", { type: "url", value: url, placeholder: "https://", onChange: (event) => setUrl(event.target.value), onKeyDown: (event) => {
131
+ } })) : null, _jsxs("label", { className: "vertebr-field", children: [_jsxs("span", { children: ["Or paste a ", docsOnly ? "PDF" : "image", " URL"] }), _jsxs("div", { className: "vertebr-picker-url", children: [_jsx("input", { type: "url", value: url, placeholder: "https://", onChange: (event) => setUrl(event.target.value), onKeyDown: (event) => {
108
132
  if (event.key === "Enter") {
109
133
  event.preventDefault();
110
134
  addUrl();
111
135
  }
112
- } }), _jsx("button", { type: "button", className: "vertebr-btn", disabled: !url.trim(), onClick: addUrl, children: "Add" })] })] }), error ? (_jsx("p", { className: "vertebr-status", "data-tone": "danger", children: error })) : null, loading && tab === "gallery" ? (_jsx("div", { className: "vertebr-empty", children: "Loading gallery\u2026" })) : tiles.length === 0 ? (_jsx("div", { className: "vertebr-empty", children: tab === "record"
136
+ } }), _jsx("button", { type: "button", className: "vertebr-btn", disabled: !url.trim(), onClick: addUrl, children: "Add" })] })] }), error ? (_jsx("p", { className: "vertebr-status", "data-tone": "danger", children: error })) : null, loading && tab === "gallery" ? (_jsx("div", { className: "vertebr-empty", children: "Loading Files\u2026" })) : tiles.length === 0 ? (_jsx("div", { className: "vertebr-empty", children: tab === "record"
113
137
  ? "No product photos on this record yet."
114
138
  : hasGallery
115
- ? "No images in the gallery yet."
116
- : "No gallery is configured. Paste a URL or add product photos." })) : (_jsx("div", { className: "vertebr-picker-grid", children: tiles.map((image) => {
139
+ ? docsOnly
140
+ ? "No PDFs in Files yet."
141
+ : "No images in Files yet."
142
+ : "No Files library is configured. Paste a URL instead." })) : (_jsx("div", { className: "vertebr-picker-grid", children: tiles.map((image) => {
117
143
  const active = Boolean(selected[image.id]);
118
- return (_jsxs("button", { type: "button", className: "vertebr-picker-tile", "data-selected": active || undefined, onClick: () => toggle(image), children: [_jsx("span", { className: "vertebr-picker-thumb", children: _jsx("img", { src: image.url, alt: "" }) }), _jsx("span", { className: "vertebr-picker-name", children: image.name })] }, image.id));
119
- }) }))] }), _jsxs("footer", { className: "vertebr-picker-foot", children: [_jsxs("span", { className: "vertebr-picker-count", children: [picked.length, " selected"] }), _jsxs("button", { type: "button", className: "vertebr-btn vertebr-btn-primary", disabled: picked.length === 0, onClick: () => onInsert(picked), children: ["Insert ", picked.length || "", picked.length === 1 ? " image" : " images"] })] })] }) }));
144
+ const pdf = docsOnly || isPdfAsset(image);
145
+ return (_jsxs("button", { type: "button", className: "vertebr-picker-tile", "data-selected": active || undefined, onClick: () => toggle(image), children: [_jsx("span", { className: pdf
146
+ ? "vertebr-picker-thumb vertebr-gallery-thumb-file"
147
+ : "vertebr-picker-thumb", children: pdf ? (_jsx("span", { className: "vertebr-gallery-file-badge", children: "PDF" })) : (_jsx("img", { src: image.url, alt: "" })) }), _jsx("span", { className: "vertebr-picker-name", children: image.name })] }, image.id));
148
+ }) }))] }), _jsxs("footer", { className: "vertebr-picker-foot", children: [_jsxs("span", { className: "vertebr-picker-count", children: [picked.length, " selected"] }), _jsxs("button", { type: "button", className: "vertebr-btn vertebr-btn-primary", disabled: picked.length === 0, onClick: () => onInsert(picked), children: [confirmLabel, " ", picked.length || "", picked.length === 1 ? ` ${unit}` : ` ${units}`] })] })] }) }), document.body);
120
149
  }
@@ -0,0 +1,19 @@
1
+ import type { GalleryItem, ResourceUploadMeta } from "@vertebr/client";
2
+ import type { RecordImage } from "../../lib/images";
3
+ export type MarkdownDocumentModalProps = {
4
+ title?: string;
5
+ value: string;
6
+ readOnly?: boolean;
7
+ recordImages?: RecordImage[];
8
+ galleryUpload?: Pick<ResourceUploadMeta, "accept" | "maxBytes">;
9
+ onListGallery?: () => Promise<GalleryItem[]>;
10
+ onUploadGallery?: (files: File[]) => Promise<GalleryItem[]>;
11
+ onChange: (next: string) => void;
12
+ onClose: () => void;
13
+ };
14
+ /**
15
+ * Full-page document chrome for editing policy markdown
16
+ * (PDF-like page, not a binary PDF editor).
17
+ */
18
+ export declare function MarkdownDocumentModal({ title, value, readOnly, recordImages, galleryUpload, onListGallery, onUploadGallery, onChange, onClose, }: MarkdownDocumentModalProps): import("react").ReactPortal;
19
+ //# sourceMappingURL=MarkdownDocumentModal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MarkdownDocumentModal.d.ts","sourceRoot":"","sources":["../../../src/components/config/MarkdownDocumentModal.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAEvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD,MAAM,MAAM,0BAA0B,GAAG;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B,aAAa,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,GAAG,UAAU,CAAC,CAAC;IAChE,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7C,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5D,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,KAAyB,EACzB,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,aAAa,EACb,aAAa,EACb,eAAe,EACf,QAAQ,EACR,OAAO,GACR,EAAE,0BAA0B,+BAkF5B"}
@@ -0,0 +1,34 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from "react";
3
+ import { createPortal } from "react-dom";
4
+ import { descriptionStats } from "../../lib/description";
5
+ import { DescriptionInput } from "./DescriptionInput";
6
+ /**
7
+ * Full-page document chrome for editing policy markdown
8
+ * (PDF-like page, not a binary PDF editor).
9
+ */
10
+ export function MarkdownDocumentModal({ title = "Policy document", value, readOnly, recordImages, galleryUpload, onListGallery, onUploadGallery, onChange, onClose, }) {
11
+ const [draft, setDraft] = useState(value);
12
+ const stats = descriptionStats(draft);
13
+ useEffect(() => {
14
+ setDraft(value);
15
+ }, [value]);
16
+ useEffect(() => {
17
+ const onKeyDown = (event) => {
18
+ if (event.key === "Escape")
19
+ onClose();
20
+ };
21
+ window.addEventListener("keydown", onKeyDown);
22
+ const previous = document.body.style.overflow;
23
+ document.body.style.overflow = "hidden";
24
+ return () => {
25
+ window.removeEventListener("keydown", onKeyDown);
26
+ document.body.style.overflow = previous;
27
+ };
28
+ }, [onClose]);
29
+ const saveAndClose = () => {
30
+ onChange(draft);
31
+ onClose();
32
+ };
33
+ return createPortal(_jsx("div", { className: "vertebr-modal-backdrop vertebr-doc-modal-backdrop", role: "presentation", onClick: onClose, children: _jsxs("div", { className: "vertebr-modal vertebr-doc-modal", role: "dialog", "aria-modal": "true", "aria-label": title, onClick: (event) => event.stopPropagation(), children: [_jsxs("header", { className: "vertebr-modal-head", children: [_jsxs("div", { className: "vertebr-modal-heading", children: [_jsx("p", { className: "vertebr-modal-eyebrow", children: "Document" }), _jsx("h2", { children: title })] }), _jsxs("div", { className: "vertebr-doc-modal-actions", children: [_jsxs("span", { className: "vertebr-doc-modal-stats", children: [stats.words, " words \u00B7 ", stats.characters, " characters"] }), !readOnly ? (_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-primary", onClick: saveAndClose, children: "Done" })) : null, _jsx("button", { type: "button", className: "vertebr-btn", onClick: onClose, children: "Close" })] })] }), _jsx("div", { className: "vertebr-modal-body vertebr-doc-modal-body", children: _jsx("div", { className: "vertebr-doc-page", children: _jsx(DescriptionInput, { id: "vertebr-doc-modal-editor", value: draft, readOnly: readOnly, placeholder: "Write the policy\u2026", recordImages: recordImages, galleryUpload: galleryUpload, onListGallery: onListGallery, onUploadGallery: onUploadGallery, onChange: setDraft }) }) })] }) }), document.body);
34
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"ConfigField.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/ConfigField.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAIjE,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAuBtF,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAEvF,MAAM,MAAM,gBAAgB,GAAG,eAAe,GAC5C,mBAAmB,GAAG;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,EAAE,KACV,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACpD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uEAAuE;IACvE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,KAAK,EACL,UAAU,EACV,OAAO,EACP,MAAM,EACN,OAAO,EACP,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,aAAa,EACb,aAAa,EACb,eAAe,EACf,KAAK,EACL,YAAY,EACZ,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,WAAW,EACX,MAAM,GACP,EAAE,gBAAgB,+BAkUlB"}
1
+ {"version":3,"file":"ConfigField.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/ConfigField.tsx"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAIjE,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AA2BtF,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAmBvF,MAAM,MAAM,gBAAgB,GAAG,eAAe,GAC5C,mBAAmB,GAAG;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,EAAE,KACV,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACpD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uEAAuE;IACvE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,KAAK,EACL,UAAU,EACV,OAAO,EACP,MAAM,EACN,OAAO,EACP,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,aAAa,EACb,aAAa,EACb,eAAe,EACf,KAAK,EACL,YAAY,EACZ,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,WAAW,EACX,MAAM,GACP,EAAE,gBAAgB,+BA4elB"}