@mano8/astro-media-m8 1.1.0 → 2.0.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 (123) hide show
  1. package/README.md +54 -11
  2. package/dist/src/integration.d.ts.map +1 -1
  3. package/dist/src/integration.js +1 -0
  4. package/dist/src/integration.js.map +1 -1
  5. package/dist/src/runtime/api/categories.d.ts +14 -8
  6. package/dist/src/runtime/api/categories.d.ts.map +1 -1
  7. package/dist/src/runtime/api/categories.js +21 -8
  8. package/dist/src/runtime/api/categories.js.map +1 -1
  9. package/dist/src/runtime/api/index.d.ts +8 -0
  10. package/dist/src/runtime/api/index.d.ts.map +1 -1
  11. package/dist/src/runtime/api/index.js +8 -0
  12. package/dist/src/runtime/api/index.js.map +1 -1
  13. package/dist/src/runtime/api/transfer.d.ts +19 -0
  14. package/dist/src/runtime/api/transfer.d.ts.map +1 -0
  15. package/dist/src/runtime/api/transfer.js +48 -0
  16. package/dist/src/runtime/api/transfer.js.map +1 -0
  17. package/dist/src/runtime/client.d.ts.map +1 -1
  18. package/dist/src/runtime/client.js +7 -1
  19. package/dist/src/runtime/client.js.map +1 -1
  20. package/dist/src/runtime/compatibility.d.ts +6 -6
  21. package/dist/src/runtime/compatibility.d.ts.map +1 -1
  22. package/dist/src/runtime/compatibility.js +59 -7
  23. package/dist/src/runtime/compatibility.js.map +1 -1
  24. package/dist/src/runtime/errors.d.ts +20 -2
  25. package/dist/src/runtime/errors.d.ts.map +1 -1
  26. package/dist/src/runtime/errors.js +53 -2
  27. package/dist/src/runtime/errors.js.map +1 -1
  28. package/dist/src/runtime/hooks/index.d.ts +2 -0
  29. package/dist/src/runtime/hooks/index.d.ts.map +1 -1
  30. package/dist/src/runtime/hooks/index.js +2 -0
  31. package/dist/src/runtime/hooks/index.js.map +1 -1
  32. package/dist/src/runtime/hooks/useMediaCategories.d.ts +30 -0
  33. package/dist/src/runtime/hooks/useMediaCategories.d.ts.map +1 -0
  34. package/dist/src/runtime/hooks/useMediaCategories.js +56 -0
  35. package/dist/src/runtime/hooks/useMediaCategories.js.map +1 -0
  36. package/dist/src/runtime/hooks/useMediaObjects.d.ts.map +1 -1
  37. package/dist/src/runtime/hooks/useMediaObjects.js +14 -2
  38. package/dist/src/runtime/hooks/useMediaObjects.js.map +1 -1
  39. package/dist/src/runtime/hooks/useMediaTransfer.d.ts +42 -0
  40. package/dist/src/runtime/hooks/useMediaTransfer.d.ts.map +1 -0
  41. package/dist/src/runtime/hooks/useMediaTransfer.js +106 -0
  42. package/dist/src/runtime/hooks/useMediaTransfer.js.map +1 -0
  43. package/dist/src/runtime/queryKeys.d.ts +2 -0
  44. package/dist/src/runtime/queryKeys.d.ts.map +1 -1
  45. package/dist/src/runtime/queryKeys.js +2 -0
  46. package/dist/src/runtime/queryKeys.js.map +1 -1
  47. package/dist/src/runtime/react/CategoryManager.d.ts +10 -0
  48. package/dist/src/runtime/react/CategoryManager.d.ts.map +1 -0
  49. package/dist/src/runtime/react/CategoryManager.js +194 -0
  50. package/dist/src/runtime/react/CategoryManager.js.map +1 -0
  51. package/dist/src/runtime/react/CategoryMultiSelect.d.ts +73 -0
  52. package/dist/src/runtime/react/CategoryMultiSelect.d.ts.map +1 -0
  53. package/dist/src/runtime/react/CategoryMultiSelect.js +179 -0
  54. package/dist/src/runtime/react/CategoryMultiSelect.js.map +1 -0
  55. package/dist/src/runtime/react/MediaCategoryTreePane.d.ts +22 -0
  56. package/dist/src/runtime/react/MediaCategoryTreePane.d.ts.map +1 -0
  57. package/dist/src/runtime/react/MediaCategoryTreePane.js +244 -0
  58. package/dist/src/runtime/react/MediaCategoryTreePane.js.map +1 -0
  59. package/dist/src/runtime/react/MediaErrorBoundary.d.ts +53 -0
  60. package/dist/src/runtime/react/MediaErrorBoundary.d.ts.map +1 -0
  61. package/dist/src/runtime/react/MediaErrorBoundary.js +58 -0
  62. package/dist/src/runtime/react/MediaErrorBoundary.js.map +1 -0
  63. package/dist/src/runtime/react/MediaLibrary.d.ts +16 -1
  64. package/dist/src/runtime/react/MediaLibrary.d.ts.map +1 -1
  65. package/dist/src/runtime/react/MediaLibrary.js +75 -110
  66. package/dist/src/runtime/react/MediaLibrary.js.map +1 -1
  67. package/dist/src/runtime/react/MediaObjectViews.d.ts +47 -0
  68. package/dist/src/runtime/react/MediaObjectViews.d.ts.map +1 -0
  69. package/dist/src/runtime/react/MediaObjectViews.js +131 -0
  70. package/dist/src/runtime/react/MediaObjectViews.js.map +1 -0
  71. package/dist/src/runtime/react/MediaTransferPanel.d.ts +17 -0
  72. package/dist/src/runtime/react/MediaTransferPanel.d.ts.map +1 -0
  73. package/dist/src/runtime/react/MediaTransferPanel.js +93 -0
  74. package/dist/src/runtime/react/MediaTransferPanel.js.map +1 -0
  75. package/dist/src/runtime/react/MediaUploadDropzone.d.ts +36 -1
  76. package/dist/src/runtime/react/MediaUploadDropzone.d.ts.map +1 -1
  77. package/dist/src/runtime/react/MediaUploadDropzone.js +63 -3
  78. package/dist/src/runtime/react/MediaUploadDropzone.js.map +1 -1
  79. package/dist/src/runtime/react/ObjectDetail.d.ts.map +1 -1
  80. package/dist/src/runtime/react/ObjectDetail.js +51 -1
  81. package/dist/src/runtime/react/ObjectDetail.js.map +1 -1
  82. package/dist/src/runtime/react/categoryBranch.d.ts +38 -0
  83. package/dist/src/runtime/react/categoryBranch.d.ts.map +1 -0
  84. package/dist/src/runtime/react/categoryBranch.js +37 -0
  85. package/dist/src/runtime/react/categoryBranch.js.map +1 -0
  86. package/dist/src/runtime/react/default-ui/index.d.ts +6 -2
  87. package/dist/src/runtime/react/default-ui/index.d.ts.map +1 -1
  88. package/dist/src/runtime/react/default-ui/index.js +14 -9
  89. package/dist/src/runtime/react/default-ui/index.js.map +1 -1
  90. package/dist/src/runtime/react/index.d.ts +5 -2
  91. package/dist/src/runtime/react/index.d.ts.map +1 -1
  92. package/dist/src/runtime/react/index.js +3 -0
  93. package/dist/src/runtime/react/index.js.map +1 -1
  94. package/dist/src/runtime/react/mediaLibraryLabels.d.ts +93 -0
  95. package/dist/src/runtime/react/mediaLibraryLabels.d.ts.map +1 -0
  96. package/dist/src/runtime/react/mediaLibraryLabels.js +100 -0
  97. package/dist/src/runtime/react/mediaLibraryLabels.js.map +1 -0
  98. package/dist/src/runtime/react/mediaLibraryStyles.d.ts +44 -0
  99. package/dist/src/runtime/react/mediaLibraryStyles.d.ts.map +1 -0
  100. package/dist/src/runtime/react/mediaLibraryStyles.js +82 -0
  101. package/dist/src/runtime/react/mediaLibraryStyles.js.map +1 -0
  102. package/dist/src/runtime/routes.d.ts +2 -0
  103. package/dist/src/runtime/routes.d.ts.map +1 -1
  104. package/dist/src/runtime/routes.js +2 -0
  105. package/dist/src/runtime/routes.js.map +1 -1
  106. package/dist/src/runtime/schemas.d.ts +265 -0
  107. package/dist/src/runtime/schemas.d.ts.map +1 -1
  108. package/dist/src/runtime/schemas.js +173 -6
  109. package/dist/src/runtime/schemas.js.map +1 -1
  110. package/dist/src/runtime/upload/uploadController.d.ts +7 -0
  111. package/dist/src/runtime/upload/uploadController.d.ts.map +1 -1
  112. package/dist/src/runtime/upload/uploadController.js +10 -5
  113. package/dist/src/runtime/upload/uploadController.js.map +1 -1
  114. package/package.json +37 -30
  115. package/registry/r/media-category-tree.json +21 -0
  116. package/registry/r/media-dashboard-overview.json +1 -1
  117. package/registry/r/media-library-tree.json +25 -0
  118. package/registry/r/media-maintenance-panel.json +3 -2
  119. package/registry/r/media-transfer-dialog.json +26 -0
  120. package/registry/r/registry.json +18 -0
  121. package/registry.json +61 -1
  122. package/src/routes/categories.astro +12 -0
  123. package/src/scaffold/styles/media.css +395 -5
@@ -0,0 +1,93 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * The library's import/export control (`U10`).
4
+ */
5
+ import { useState } from "react";
6
+ import { useMediaTransfer } from "../hooks/useMediaTransfer.js";
7
+ import { friendlyReasonMessage } from "../errors.js";
8
+ import { actionLinkClassName, buttonClassName, labelInlineClassName, transferDropzoneClassName, transferPanelClassName, transferSectionClassName, transferTableClassName, transferTableWrapClassName } from "./mediaLibraryStyles.js";
9
+ const EXPORT_FORMAT_OPTIONS = ["manifest", "archive"];
10
+ const IMPORT_FORMAT_OPTIONS = ["manifest", "archive"];
11
+ /** One row of the per-import result table. */
12
+ function ImportResultRow({ result, labels }) {
13
+ const message = result.reason ? friendlyReasonMessage({ reason: result.reason }, result.message ?? result.reason) : result.message;
14
+ return (_jsxs("tr", { children: [_jsx("td", { children: result.filename ?? result.source_id }), _jsx("td", { children: labels.importStatuses[result.status] }), _jsx("td", { children: message ?? "—" })] }));
15
+ }
16
+ /**
17
+ * The export half: format choice, the start action, and whatever the job has
18
+ * produced so far — a manifest to download, an archive link, or its status.
19
+ */
20
+ function ExportSection({ transfer, filters, exportScopeLabel, labels }) {
21
+ const [exportFormat, setExportFormat] = useState("manifest");
22
+ async function handleStartExport() {
23
+ transfer.resetExport();
24
+ try {
25
+ await transfer.startExport(exportFormat, filters);
26
+ }
27
+ catch {
28
+ // surfaced via `transfer.exportError`
29
+ }
30
+ }
31
+ return (_jsxs("section", { className: transferSectionClassName, "aria-label": labels.exportTitle, children: [_jsx("h3", { children: labels.exportTitle }), exportScopeLabel ? _jsxs("p", { className: "fa-media-transfer-hint", children: [labels.scope, ": ", exportScopeLabel] }) : null, _jsxs("fieldset", { children: [_jsx("legend", { children: labels.format }), EXPORT_FORMAT_OPTIONS.map((value) => (_jsxs("label", { className: labelInlineClassName, children: [_jsx("input", { type: "radio", name: "fa-media-export-format", value: value, checked: exportFormat === value, onChange: () => setExportFormat(value) }), value === "manifest" ? labels.manifest : labels.archive, _jsx("span", { className: "fa-media-transfer-hint", children: value === "manifest" ? labels.manifestHint : labels.archiveHint })] }, value)))] }), _jsx("button", { type: "button", className: buttonClassName, disabled: transfer.exportPending, onClick: () => void handleStartExport(), children: transfer.exportPending ? labels.exporting : labels.startExport }), transfer.exportError ? (_jsx("p", { role: "alert", children: transfer.exportError instanceof Error ? transfer.exportError.message : labels.exportError })) : null, transfer.exportFormat === "manifest" && transfer.manifest ? (_jsx("button", { type: "button", className: buttonClassName, onClick: () => transfer.downloadManifest(), children: labels.downloadManifest(transfer.manifest.objects.length) })) : null, transfer.exportFormat === "archive" && transfer.exportJob ? (_jsx("p", { role: "status", children: transfer.exportJob.status === "completed" && transfer.exportJob.download_url ? (_jsx("a", { className: actionLinkClassName, href: transfer.exportJob.download_url, download: true, children: labels.downloadArchive(transfer.exportJob.object_count) })) : transfer.exportJob.status === "failed" ? (labels.exportFailed(transfer.exportJob.error)) : (labels.exportStatus(transfer.exportJob.status)) })) : null] }));
32
+ }
33
+ /**
34
+ * The file target: a drop zone wrapped around the file input, so dragging a
35
+ * file in and choosing one from the picker are the same control.
36
+ */
37
+ function ImportDropzone({ importFormat, importFile, onFile, labels }) {
38
+ const [dragActive, setDragActive] = useState(false);
39
+ function onDrop(event) {
40
+ event.preventDefault();
41
+ setDragActive(false);
42
+ const file = event.dataTransfer.files?.[0];
43
+ if (file)
44
+ onFile(file);
45
+ }
46
+ return (_jsxs("div", { className: dragActive ? `${transferDropzoneClassName} fa-media-transfer-dropzone--active` : transferDropzoneClassName, onDragOver: (event) => {
47
+ event.preventDefault();
48
+ setDragActive(true);
49
+ }, onDragLeave: () => setDragActive(false), onDrop: onDrop, children: [_jsx("label", { className: buttonClassName, htmlFor: "fa-media-import-file", children: labels.chooseFile }), _jsx("input", { id: "fa-media-import-file", className: "sr-only", type: "file", accept: importFormat === "archive" ? ".zip" : ".json", onChange: (event) => onFile(event.currentTarget.files?.[0] ?? null) }), importFile ? _jsx("p", { children: importFile.name }) : _jsx("p", { children: labels.dropFile })] }));
50
+ }
51
+ /** The import's summary line and its per-object result table. */
52
+ function ImportReport({ report, labels }) {
53
+ if (!report)
54
+ return null;
55
+ return (_jsxs("div", { children: [_jsxs("p", { role: "status", children: [labels.report(report.created, report.linked, report.skipped, report.failed), report.categories_created ? `; ${labels.categoriesCreated(report.categories_created)}` : ""] }), _jsx("div", { className: transferTableWrapClassName, children: _jsxs("table", { className: transferTableClassName, children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: labels.file }), _jsx("th", { children: labels.status }), _jsx("th", { children: labels.reason })] }) }), _jsx("tbody", { children: report.objects.map((result) => (_jsx(ImportResultRow, { result: result, labels: labels }, result.source_id))) })] }) })] }));
56
+ }
57
+ /**
58
+ * The import half: format choice, the drop target that also hosts the file
59
+ * input, and the per-object result table once the server has answered.
60
+ */
61
+ function ImportSection({ transfer, labels }) {
62
+ const [importFormat, setImportFormat] = useState("manifest");
63
+ const [importFile, setImportFile] = useState(null);
64
+ const report = transfer.importReport;
65
+ async function handleStartImport() {
66
+ if (!importFile)
67
+ return;
68
+ try {
69
+ await transfer.startImport(importFormat, importFile);
70
+ }
71
+ catch {
72
+ // surfaced via `transfer.importError`
73
+ }
74
+ finally {
75
+ setImportFile(null);
76
+ }
77
+ }
78
+ return (_jsxs("section", { className: transferSectionClassName, "aria-label": labels.importTitle, children: [_jsx("h3", { children: labels.importTitle }), _jsxs("fieldset", { children: [_jsx("legend", { children: labels.format }), IMPORT_FORMAT_OPTIONS.map((value) => (_jsxs("label", { className: labelInlineClassName, children: [_jsx("input", { type: "radio", name: "fa-media-import-format", value: value, checked: importFormat === value, onChange: () => setImportFormat(value) }), value === "manifest" ? labels.manifest : labels.archive] }, value)))] }), _jsx(ImportDropzone, { importFormat: importFormat, importFile: importFile, onFile: setImportFile, labels: labels }), _jsx("button", { type: "button", className: buttonClassName, disabled: !importFile || transfer.importPending, onClick: () => void handleStartImport(), children: transfer.importPending ? labels.importing : labels.startImport }), transfer.importError ? (_jsx("p", { role: "alert", children: transfer.importError instanceof Error ? transfer.importError.message : labels.importError })) : null, _jsx(ImportReport, { report: report, labels: labels })] }));
79
+ }
80
+ /**
81
+ * Import/export control (`U10`). A single toggled panel rather than a modal
82
+ * dialog — this package hand-rolls Tailwind token classes in `src/runtime`
83
+ * rather than importing `astro-ui-m8` components here (`D11`; the
84
+ * `dialog-form`/`data-table` composition is a separate registry skin, not
85
+ * this runtime component). Export reuses the caller's live `filters`
86
+ * (`ObjectListParams`) so exporting the selected tree branch (`U10`'s branch
87
+ * bullet) falls out of passing the library's own `query` through unchanged.
88
+ */
89
+ export function MediaTransferPanel({ filters, exportScopeLabel, labels }) {
90
+ const transfer = useMediaTransfer();
91
+ return (_jsxs("div", { className: transferPanelClassName, role: "region", "aria-label": labels.regionLabel, children: [_jsx(ExportSection, { transfer: transfer, filters: filters, exportScopeLabel: exportScopeLabel, labels: labels }), _jsx(ImportSection, { transfer: transfer, labels: labels })] }));
92
+ }
93
+ //# sourceMappingURL=MediaTransferPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaTransferPanel.js","sourceRoot":"","sources":["../../../../src/runtime/react/MediaTransferPanel.tsx"],"names":[],"mappings":"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"}
@@ -1,8 +1,43 @@
1
+ import { type CategoryMultiSelectLabels } from "./CategoryMultiSelect.js";
1
2
  import type { MediaCategory, MediaObjectPublic, MediaVisibility } from "../schemas.js";
2
- export declare function MediaUploadDropzone({ defaultCategory, defaultVisibility, checksum, onUploaded }: {
3
+ /**
4
+ * Reduce an upload failure to a rendering variant and a friendly message.
5
+ * `scan` rejections (virus-scan verdict) get their own copy and styling,
6
+ * distinct from an `api`/validation rejection (size/MIME/checksum/quota),
7
+ * which is mapped through `friendlyReasonMessage` against the server detail.
8
+ */
9
+ export interface MediaUploadDropzoneLabels {
10
+ heading: string;
11
+ category: string;
12
+ visibility: string;
13
+ categories: Record<MediaCategory, string>;
14
+ visibilities: Record<MediaVisibility, string>;
15
+ emptyCategories: string;
16
+ chooseFile: string;
17
+ cancel: string;
18
+ uploadFailed: string;
19
+ scanRejected: string;
20
+ categoryPicker: Partial<CategoryMultiSelectLabels>;
21
+ }
22
+ export declare function MediaUploadDropzone({ defaultCategory, defaultVisibility, defaultCategoryIds, showUserCategories, checksum, heading, labels: labelOverrides, onUploaded }: {
3
23
  defaultCategory?: MediaCategory;
4
24
  defaultVisibility?: MediaVisibility;
25
+ /** Pre-selected user categories for the optional nested picker. */
26
+ defaultCategoryIds?: number[];
27
+ /**
28
+ * Render the optional user-category picker beside the required functional
29
+ * category. Off gives a consumer whose deployment does not use user
30
+ * categories the previous two-field form back.
31
+ */
32
+ showUserCategories?: boolean;
5
33
  checksum?: "none" | "sha256";
34
+ /** Visible section heading. Pass false when a surrounding dialog labels the form. */
35
+ heading?: string | false;
36
+ labels?: Partial<Omit<MediaUploadDropzoneLabels, "categories" | "visibilities" | "categoryPicker">> & {
37
+ categories?: Partial<Record<MediaCategory, string>>;
38
+ visibilities?: Partial<Record<MediaVisibility, string>>;
39
+ categoryPicker?: Partial<CategoryMultiSelectLabels>;
40
+ };
6
41
  onUploaded?: (object: MediaObjectPublic) => void;
7
42
  }): import("react").JSX.Element;
8
43
  //# sourceMappingURL=MediaUploadDropzone.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MediaUploadDropzone.d.ts","sourceRoot":"","sources":["../../../../src/runtime/react/MediaUploadDropzone.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAgBvF,wBAAgB,mBAAmB,CAAC,EAClC,eAAyB,EACzB,iBAA6B,EAC7B,QAAmB,EACnB,UAAU,EACX,EAAE;IACD,eAAe,CAAC,EAAE,aAAa,CAAC;IAChC,iBAAiB,CAAC,EAAE,eAAe,CAAC;IACpC,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC7B,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAClD,+BA0DA"}
1
+ {"version":3,"file":"MediaUploadDropzone.d.ts","sourceRoot":"","sources":["../../../../src/runtime/react/MediaUploadDropzone.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAuB,KAAK,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAC/F,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAgBvF;;;;;GAKG;AACH,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAC1C,YAAY,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IAC9C,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;CACpD;AAwCD,wBAAgB,mBAAmB,CAAC,EAClC,eAAyB,EACzB,iBAA6B,EAC7B,kBAAkB,EAClB,kBAAyB,EACzB,QAAmB,EACnB,OAAO,EACP,MAAM,EAAE,cAAc,EACtB,UAAU,EACX,EAAE;IACD,eAAe,CAAC,EAAE,aAAa,CAAC;IAChC,iBAAiB,CAAC,EAAE,eAAe,CAAC;IACpC,mEAAmE;IACnE,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC7B,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,yBAAyB,EAAE,YAAY,GAAG,cAAc,GAAG,gBAAgB,CAAC,CAAC,GAAG;QACpG,UAAU,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;QACpD,YAAY,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;QACxD,cAAc,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;KACrD,CAAC;IACF,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAClD,+BAmGA"}
@@ -1,6 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from "react";
3
3
  import { useMediaUpload } from "../hooks/useMediaUpload.js";
4
+ import { ApiError, friendlyReasonMessage } from "../errors.js";
5
+ import { UploadError } from "../upload/uploadController.js";
6
+ import { CategoryMultiSelect } from "./CategoryMultiSelect.js";
4
7
  const CATEGORIES = [
5
8
  "avatar",
6
9
  "document",
@@ -12,16 +15,68 @@ const CATEGORIES = [
12
15
  const VISIBILITIES = ["private", "public", "tenant", "sensitive"];
13
16
  const inputClassName = "fa-media-control h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40";
14
17
  const labelClassName = "fa-media-label flex items-center gap-2 pb-2 text-sm leading-none font-medium select-none";
15
- export function MediaUploadDropzone({ defaultCategory = "asset", defaultVisibility = "private", checksum = "sha256", onUploaded }) {
18
+ const DEFAULT_LABELS = {
19
+ heading: "Upload media",
20
+ category: "Category",
21
+ visibility: "Visibility",
22
+ categories: {
23
+ avatar: "Avatar",
24
+ document: "Document",
25
+ asset: "Asset",
26
+ chat_attachment: "Chat attachment",
27
+ export: "Export",
28
+ receipt: "Receipt"
29
+ },
30
+ visibilities: {
31
+ private: "Private",
32
+ public: "Public",
33
+ tenant: "Tenant",
34
+ sensitive: "Sensitive"
35
+ },
36
+ emptyCategories: "No user categories yet. This upload will still work — the category above is the one the service requires.",
37
+ chooseFile: "Choose file",
38
+ cancel: "Cancel",
39
+ uploadFailed: "Upload failed",
40
+ scanRejected: "Rejected by virus scan: ",
41
+ categoryPicker: {}
42
+ };
43
+ function describeUploadError(error, fallback) {
44
+ if (error instanceof UploadError) {
45
+ if (error.kind === "scan")
46
+ return { variant: "scan", message: error.message };
47
+ const detail = error.cause instanceof ApiError ? error.cause.detail : undefined;
48
+ return { variant: "validation", message: friendlyReasonMessage(detail, error.message) };
49
+ }
50
+ return { variant: "validation", message: error instanceof Error ? error.message : fallback };
51
+ }
52
+ export function MediaUploadDropzone({ defaultCategory = "asset", defaultVisibility = "private", defaultCategoryIds, showUserCategories = true, checksum = "sha256", heading, labels: labelOverrides, onUploaded }) {
53
+ const labels = {
54
+ ...DEFAULT_LABELS,
55
+ ...labelOverrides,
56
+ categories: { ...DEFAULT_LABELS.categories, ...labelOverrides?.categories },
57
+ visibilities: { ...DEFAULT_LABELS.visibilities, ...labelOverrides?.visibilities },
58
+ categoryPicker: { ...DEFAULT_LABELS.categoryPicker, ...labelOverrides?.categoryPicker }
59
+ };
60
+ const resolvedHeading = heading === undefined ? labels.heading : heading;
16
61
  const { upload, abort, progress, error, busy } = useMediaUpload();
17
62
  const [category, setCategory] = useState(defaultCategory);
18
63
  const [visibility, setVisibility] = useState(defaultVisibility);
64
+ const [categoryIds, setCategoryIds] = useState(() => defaultCategoryIds ?? []);
19
65
  async function onPick(event) {
20
66
  const file = event.currentTarget.files?.[0];
21
67
  if (!file)
22
68
  return;
23
69
  try {
24
- const object = await upload({ file, category, visibility, checksum, waitForScan: true });
70
+ const object = await upload({
71
+ file,
72
+ category,
73
+ visibility,
74
+ // An empty selection is omitted rather than sent as `[]`, so an older
75
+ // service that does not know the field is unaffected.
76
+ categoryIds: categoryIds.length ? categoryIds : undefined,
77
+ checksum,
78
+ waitForScan: true
79
+ });
25
80
  onUploaded?.(object);
26
81
  }
27
82
  catch {
@@ -29,6 +84,11 @@ export function MediaUploadDropzone({ defaultCategory = "asset", defaultVisibili
29
84
  }
30
85
  }
31
86
  const pct = progress?.fraction != null ? Math.round(progress.fraction * 100) : null;
32
- return (_jsxs("section", { className: "not-content fa-media-panel", children: [_jsx("h2", { children: "Upload media" }), _jsxs("div", { className: "fa-media-field", children: [_jsxs("div", { className: "fa-media-field-control", children: [_jsx("label", { className: labelClassName, htmlFor: "fa-media-upload-category", children: "Category" }), _jsx("select", { id: "fa-media-upload-category", className: inputClassName, value: category, onChange: (event) => setCategory(event.currentTarget.value), children: CATEGORIES.map((value) => (_jsx("option", { value: value, children: value }, value))) })] }), _jsxs("div", { className: "fa-media-field-control", children: [_jsx("label", { className: labelClassName, htmlFor: "fa-media-upload-visibility", children: "Visibility" }), _jsx("select", { id: "fa-media-upload-visibility", className: inputClassName, value: visibility, onChange: (event) => setVisibility(event.currentTarget.value), children: VISIBILITIES.map((value) => (_jsx("option", { value: value, children: value }, value))) })] })] }), _jsx("input", { className: inputClassName, type: "file", disabled: busy, onChange: onPick }), progress ? (_jsxs("div", { className: "fa-media-progress", role: "status", children: [_jsx("span", { children: progress.state }), pct != null ? _jsx("progress", { max: 100, value: pct }) : null] })) : null, busy ? (_jsx("button", { type: "button", onClick: abort, children: "Cancel" })) : null, error ? _jsx("p", { role: "alert", children: error instanceof Error ? error.message : "Upload failed" }) : null] }));
87
+ return (_jsxs("section", { className: "not-content fa-media-panel", children: [resolvedHeading ? _jsx("h2", { children: resolvedHeading }) : null, _jsxs("div", { className: "fa-media-field", children: [_jsxs("div", { className: "fa-media-field-control", children: [_jsx("label", { className: labelClassName, htmlFor: "fa-media-upload-category", children: labels.category }), _jsx("select", { id: "fa-media-upload-category", className: inputClassName, value: category, onChange: (event) => setCategory(event.currentTarget.value), children: CATEGORIES.map((value) => (_jsx("option", { value: value, children: labels.categories[value] }, value))) })] }), _jsxs("div", { className: "fa-media-field-control", children: [_jsx("label", { className: labelClassName, htmlFor: "fa-media-upload-visibility", children: labels.visibility }), _jsx("select", { id: "fa-media-upload-visibility", className: inputClassName, value: visibility, onChange: (event) => setVisibility(event.currentTarget.value), children: VISIBILITIES.map((value) => (_jsx("option", { value: value, children: labels.visibilities[value] }, value))) })] })] }), showUserCategories ? (_jsx(CategoryMultiSelect, { value: categoryIds, onChange: setCategoryIds, disabled: busy, idPrefix: "fa-media-upload-categories", emptyHint: labels.emptyCategories, labels: labels.categoryPicker })) : null, _jsxs("label", { className: "fa-media-button inline-flex min-h-8 cursor-pointer items-center rounded-lg border border-input px-3 py-1 text-sm font-medium transition-colors hover:bg-muted", children: [labels.chooseFile, _jsx("input", { className: "sr-only", type: "file", disabled: busy, onChange: onPick })] }), progress ? (_jsxs("div", { className: "fa-media-progress", role: "status", children: [_jsx("span", { children: progress.state }), pct != null ? _jsx("progress", { max: 100, value: pct }) : null] })) : null, busy ? (_jsx("button", { type: "button", onClick: abort, children: labels.cancel })) : null, error
88
+ ? (() => {
89
+ const { variant, message } = describeUploadError(error, labels.uploadFailed);
90
+ return (_jsxs("p", { role: "alert", className: `fa-media-upload-error fa-media-upload-error--${variant}`, children: [variant === "scan" ? labels.scanRejected : null, message] }));
91
+ })()
92
+ : null] }));
33
93
  }
34
94
  //# sourceMappingURL=MediaUploadDropzone.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MediaUploadDropzone.js","sourceRoot":"","sources":["../../../../src/runtime/react/MediaUploadDropzone.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MediaUploadDropzone.js","sourceRoot":"","sources":["../../../../src/runtime/react/MediaUploadDropzone.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAoB,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAkC,MAAM,0BAA0B,CAAC;AAG/F,MAAM,UAAU,GAAoB;IAClC,QAAQ;IACR,UAAU;IACV,OAAO;IACP,iBAAiB;IACjB,QAAQ;IACR,SAAS;CACV,CAAC;AACF,MAAM,YAAY,GAAsB,CAAC,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;AACrF,MAAM,cAAc,GAClB,8pBAA8pB,CAAC;AACjqB,MAAM,cAAc,GAClB,0FAA0F,CAAC;AAsB7F,MAAM,cAAc,GAA8B;IAChD,OAAO,EAAE,cAAc;IACvB,QAAQ,EAAE,UAAU;IACpB,UAAU,EAAE,YAAY;IACxB,UAAU,EAAE;QACV,MAAM,EAAE,QAAQ;QAChB,QAAQ,EAAE,UAAU;QACpB,KAAK,EAAE,OAAO;QACd,eAAe,EAAE,iBAAiB;QAClC,MAAM,EAAE,QAAQ;QAChB,OAAO,EAAE,SAAS;KACnB;IACD,YAAY,EAAE;QACZ,OAAO,EAAE,SAAS;QAClB,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE,QAAQ;QAChB,SAAS,EAAE,WAAW;KACvB;IACD,eAAe,EAAE,2GAA2G;IAC5H,UAAU,EAAE,aAAa;IACzB,MAAM,EAAE,QAAQ;IAChB,YAAY,EAAE,eAAe;IAC7B,YAAY,EAAE,0BAA0B;IACxC,cAAc,EAAE,EAAE;CACnB,CAAC;AAEF,SAAS,mBAAmB,CAC1B,KAAc,EACd,QAAgB;IAEhB,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;QACjC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;YAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;QAC9E,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,YAAY,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;QAChF,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,qBAAqB,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;IAC1F,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC/F,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,EAClC,eAAe,GAAG,OAAO,EACzB,iBAAiB,GAAG,SAAS,EAC7B,kBAAkB,EAClB,kBAAkB,GAAG,IAAI,EACzB,QAAQ,GAAG,QAAQ,EACnB,OAAO,EACP,MAAM,EAAE,cAAc,EACtB,UAAU,EAqBX;IACC,MAAM,MAAM,GAA8B;QACxC,GAAG,cAAc;QACjB,GAAG,cAAc;QACjB,UAAU,EAAE,EAAE,GAAG,cAAc,CAAC,UAAU,EAAE,GAAG,cAAc,EAAE,UAAU,EAAE;QAC3E,YAAY,EAAE,EAAE,GAAG,cAAc,CAAC,YAAY,EAAE,GAAG,cAAc,EAAE,YAAY,EAAE;QACjF,cAAc,EAAE,EAAE,GAAG,cAAc,CAAC,cAAc,EAAE,GAAG,cAAc,EAAE,cAAc,EAAE;KACxF,CAAC;IACF,MAAM,eAAe,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IACzE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,cAAc,EAAE,CAAC;IAClE,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAgB,eAAe,CAAC,CAAC;IACzE,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAkB,iBAAiB,CAAC,CAAC;IACjF,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAW,GAAG,EAAE,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAC;IAEzF,KAAK,UAAU,MAAM,CAAC,KAAoC;QACxD,MAAM,IAAI,GAAG,KAAK,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC;gBAC1B,IAAI;gBACJ,QAAQ;gBACR,UAAU;gBACV,sEAAsE;gBACtE,sDAAsD;gBACtD,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;gBACzD,QAAQ;gBACR,WAAW,EAAE,IAAI;aAClB,CAAC,CAAC;YACH,UAAU,EAAE,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,uBAAuB;QACzB,CAAC;IACH,CAAC;IAED,MAAM,GAAG,GAAG,QAAQ,EAAE,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEpF,OAAO,CACL,mBAAS,SAAS,EAAC,4BAA4B,aAC5C,eAAe,CAAC,CAAC,CAAC,uBAAK,eAAe,GAAM,CAAC,CAAC,CAAC,IAAI,EACpD,eAAK,SAAS,EAAC,gBAAgB,aAC7B,eAAK,SAAS,EAAC,wBAAwB,aACrC,gBAAO,SAAS,EAAE,cAAc,EAAE,OAAO,EAAC,0BAA0B,YAAE,MAAM,CAAC,QAAQ,GAAS,EAC9F,iBAAQ,EAAE,EAAC,0BAA0B,EAAC,SAAS,EAAE,cAAc,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,aAAa,CAAC,KAAsB,CAAC,YAC3J,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACzB,iBAAoB,KAAK,EAAE,KAAK,YAC7B,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,IADd,KAAK,CAET,CACV,CAAC,GACK,IACL,EACN,eAAK,SAAS,EAAC,wBAAwB,aACrC,gBAAO,SAAS,EAAE,cAAc,EAAE,OAAO,EAAC,4BAA4B,YAAE,MAAM,CAAC,UAAU,GAAS,EAClG,iBAAQ,EAAE,EAAC,4BAA4B,EAAC,SAAS,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,aAAa,CAAC,KAAwB,CAAC,YACnK,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAC3B,iBAAoB,KAAK,EAAE,KAAK,YAC7B,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,IADhB,KAAK,CAET,CACV,CAAC,GACK,IACL,IACF,EACL,kBAAkB,CAAC,CAAC,CAAC,CACpB,KAAC,mBAAmB,IAClB,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,IAAI,EACd,QAAQ,EAAC,4BAA4B,EACrC,SAAS,EAAE,MAAM,CAAC,eAAe,EACjC,MAAM,EAAE,MAAM,CAAC,cAAc,GAC7B,CACH,CAAC,CAAC,CAAC,IAAI,EACR,iBAAO,SAAS,EAAC,+JAA+J,aAC7K,MAAM,CAAC,UAAU,EAClB,gBAAO,SAAS,EAAC,SAAS,EAAC,IAAI,EAAC,MAAM,EAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAI,IACrE,EACP,QAAQ,CAAC,CAAC,CAAC,CACV,eAAK,SAAS,EAAC,mBAAmB,EAAC,IAAI,EAAC,QAAQ,aAC9C,yBAAO,QAAQ,CAAC,KAAK,GAAQ,EAC5B,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,mBAAU,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,GAAI,CAAC,CAAC,CAAC,IAAI,IACpD,CACP,CAAC,CAAC,CAAC,IAAI,EACP,IAAI,CAAC,CAAC,CAAC,CACN,iBAAQ,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,KAAK,YACjC,MAAM,CAAC,MAAM,GACP,CACV,CAAC,CAAC,CAAC,IAAI,EACP,KAAK;gBACJ,CAAC,CAAC,CAAC,GAAG,EAAE;oBACJ,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;oBAC7E,OAAO,CACL,aAAG,IAAI,EAAC,OAAO,EAAC,SAAS,EAAE,gDAAgD,OAAO,EAAE,aACjF,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,EAC/C,OAAO,IACN,CACL,CAAC;gBACJ,CAAC,CAAC,EAAE;gBACN,CAAC,CAAC,IAAI,IACA,CACX,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ObjectDetail.d.ts","sourceRoot":"","sources":["../../../../src/runtime/react/ObjectDetail.tsx"],"names":[],"mappings":"AAWA,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,+BAuEjG"}
1
+ {"version":3,"file":"ObjectDetail.d.ts","sourceRoot":"","sources":["../../../../src/runtime/react/ObjectDetail.tsx"],"names":[],"mappings":"AAmCA,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,+BAwHjG"}
@@ -2,13 +2,41 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from "react";
3
3
  import { useDownloadUrl } from "../hooks/useDownloadUrl.js";
4
4
  import { useMediaObject } from "../hooks/useMediaObject.js";
5
+ import { ApiError, messageFromDetail } from "../errors.js";
6
+ import { CategoryMultiSelect, isSameCategorySelection } from "./CategoryMultiSelect.js";
5
7
  import { VariantPicker } from "./VariantPicker.js";
6
8
  const inputClassName = "fa-media-control h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40";
7
9
  const labelClassName = "fa-media-label flex items-center gap-2 pb-2 text-sm leading-none font-medium select-none";
10
+ /**
11
+ * Copy for the refusals the object PATCH can answer once it carries
12
+ * `category_ids` (`U4`): an unknown id, a foreign one, or more than the
13
+ * server's `MAX_CATEGORY_ASSIGNMENTS`. Each is a recoverable user error, so it
14
+ * is surfaced as its own sentence rather than a generic "save failed".
15
+ */
16
+ function describeFilingError(error) {
17
+ if (error instanceof ApiError) {
18
+ if (error.status === 404)
19
+ return "One of the selected categories no longer exists. Refresh and try again.";
20
+ if (error.status === 403)
21
+ return "One of the selected categories is not yours to use.";
22
+ if (error.status === 422) {
23
+ return messageFromDetail(error.detail) ?? "Too many categories selected for one object.";
24
+ }
25
+ return messageFromDetail(error.detail) ?? error.message;
26
+ }
27
+ return error instanceof Error ? error.message : "Failed to save the categories";
28
+ }
29
+ function labelsFor(categories) {
30
+ return new Map(categories.map((category) => [category.id, category.path]));
31
+ }
8
32
  export function ObjectDetail({ objectId, onDeleted }) {
9
33
  const { object, loading, error, update, remove } = useMediaObject(objectId);
10
34
  const { data: download, request: requestDownload } = useDownloadUrl(objectId);
11
35
  const [saving, setSaving] = useState(false);
36
+ // `null` means "not edited yet" — the picker mirrors the served filing until
37
+ // the user touches it, so a background refetch is not fighting a local draft.
38
+ const [draftCategoryIds, setDraftCategoryIds] = useState(null);
39
+ const [filingError, setFilingError] = useState(null);
12
40
  if (loading && !object)
13
41
  return _jsx("p", { children: "Loading\u2026" });
14
42
  if (error)
@@ -26,7 +54,29 @@ export function ObjectDetail({ objectId, onDeleted }) {
26
54
  setSaving(false);
27
55
  }
28
56
  }
29
- return (_jsxs("section", { className: "not-content fa-media-panel", children: [_jsx("h2", { children: object.original_filename ?? object.id }), _jsxs("dl", { className: "fa-media-meta", children: [_jsx("dt", { children: "Status" }), _jsx("dd", { children: object.status }), _jsx("dt", { children: "Scan" }), _jsx("dd", { children: object.scan_status }), _jsx("dt", { children: "MIME" }), _jsx("dd", { children: object.mime_type }), _jsx("dt", { children: "Size" }), _jsxs("dd", { children: [object.size_bytes, " bytes"] })] }), _jsxs("div", { className: "fa-media-field-control", children: [_jsx("label", { className: labelClassName, htmlFor: "fa-media-object-visibility", children: "Visibility" }), _jsx("select", { id: "fa-media-object-visibility", className: inputClassName, disabled: saving, value: object.visibility, onChange: (event) => void patch("visibility", event.currentTarget.value), children: ["private", "public", "tenant", "sensitive"].map((value) => (_jsx("option", { value: value, children: value }, value))) })] }), _jsxs("div", { className: "fa-media-actions", children: [_jsx("button", { type: "button", onClick: () => void requestDownload(), children: "Get download URL" }), download ? (_jsxs("a", { href: download.url, rel: "noreferrer", children: ["Download (expires ", download.expires_at, ")"] })) : null, _jsx("button", { type: "button", className: "fa-media-danger", onClick: async () => {
57
+ const assignedIds = object.categories.map((category) => category.id);
58
+ const selectedIds = draftCategoryIds ?? assignedIds;
59
+ const filingDirty = draftCategoryIds !== null && !isSameCategorySelection(draftCategoryIds, assignedIds);
60
+ async function saveFiling(next) {
61
+ setSaving(true);
62
+ setFilingError(null);
63
+ try {
64
+ // Set semantics (`U4`): the whole filing is replaced by this array, and
65
+ // `[]` unfiles the object.
66
+ await update({ category_ids: [...next] });
67
+ setDraftCategoryIds(null);
68
+ }
69
+ catch (saveError) {
70
+ setFilingError(saveError);
71
+ }
72
+ finally {
73
+ setSaving(false);
74
+ }
75
+ }
76
+ return (_jsxs("section", { className: "not-content fa-media-panel", children: [_jsx("h2", { children: object.original_filename ?? object.id }), _jsxs("dl", { className: "fa-media-meta", children: [_jsx("dt", { children: "Status" }), _jsx("dd", { children: object.status }), _jsx("dt", { children: "Scan" }), _jsx("dd", { children: object.scan_status }), _jsx("dt", { children: "MIME" }), _jsx("dd", { children: object.mime_type }), _jsx("dt", { children: "Size" }), _jsxs("dd", { children: [object.size_bytes, " bytes"] })] }), _jsxs("div", { className: "fa-media-field-control", children: [_jsx("label", { className: labelClassName, htmlFor: "fa-media-object-visibility", children: "Visibility" }), _jsx("select", { id: "fa-media-object-visibility", className: inputClassName, disabled: saving, value: object.visibility, onChange: (event) => void patch("visibility", event.currentTarget.value), children: ["private", "public", "tenant", "sensitive"].map((value) => (_jsx("option", { value: value, children: value }, value))) })] }), _jsx(CategoryMultiSelect, { value: selectedIds, onChange: setDraftCategoryIds, disabled: saving, idPrefix: "fa-media-object-categories", legend: "User categories", emptyHint: "No user categories yet. Create one from the category manager to re-file this object.", fallbackLabels: labelsFor(object.categories) }), _jsxs("div", { className: "fa-media-actions fa-media-category-actions", children: [_jsx("button", { type: "button", disabled: !filingDirty || saving, onClick: () => void saveFiling(selectedIds), children: saving ? "Saving…" : "Save categories" }), _jsx("button", { type: "button", disabled: draftCategoryIds === null || saving, onClick: () => {
77
+ setDraftCategoryIds(null);
78
+ setFilingError(null);
79
+ }, children: "Reset" })] }), filingError ? _jsx("p", { role: "alert", children: describeFilingError(filingError) }) : null, _jsxs("div", { className: "fa-media-actions", children: [_jsx("button", { type: "button", onClick: () => void requestDownload(), children: "Get download URL" }), download ? (_jsxs("a", { href: download.url, rel: "noreferrer", children: ["Download (expires ", download.expires_at, ")"] })) : null, _jsx("button", { type: "button", className: "fa-media-danger", onClick: async () => {
30
80
  await remove();
31
81
  onDeleted?.();
32
82
  }, children: "Delete" })] }), _jsx(VariantPicker, { objectId: object.id })] }));
@@ -1 +1 @@
1
- {"version":3,"file":"ObjectDetail.js","sourceRoot":"","sources":["../../../../src/runtime/react/ObjectDetail.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ObjectDetail.js","sourceRoot":"","sources":["../../../../src/runtime/react/ObjectDetail.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The browse-pane selection and its translation into list params, shared by
3
+ * `MediaLibrary` and the tree pane it mounts.
4
+ */
5
+ import type { MediaLibraryLabels } from "./mediaLibraryLabels.js";
6
+ import type { ObjectListParams } from "../schemas.js";
7
+ /**
8
+ * What the browse pane has selected. The two pseudo-nodes are part of the
9
+ * selection rather than a separate toggle because they are mutually exclusive
10
+ * with a branch: "all" clears `category_id`/`include_descendants`/
11
+ * `uncategorized`, "uncategorized" sets only `uncategorized`, and a category
12
+ * sets `category_id` + `include_descendants`. Modelling them as three
13
+ * independent booleans would let the UI reach states the API rejects.
14
+ */
15
+ export type CategoryBranchSelection = {
16
+ kind: "all";
17
+ } | {
18
+ kind: "uncategorized";
19
+ } | {
20
+ kind: "category";
21
+ id: number;
22
+ };
23
+ /**
24
+ * The one place a selection becomes list params. Every key is written on every
25
+ * selection — `undefined` where it does not apply — so switching branches
26
+ * clears the previous branch's params instead of leaving a stale
27
+ * `category_id` next to a fresh `uncategorized`.
28
+ *
29
+ * A branch selection is always descendant-inclusive: the node badge shows
30
+ * `total_object_count`, so a branch that lists fewer objects than its own badge
31
+ * promises would read as a bug.
32
+ */
33
+ export declare function branchListParams(selection: CategoryBranchSelection): Pick<ObjectListParams, "category_id" | "include_descendants" | "uncategorized">;
34
+ /** A concise, visible description of the branch whose filters will be exported. */
35
+ export declare function exportBranchLabel(selection: CategoryBranchSelection, labels: MediaLibraryLabels["tree"]): string;
36
+ /** Keep the pane in step with a caller-supplied `initial` branch filter. */
37
+ export declare function initialBranchSelection(params: ObjectListParams): CategoryBranchSelection;
38
+ //# sourceMappingURL=categoryBranch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"categoryBranch.d.ts","sourceRoot":"","sources":["../../../../src/runtime/react/categoryBranch.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD;;;;;;;GAOG;AACH,MAAM,MAAM,uBAAuB,GAC/B;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GACf;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAErC;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,uBAAuB,GAAG,IAAI,CACxE,gBAAgB,EAChB,aAAa,GAAG,qBAAqB,GAAG,eAAe,CACxD,CAMA;AAED,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,uBAAuB,EAAE,MAAM,EAAE,kBAAkB,CAAC,MAAM,CAAC,GAAG,MAAM,CAShH;AAED,4EAA4E;AAC5E,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,GAAG,uBAAuB,CAIxF"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * The one place a selection becomes list params. Every key is written on every
3
+ * selection — `undefined` where it does not apply — so switching branches
4
+ * clears the previous branch's params instead of leaving a stale
5
+ * `category_id` next to a fresh `uncategorized`.
6
+ *
7
+ * A branch selection is always descendant-inclusive: the node badge shows
8
+ * `total_object_count`, so a branch that lists fewer objects than its own badge
9
+ * promises would read as a bug.
10
+ */
11
+ export function branchListParams(selection) {
12
+ return {
13
+ category_id: selection.kind === "category" ? selection.id : undefined,
14
+ include_descendants: selection.kind === "category" ? true : undefined,
15
+ uncategorized: selection.kind === "uncategorized" ? true : undefined
16
+ };
17
+ }
18
+ /** A concise, visible description of the branch whose filters will be exported. */
19
+ export function exportBranchLabel(selection, labels) {
20
+ switch (selection.kind) {
21
+ case "all":
22
+ return labels.allMediaScope;
23
+ case "uncategorized":
24
+ return labels.uncategorizedScope;
25
+ case "category":
26
+ return labels.selectedScope(selection.id);
27
+ }
28
+ }
29
+ /** Keep the pane in step with a caller-supplied `initial` branch filter. */
30
+ export function initialBranchSelection(params) {
31
+ if (params.category_id != null)
32
+ return { kind: "category", id: params.category_id };
33
+ if (params.uncategorized)
34
+ return { kind: "uncategorized" };
35
+ return { kind: "all" };
36
+ }
37
+ //# sourceMappingURL=categoryBranch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"categoryBranch.js","sourceRoot":"","sources":["../../../../src/runtime/react/categoryBranch.ts"],"names":[],"mappings":"AAoBA;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAkC;IAIjE,OAAO;QACL,WAAW,EAAE,SAAS,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;QACrE,mBAAmB,EAAE,SAAS,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;QACrE,aAAa,EAAE,SAAS,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;KACrE,CAAC;AACJ,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,iBAAiB,CAAC,SAAkC,EAAE,MAAkC;IACtG,QAAQ,SAAS,CAAC,IAAI,EAAE,CAAC;QACvB,KAAK,KAAK;YACR,OAAO,MAAM,CAAC,aAAa,CAAC;QAC9B,KAAK,eAAe;YAClB,OAAO,MAAM,CAAC,kBAAkB,CAAC;QACnC,KAAK,UAAU;YACb,OAAO,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,sBAAsB,CAAC,MAAwB;IAC7D,IAAI,MAAM,CAAC,WAAW,IAAI,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC;IACpF,IAAI,MAAM,CAAC,aAAa;QAAE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;IAC3D,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACzB,CAAC"}
@@ -2,13 +2,17 @@ import type { MediaRuntimeConfig } from "../../config.js";
2
2
  type ViewConfig = Partial<Omit<MediaRuntimeConfig, "polling">> & {
3
3
  polling?: Partial<MediaRuntimeConfig["polling"]>;
4
4
  };
5
- export declare function UploadView({ config, libraryHref }: {
5
+ export declare function UploadView({ config }: {
6
6
  config?: ViewConfig;
7
7
  libraryHref?: string;
8
8
  }): import("react").JSX.Element;
9
- export declare function LibraryView({ config, objectHref }: {
9
+ export declare function LibraryView({ config, objectHref, initialUploadOpen }: {
10
10
  config?: ViewConfig;
11
11
  objectHref?: (id: string) => string;
12
+ initialUploadOpen?: boolean;
13
+ }): import("react").JSX.Element;
14
+ export declare function CategoriesView({ config }: {
15
+ config?: ViewConfig;
12
16
  }): import("react").JSX.Element;
13
17
  export declare function ObjectDetailView({ config, objectId, libraryHref }: {
14
18
  config?: ViewConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/runtime/react/default-ui/index.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,KAAK,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,SAAS,CAAC,CAAC,GAAG;IAC/D,OAAO,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC;CAClD,CAAC;AAUF,wBAAgB,UAAU,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,+BAUhG;AAED,wBAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAC;IAAC,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAA;CAAE,+BAM/G;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,QAAQ,EACR,WAAW,EACZ,EAAE;IACD,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,+BAWA;AAED,wBAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,+BAM9D;AAED,wBAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,+BAMjE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/runtime/react/default-ui/index.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,KAAK,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,SAAS,CAAC,CAAC,GAAG;IAC/D,OAAO,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC;CAClD,CAAC;AAgBF,wBAAgB,UAAU,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,+BAMnF;AAED,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,UAAU,EACV,iBAAyB,EAC1B,EAAE;IACD,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,+BAMA;AAED,wBAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,+BAMjE;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,QAAQ,EACR,WAAW,EACZ,EAAE;IACD,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,+BAWA;AAED,wBAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,+BAM9D;AAED,wBAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,+BAMjE"}
@@ -1,22 +1,27 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { MediaProvider } from "../MediaProvider.js";
3
3
  import { MediaQueryProvider } from "../MediaQueryProvider.js";
4
+ import { MediaErrorBoundary } from "../MediaErrorBoundary.js";
4
5
  import { AdminMediaPanel } from "../AdminMediaPanel.js";
6
+ import { CategoryManager } from "../CategoryManager.js";
5
7
  import { MediaLibrary } from "../MediaLibrary.js";
6
- import { MediaUploadDropzone } from "../MediaUploadDropzone.js";
7
8
  import { ObjectDetail } from "../ObjectDetail.js";
8
9
  import { PresetEditor } from "../PresetEditor.js";
10
+ // The boundary is the outermost wrapper on purpose (`A-C3`). Inside the
11
+ // providers it would be unmounted by a throw in a provider's own render, which
12
+ // is exactly the case that leaves an island blank; outside them it survives
13
+ // anything either provider does.
9
14
  function Shell({ config, children }) {
10
- return (_jsx(MediaQueryProvider, { children: _jsx(MediaProvider, { config: config, children: children }) }));
15
+ return (_jsx(MediaErrorBoundary, { children: _jsx(MediaQueryProvider, { children: _jsx(MediaProvider, { config: config, children: children }) }) }));
11
16
  }
12
- export function UploadView({ config, libraryHref }) {
13
- return (_jsx(Shell, { config: config, children: _jsx(MediaUploadDropzone, { onUploaded: () => {
14
- if (libraryHref)
15
- window.location.assign(libraryHref);
16
- } }) }));
17
+ export function UploadView({ config }) {
18
+ return (_jsx(Shell, { config: config, children: _jsx(MediaLibrary, { initialUploadOpen: true }) }));
19
+ }
20
+ export function LibraryView({ config, objectHref, initialUploadOpen = false }) {
21
+ return (_jsx(Shell, { config: config, children: _jsx(MediaLibrary, { objectHref: objectHref, initialUploadOpen: initialUploadOpen }) }));
17
22
  }
18
- export function LibraryView({ config, objectHref }) {
19
- return (_jsx(Shell, { config: config, children: _jsx(MediaLibrary, { objectHref: objectHref }) }));
23
+ export function CategoriesView({ config }) {
24
+ return (_jsx(Shell, { config: config, children: _jsx(CategoryManager, {}) }));
20
25
  }
21
26
  export function ObjectDetailView({ config, objectId, libraryHref }) {
22
27
  return (_jsx(Shell, { config: config, children: _jsx(ObjectDetail, { objectId: objectId, onDeleted: () => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/runtime/react/default-ui/index.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAOlD,SAAS,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAgD;IAC/E,OAAO,CACL,KAAC,kBAAkB,cACjB,KAAC,aAAa,IAAC,MAAM,EAAE,MAAM,YAAG,QAAQ,GAAiB,GACtC,CACtB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,EAAE,MAAM,EAAE,WAAW,EAAiD;IAC/F,OAAO,CACL,KAAC,KAAK,IAAC,MAAM,EAAE,MAAM,YACnB,KAAC,mBAAmB,IAClB,UAAU,EAAE,GAAG,EAAE;gBACf,IAAI,WAAW;oBAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YACvD,CAAC,GACD,GACI,CACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,EAAE,MAAM,EAAE,UAAU,EAAgE;IAC9G,OAAO,CACL,KAAC,KAAK,IAAC,MAAM,EAAE,MAAM,YACnB,KAAC,YAAY,IAAC,UAAU,EAAE,UAAU,GAAI,GAClC,CACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,EAC/B,MAAM,EACN,QAAQ,EACR,WAAW,EAKZ;IACC,OAAO,CACL,KAAC,KAAK,IAAC,MAAM,EAAE,MAAM,YACnB,KAAC,YAAY,IACX,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,GAAG,EAAE;gBACd,IAAI,WAAW;oBAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YACvD,CAAC,GACD,GACI,CACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,EAAE,MAAM,EAA2B;IAC7D,OAAO,CACL,KAAC,KAAK,IAAC,MAAM,EAAE,MAAM,YACnB,KAAC,YAAY,KAAG,GACV,CACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,EAAE,MAAM,EAA2B;IAChE,OAAO,CACL,KAAC,KAAK,IAAC,MAAM,EAAE,MAAM,YACnB,KAAC,eAAe,KAAG,GACb,CACT,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/runtime/react/default-ui/index.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAOlD,wEAAwE;AACxE,+EAA+E;AAC/E,4EAA4E;AAC5E,iCAAiC;AACjC,SAAS,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAgD;IAC/E,OAAO,CACL,KAAC,kBAAkB,cACjB,KAAC,kBAAkB,cACjB,KAAC,aAAa,IAAC,MAAM,EAAE,MAAM,YAAG,QAAQ,GAAiB,GACtC,GACF,CACtB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,EAAE,MAAM,EAAiD;IAClF,OAAO,CACL,KAAC,KAAK,IAAC,MAAM,EAAE,MAAM,YACnB,KAAC,YAAY,IAAC,iBAAiB,SAAG,GAC5B,CACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,EAC1B,MAAM,EACN,UAAU,EACV,iBAAiB,GAAG,KAAK,EAK1B;IACC,OAAO,CACL,KAAC,KAAK,IAAC,MAAM,EAAE,MAAM,YACnB,KAAC,YAAY,IAAC,UAAU,EAAE,UAAU,EAAE,iBAAiB,EAAE,iBAAiB,GAAI,GACxE,CACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,EAAE,MAAM,EAA2B;IAChE,OAAO,CACL,KAAC,KAAK,IAAC,MAAM,EAAE,MAAM,YACnB,KAAC,eAAe,KAAG,GACb,CACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,EAC/B,MAAM,EACN,QAAQ,EACR,WAAW,EAKZ;IACC,OAAO,CACL,KAAC,KAAK,IAAC,MAAM,EAAE,MAAM,YACnB,KAAC,YAAY,IACX,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,GAAG,EAAE;gBACd,IAAI,WAAW;oBAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YACvD,CAAC,GACD,GACI,CACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,EAAE,MAAM,EAA2B;IAC7D,OAAO,CACL,KAAC,KAAK,IAAC,MAAM,EAAE,MAAM,YACnB,KAAC,YAAY,KAAG,GACV,CACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,EAAE,MAAM,EAA2B;IAChE,OAAO,CACL,KAAC,KAAK,IAAC,MAAM,EAAE,MAAM,YACnB,KAAC,eAAe,KAAG,GACb,CACT,CAAC;AACJ,CAAC"}
@@ -1,10 +1,13 @@
1
1
  export { MediaQueryProvider, type MediaQueryProviderProps } from "./MediaQueryProvider.js";
2
2
  export { MediaProvider, useMediaContext, type MediaContextValue } from "./MediaProvider.js";
3
+ export { MediaErrorBoundary, type MediaErrorBoundaryFallbackProps, type MediaErrorBoundaryLabels, type MediaErrorBoundaryProps } from "./MediaErrorBoundary.js";
3
4
  export { RequireSuperuser } from "./RequireSuperuser.js";
4
- export { MediaUploadDropzone } from "./MediaUploadDropzone.js";
5
- export { MediaLibrary } from "./MediaLibrary.js";
5
+ export { MediaUploadDropzone, type MediaUploadDropzoneLabels } from "./MediaUploadDropzone.js";
6
+ export { MediaLibrary, type MediaLibraryLabels } from "./MediaLibrary.js";
6
7
  export { ObjectDetail } from "./ObjectDetail.js";
7
8
  export { VariantPicker } from "./VariantPicker.js";
8
9
  export { PresetEditor } from "./PresetEditor.js";
9
10
  export { AdminMediaPanel } from "./AdminMediaPanel.js";
11
+ export { CategoryMultiSelect, CategoryMultiSelectView, collectCategoryPaths, isSameCategorySelection, type CategoryMultiSelectProps, type CategoryMultiSelectLabels, type CategoryMultiSelectViewProps, type CategoryPathOption } from "./CategoryMultiSelect.js";
12
+ export { CategoryManager } from "./CategoryManager.js";
10
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/runtime/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAC3F,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5F,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/runtime/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAC3F,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5F,OAAO,EACL,kBAAkB,EAClB,KAAK,+BAA+B,EACpC,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,KAAK,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAC/F,OAAO,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,oBAAoB,EACpB,uBAAuB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,4BAA4B,EACjC,KAAK,kBAAkB,EACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
@@ -1,5 +1,6 @@
1
1
  export { MediaQueryProvider } from "./MediaQueryProvider.js";
2
2
  export { MediaProvider, useMediaContext } from "./MediaProvider.js";
3
+ export { MediaErrorBoundary } from "./MediaErrorBoundary.js";
3
4
  export { RequireSuperuser } from "./RequireSuperuser.js";
4
5
  export { MediaUploadDropzone } from "./MediaUploadDropzone.js";
5
6
  export { MediaLibrary } from "./MediaLibrary.js";
@@ -7,4 +8,6 @@ export { ObjectDetail } from "./ObjectDetail.js";
7
8
  export { VariantPicker } from "./VariantPicker.js";
8
9
  export { PresetEditor } from "./PresetEditor.js";
9
10
  export { AdminMediaPanel } from "./AdminMediaPanel.js";
11
+ export { CategoryMultiSelect, CategoryMultiSelectView, collectCategoryPaths, isSameCategorySelection } from "./CategoryMultiSelect.js";
12
+ export { CategoryManager } from "./CategoryManager.js";
10
13
  //# sourceMappingURL=index.js.map