@wordpress/media-utils 5.33.1 → 5.34.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 5.34.0 (2025-10-29)
6
+
5
7
  ## 5.33.0 (2025-10-17)
6
8
 
7
9
  ## 5.32.0 (2025-10-01)
@@ -0,0 +1,253 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var media_upload_modal_exports = {};
20
+ __export(media_upload_modal_exports, {
21
+ MediaUploadModal: () => MediaUploadModal,
22
+ default: () => media_upload_modal_default
23
+ });
24
+ module.exports = __toCommonJS(media_upload_modal_exports);
25
+ var import_jsx_runtime = require("react/jsx-runtime");
26
+ var import_element = require("@wordpress/element");
27
+ var import_i18n = require("@wordpress/i18n");
28
+ var import_core_data = require("@wordpress/core-data");
29
+ var import_data = require("@wordpress/data");
30
+ var import_components = require("@wordpress/components");
31
+ var import_dataviews = require("@wordpress/dataviews");
32
+ var import_transform_attachment = require("../../utils/transform-attachment");
33
+ var import_upload_media = require("../../utils/upload-media");
34
+ var import_lock_unlock = require("../../lock-unlock");
35
+ const { useEntityRecordsWithPermissions } = (0, import_lock_unlock.unlock)(import_core_data.privateApis);
36
+ const LAYOUT_PICKER_GRID = "pickerGrid";
37
+ function MediaUploadModal({
38
+ allowedTypes = ["image"],
39
+ multiple = false,
40
+ value,
41
+ onSelect,
42
+ onClose,
43
+ onUpload,
44
+ title = (0, import_i18n.__)("Select Media"),
45
+ isOpen,
46
+ isDismissible = true,
47
+ modalClass,
48
+ search = true,
49
+ searchLabel = (0, import_i18n.__)("Search media")
50
+ }) {
51
+ const [selection, setSelection] = (0, import_element.useState)(() => {
52
+ if (!value) {
53
+ return [];
54
+ }
55
+ return Array.isArray(value) ? value.map(String) : [String(value)];
56
+ });
57
+ const [view, setView] = (0, import_element.useState)(() => ({
58
+ type: LAYOUT_PICKER_GRID,
59
+ fields: [],
60
+ titleField: "title",
61
+ mediaField: "url",
62
+ search: "",
63
+ page: 1,
64
+ perPage: 20,
65
+ filters: []
66
+ }));
67
+ const queryArgs = (0, import_element.useMemo)(() => {
68
+ const filters = {};
69
+ view.filters?.forEach((filter) => {
70
+ if (filter.field === "media_type") {
71
+ filters.media_type = filter.value;
72
+ }
73
+ if (filter.field === "author") {
74
+ filters.author = filter.value;
75
+ }
76
+ if (filter.field === "date") {
77
+ filters.after = filter.value?.after;
78
+ filters.before = filter.value?.before;
79
+ }
80
+ if (filter.field === "mime_type") {
81
+ filters.mime_type = filter.value;
82
+ }
83
+ });
84
+ if (!filters.media_type) {
85
+ filters.media_type = allowedTypes.includes("*") ? void 0 : allowedTypes[0];
86
+ }
87
+ return {
88
+ per_page: view.perPage || 20,
89
+ page: view.page || 1,
90
+ status: "inherit",
91
+ order: view.sort?.direction,
92
+ orderby: view.sort?.field,
93
+ search: view.search,
94
+ ...filters
95
+ };
96
+ }, [view, allowedTypes]);
97
+ const {
98
+ records: mediaRecords,
99
+ isResolving: isLoading,
100
+ totalItems,
101
+ totalPages
102
+ } = useEntityRecordsWithPermissions("postType", "attachment", queryArgs);
103
+ const fields = (0, import_element.useMemo)(
104
+ () => [
105
+ {
106
+ id: "url",
107
+ type: "media",
108
+ label: (0, import_i18n.__)("Media"),
109
+ render: ({ item }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
110
+ "img",
111
+ {
112
+ src: item.source_url,
113
+ alt: item.alt_text,
114
+ style: {
115
+ width: "100%",
116
+ height: "100%",
117
+ objectFit: "cover",
118
+ borderRadius: "4px"
119
+ }
120
+ }
121
+ )
122
+ },
123
+ {
124
+ id: "title",
125
+ type: "text",
126
+ label: (0, import_i18n.__)("Title"),
127
+ getValue: ({ item }) => {
128
+ const titleValue = item.title.raw || item.title.rendered;
129
+ return titleValue || (0, import_i18n.__)("(no title)");
130
+ }
131
+ },
132
+ {
133
+ id: "alt",
134
+ type: "text",
135
+ label: (0, import_i18n.__)("Alt text"),
136
+ getValue: ({ item }) => item.alt_text
137
+ }
138
+ ],
139
+ []
140
+ );
141
+ const actions = (0, import_element.useMemo)(
142
+ () => [
143
+ {
144
+ id: "select",
145
+ label: multiple ? (0, import_i18n.__)("Select") : (0, import_i18n.__)("Select"),
146
+ isPrimary: true,
147
+ supportsBulk: multiple,
148
+ async callback() {
149
+ if (selection.length === 0) {
150
+ return;
151
+ }
152
+ const selectedPostsQuery = {
153
+ include: selection,
154
+ per_page: -1
155
+ };
156
+ const selectedPosts = await (0, import_data.resolveSelect)(
157
+ import_core_data.store
158
+ ).getEntityRecords(
159
+ "postType",
160
+ "attachment",
161
+ selectedPostsQuery
162
+ );
163
+ const transformedPosts = selectedPosts?.map(import_transform_attachment.transformAttachment);
164
+ const selectedItems = multiple ? transformedPosts : transformedPosts?.[0];
165
+ onSelect(selectedItems);
166
+ }
167
+ }
168
+ ],
169
+ [multiple, onSelect, selection]
170
+ );
171
+ const handleModalClose = (0, import_element.useCallback)(() => {
172
+ onClose?.();
173
+ }, [onClose]);
174
+ const paginationInfo = (0, import_element.useMemo)(
175
+ () => ({
176
+ totalItems,
177
+ totalPages
178
+ }),
179
+ [totalItems, totalPages]
180
+ );
181
+ const defaultLayouts = (0, import_element.useMemo)(
182
+ () => ({
183
+ [LAYOUT_PICKER_GRID]: {}
184
+ }),
185
+ []
186
+ );
187
+ if (!isOpen) {
188
+ return null;
189
+ }
190
+ const handleUpload = onUpload || import_upload_media.uploadMedia;
191
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
192
+ import_components.Modal,
193
+ {
194
+ title,
195
+ onRequestClose: handleModalClose,
196
+ isDismissible,
197
+ className: modalClass,
198
+ size: "fill",
199
+ children: [
200
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
201
+ import_components.DropZone,
202
+ {
203
+ onFilesDrop: (files) => {
204
+ let filteredFiles = files;
205
+ if (allowedTypes && !allowedTypes.includes("*")) {
206
+ filteredFiles = files.filter(
207
+ (file) => allowedTypes.some((allowedType) => {
208
+ return file.type === allowedType || file.type.startsWith(
209
+ allowedType.replace("*", "")
210
+ );
211
+ })
212
+ );
213
+ }
214
+ if (filteredFiles.length > 0) {
215
+ handleUpload({
216
+ allowedTypes,
217
+ filesList: filteredFiles,
218
+ multiple
219
+ });
220
+ }
221
+ },
222
+ label: (0, import_i18n.__)("Drop files to upload")
223
+ }
224
+ ),
225
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
226
+ import_dataviews.DataViewsPicker,
227
+ {
228
+ data: mediaRecords || [],
229
+ fields,
230
+ view,
231
+ onChangeView: setView,
232
+ actions,
233
+ selection,
234
+ onChangeSelection: setSelection,
235
+ isLoading,
236
+ paginationInfo,
237
+ defaultLayouts,
238
+ getItemId: (item) => String(item.id),
239
+ search,
240
+ searchLabel,
241
+ itemListLabel: (0, import_i18n.__)("Media items")
242
+ }
243
+ )
244
+ ]
245
+ }
246
+ );
247
+ }
248
+ var media_upload_modal_default = MediaUploadModal;
249
+ // Annotate the CommonJS export names for ESM import in node:
250
+ 0 && (module.exports = {
251
+ MediaUploadModal
252
+ });
253
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/components/media-upload-modal/index.tsx"],
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useState, useCallback, useMemo } from '@wordpress/element';\nimport { __ } from '@wordpress/i18n';\nimport {\n\tprivateApis as coreDataPrivateApis,\n\tstore as coreStore,\n} from '@wordpress/core-data';\nimport { resolveSelect } from '@wordpress/data';\nimport { Modal, DropZone } from '@wordpress/components';\n\n/**\n * Internal dependencies\n */\nimport { DataViewsPicker } from '@wordpress/dataviews';\nimport type { View, Field, ActionButton } from '@wordpress/dataviews';\nimport type { Attachment, RestAttachment } from '../../utils/types';\nimport { transformAttachment } from '../../utils/transform-attachment';\nimport { uploadMedia } from '../../utils/upload-media';\nimport { unlock } from '../../lock-unlock';\n\nconst { useEntityRecordsWithPermissions } = unlock( coreDataPrivateApis );\n\n// Layout constant - matching the picker grid layout type\nconst LAYOUT_PICKER_GRID = 'pickerGrid';\n\ninterface MediaUploadModalProps {\n\t/**\n\t * Array of allowed media types.\n\t * @default ['image']\n\t */\n\tallowedTypes?: string[];\n\n\t/**\n\t * Whether multiple files can be selected.\n\t * @default false\n\t */\n\tmultiple?: boolean;\n\n\t/**\n\t * The currently selected media item(s).\n\t * Can be a single ID number or array of IDs for multiple selection.\n\t */\n\tvalue?: number | number[];\n\n\t/**\n\t * Function called when media is selected.\n\t * Receives single attachment object or array of attachments.\n\t */\n\tonSelect: ( media: Attachment | Attachment[] ) => void;\n\n\t/**\n\t * Function called when the modal is closed without selection.\n\t */\n\tonClose?: () => void;\n\n\t/**\n\t * Function to handle media uploads.\n\t * If not provided, drag and drop will be disabled.\n\t */\n\tonUpload?: ( args: {\n\t\tallowedTypes?: string[];\n\t\tfilesList: File[];\n\t\tonFileChange?: ( attachments: Partial< Attachment >[] ) => void;\n\t\tonError?: ( error: Error ) => void;\n\t\tmultiple?: boolean;\n\t} ) => void;\n\n\t/**\n\t * Title for the modal.\n\t * @default 'Select Media'\n\t */\n\ttitle?: string;\n\n\t/**\n\t * Whether the modal is open.\n\t */\n\tisOpen: boolean;\n\n\t/**\n\t * Whether the modal can be closed by clicking outside or pressing escape.\n\t * @default true\n\t */\n\tisDismissible?: boolean;\n\n\t/**\n\t * Additional CSS class for the modal.\n\t */\n\tmodalClass?: string;\n\n\t/**\n\t * Whether to show a search input.\n\t * @default true\n\t */\n\tsearch?: boolean;\n\n\t/**\n\t * Label for the search input.\n\t */\n\tsearchLabel?: string;\n}\n\n/**\n * MediaUploadModal component that uses Modal and DataViewsPicker for media selection.\n *\n * This is a modern functional component alternative to the legacy MediaUpload class component.\n * It provides a cleaner API and better integration with the WordPress block editor.\n *\n * @param props Component props\n * @param props.allowedTypes Array of allowed media types\n * @param props.multiple Whether multiple files can be selected\n * @param props.value Currently selected media item(s)\n * @param props.onSelect Function called when media is selected\n * @param props.onClose Function called when modal is closed\n * @param props.onUpload Function to handle media uploads\n * @param props.title Title for the modal\n * @param props.isOpen Whether the modal is open\n * @param props.isDismissible Whether modal can be dismissed\n * @param props.modalClass Additional CSS class for modal\n * @param props.search Whether to show search input\n * @param props.searchLabel Label for search input\n * @return JSX element or null\n */\nexport function MediaUploadModal( {\n\tallowedTypes = [ 'image' ],\n\tmultiple = false,\n\tvalue,\n\tonSelect,\n\tonClose,\n\tonUpload,\n\ttitle = __( 'Select Media' ),\n\tisOpen,\n\tisDismissible = true,\n\tmodalClass,\n\tsearch = true,\n\tsearchLabel = __( 'Search media' ),\n}: MediaUploadModalProps ) {\n\tconst [ selection, setSelection ] = useState< string[] >( () => {\n\t\tif ( ! value ) {\n\t\t\treturn [];\n\t\t}\n\t\treturn Array.isArray( value )\n\t\t\t? value.map( String )\n\t\t\t: [ String( value ) ];\n\t} );\n\n\t// DataViews configuration - allow view updates\n\tconst [ view, setView ] = useState< View >( () => ( {\n\t\ttype: LAYOUT_PICKER_GRID,\n\t\tfields: [],\n\t\ttitleField: 'title',\n\t\tmediaField: 'url',\n\t\tsearch: '',\n\t\tpage: 1,\n\t\tperPage: 20,\n\t\tfilters: [],\n\t} ) );\n\n\t// Build query args based on view properties, similar to PostList\n\tconst queryArgs = useMemo( () => {\n\t\tconst filters: Record< string, any > = {};\n\n\t\tview.filters?.forEach( ( filter ) => {\n\t\t\t// Handle media type filters\n\t\t\tif ( filter.field === 'media_type' ) {\n\t\t\t\tfilters.media_type = filter.value;\n\t\t\t}\n\t\t\t// Handle author filters\n\t\t\tif ( filter.field === 'author' ) {\n\t\t\t\tfilters.author = filter.value;\n\t\t\t}\n\t\t\t// Handle date filters\n\t\t\tif ( filter.field === 'date' ) {\n\t\t\t\tfilters.after = filter.value?.after;\n\t\t\t\tfilters.before = filter.value?.before;\n\t\t\t}\n\t\t\t// Handle mime type filters\n\t\t\tif ( filter.field === 'mime_type' ) {\n\t\t\t\tfilters.mime_type = filter.value;\n\t\t\t}\n\t\t} );\n\n\t\t// Base media type on allowedTypes if no filter is set\n\t\tif ( ! filters.media_type ) {\n\t\t\tfilters.media_type = allowedTypes.includes( '*' )\n\t\t\t\t? undefined\n\t\t\t\t: allowedTypes[ 0 ];\n\t\t}\n\n\t\treturn {\n\t\t\tper_page: view.perPage || 20,\n\t\t\tpage: view.page || 1,\n\t\t\tstatus: 'inherit',\n\t\t\torder: view.sort?.direction,\n\t\t\torderby: view.sort?.field,\n\t\t\tsearch: view.search,\n\t\t\t...filters,\n\t\t};\n\t}, [ view, allowedTypes ] );\n\n\t// Fetch all media attachments using WordPress core data with permissions\n\tconst {\n\t\trecords: mediaRecords,\n\t\tisResolving: isLoading,\n\t\ttotalItems,\n\t\ttotalPages,\n\t} = useEntityRecordsWithPermissions( 'postType', 'attachment', queryArgs );\n\n\tconst fields: Field< RestAttachment >[] = useMemo(\n\t\t() => [\n\t\t\t{\n\t\t\t\tid: 'url',\n\t\t\t\ttype: 'media' as const,\n\t\t\t\tlabel: __( 'Media' ),\n\t\t\t\trender: ( { item }: { item: RestAttachment } ) => (\n\t\t\t\t\t<img\n\t\t\t\t\t\tsrc={ item.source_url }\n\t\t\t\t\t\talt={ item.alt_text }\n\t\t\t\t\t\tstyle={ {\n\t\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t\t\theight: '100%',\n\t\t\t\t\t\t\tobjectFit: 'cover',\n\t\t\t\t\t\t\tborderRadius: '4px',\n\t\t\t\t\t\t} }\n\t\t\t\t\t/>\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'title',\n\t\t\t\ttype: 'text' as const,\n\t\t\t\tlabel: __( 'Title' ),\n\t\t\t\tgetValue: ( { item }: { item: RestAttachment } ) => {\n\t\t\t\t\tconst titleValue = item.title.raw || item.title.rendered;\n\t\t\t\t\treturn titleValue || __( '(no title)' );\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'alt',\n\t\t\t\ttype: 'text' as const,\n\t\t\t\tlabel: __( 'Alt text' ),\n\t\t\t\tgetValue: ( { item }: { item: RestAttachment } ) =>\n\t\t\t\t\titem.alt_text,\n\t\t\t},\n\t\t],\n\t\t[]\n\t);\n\n\tconst actions: ActionButton< RestAttachment >[] = useMemo(\n\t\t() => [\n\t\t\t{\n\t\t\t\tid: 'select',\n\t\t\t\tlabel: multiple ? __( 'Select' ) : __( 'Select' ),\n\t\t\t\tisPrimary: true,\n\t\t\t\tsupportsBulk: multiple,\n\t\t\t\tasync callback() {\n\t\t\t\t\tif ( selection.length === 0 ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst selectedPostsQuery = {\n\t\t\t\t\t\tinclude: selection,\n\t\t\t\t\t\tper_page: -1,\n\t\t\t\t\t};\n\n\t\t\t\t\tconst selectedPosts = await resolveSelect(\n\t\t\t\t\t\tcoreStore\n\t\t\t\t\t).getEntityRecords(\n\t\t\t\t\t\t'postType',\n\t\t\t\t\t\t'attachment',\n\t\t\t\t\t\tselectedPostsQuery\n\t\t\t\t\t);\n\n\t\t\t\t\t// Transform the selected posts to the expected Attachment format\n\t\t\t\t\tconst transformedPosts =\n\t\t\t\t\t\tselectedPosts?.map( transformAttachment );\n\n\t\t\t\t\tconst selectedItems = multiple\n\t\t\t\t\t\t? transformedPosts\n\t\t\t\t\t\t: transformedPosts?.[ 0 ];\n\n\t\t\t\t\tonSelect( selectedItems );\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[ multiple, onSelect, selection ]\n\t);\n\n\tconst handleModalClose = useCallback( () => {\n\t\tonClose?.();\n\t}, [ onClose ] );\n\n\tconst paginationInfo = useMemo(\n\t\t() => ( {\n\t\t\ttotalItems,\n\t\t\ttotalPages,\n\t\t} ),\n\t\t[ totalItems, totalPages ]\n\t);\n\n\tconst defaultLayouts = useMemo(\n\t\t() => ( {\n\t\t\t[ LAYOUT_PICKER_GRID ]: {},\n\t\t} ),\n\t\t[]\n\t);\n\n\tif ( ! isOpen ) {\n\t\treturn null;\n\t}\n\n\t// Use onUpload if provided, otherwise fall back to uploadMedia\n\tconst handleUpload = onUpload || uploadMedia;\n\n\treturn (\n\t\t<Modal\n\t\t\ttitle={ title }\n\t\t\tonRequestClose={ handleModalClose }\n\t\t\tisDismissible={ isDismissible }\n\t\t\tclassName={ modalClass }\n\t\t\tsize=\"fill\"\n\t\t>\n\t\t\t<DropZone\n\t\t\t\tonFilesDrop={ ( files ) => {\n\t\t\t\t\tlet filteredFiles = files;\n\t\t\t\t\t// Filter files by allowed types if specified\n\t\t\t\t\tif ( allowedTypes && ! allowedTypes.includes( '*' ) ) {\n\t\t\t\t\t\tfilteredFiles = files.filter( ( file ) =>\n\t\t\t\t\t\t\tallowedTypes.some( ( allowedType ) => {\n\t\t\t\t\t\t\t\t// Check if the file type matches the allowed MIME type\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\tfile.type === allowedType ||\n\t\t\t\t\t\t\t\t\tfile.type.startsWith(\n\t\t\t\t\t\t\t\t\t\tallowedType.replace( '*', '' )\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif ( filteredFiles.length > 0 ) {\n\t\t\t\t\t\thandleUpload( {\n\t\t\t\t\t\t\tallowedTypes,\n\t\t\t\t\t\t\tfilesList: filteredFiles,\n\t\t\t\t\t\t\tmultiple,\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t} }\n\t\t\t\tlabel={ __( 'Drop files to upload' ) }\n\t\t\t/>\n\t\t\t<DataViewsPicker\n\t\t\t\tdata={ mediaRecords || [] }\n\t\t\t\tfields={ fields }\n\t\t\t\tview={ view }\n\t\t\t\tonChangeView={ setView }\n\t\t\t\tactions={ actions }\n\t\t\t\tselection={ selection }\n\t\t\t\tonChangeSelection={ setSelection }\n\t\t\t\tisLoading={ isLoading }\n\t\t\t\tpaginationInfo={ paginationInfo }\n\t\t\t\tdefaultLayouts={ defaultLayouts }\n\t\t\t\tgetItemId={ ( item: RestAttachment ) => String( item.id ) }\n\t\t\t\tsearch={ search }\n\t\t\t\tsearchLabel={ searchLabel }\n\t\t\t\titemListLabel={ __( 'Media items' ) }\n\t\t\t/>\n\t\t</Modal>\n\t);\n}\n\nexport default MediaUploadModal;\n"],
5
+ "mappings": "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",
6
+ "names": ["coreDataPrivateApis", "coreStore"]
7
+ }
@@ -22,10 +22,12 @@ __export(private_apis_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(private_apis_exports);
24
24
  var import_sideload_media = require("./utils/sideload-media");
25
+ var import_media_upload_modal = require("./components/media-upload-modal");
25
26
  var import_lock_unlock = require("./lock-unlock");
26
27
  const privateApis = {};
27
28
  (0, import_lock_unlock.lock)(privateApis, {
28
- sideloadMedia: import_sideload_media.sideloadMedia
29
+ sideloadMedia: import_sideload_media.sideloadMedia,
30
+ MediaUploadModal: import_media_upload_modal.MediaUploadModal
29
31
  });
30
32
  // Annotate the CommonJS export names for ESM import in node:
31
33
  0 && (module.exports = {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/private-apis.ts"],
4
- "sourcesContent": ["/**\n * Internal dependencies\n */\nimport { sideloadMedia } from './utils/sideload-media';\nimport { lock } from './lock-unlock';\n\n/**\n * Private @wordpress/media-utils APIs.\n */\nexport const privateApis = {};\n\nlock( privateApis, {\n\tsideloadMedia,\n} );\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,4BAA8B;AAC9B,yBAAqB;AAKd,MAAM,cAAc,CAAC;AAAA,IAE5B,yBAAM,aAAa;AAAA,EAClB;AACD,CAAE;",
4
+ "sourcesContent": ["/**\n * Internal dependencies\n */\nimport { sideloadMedia } from './utils/sideload-media';\nimport { MediaUploadModal } from './components/media-upload-modal';\nimport { lock } from './lock-unlock';\n\n/**\n * Private @wordpress/media-utils APIs.\n */\nexport const privateApis = {};\n\nlock( privateApis, {\n\tsideloadMedia,\n\tMediaUploadModal,\n} );\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,4BAA8B;AAC9B,gCAAiC;AACjC,yBAAqB;AAKd,MAAM,cAAc,CAAC;AAAA,IAE5B,yBAAM,aAAa;AAAA,EAClB;AAAA,EACA;AACD,CAAE;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,232 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useState, useCallback, useMemo } from "@wordpress/element";
3
+ import { __ } from "@wordpress/i18n";
4
+ import {
5
+ privateApis as coreDataPrivateApis,
6
+ store as coreStore
7
+ } from "@wordpress/core-data";
8
+ import { resolveSelect } from "@wordpress/data";
9
+ import { Modal, DropZone } from "@wordpress/components";
10
+ import { DataViewsPicker } from "@wordpress/dataviews";
11
+ import { transformAttachment } from "../../utils/transform-attachment";
12
+ import { uploadMedia } from "../../utils/upload-media";
13
+ import { unlock } from "../../lock-unlock";
14
+ const { useEntityRecordsWithPermissions } = unlock(coreDataPrivateApis);
15
+ const LAYOUT_PICKER_GRID = "pickerGrid";
16
+ function MediaUploadModal({
17
+ allowedTypes = ["image"],
18
+ multiple = false,
19
+ value,
20
+ onSelect,
21
+ onClose,
22
+ onUpload,
23
+ title = __("Select Media"),
24
+ isOpen,
25
+ isDismissible = true,
26
+ modalClass,
27
+ search = true,
28
+ searchLabel = __("Search media")
29
+ }) {
30
+ const [selection, setSelection] = useState(() => {
31
+ if (!value) {
32
+ return [];
33
+ }
34
+ return Array.isArray(value) ? value.map(String) : [String(value)];
35
+ });
36
+ const [view, setView] = useState(() => ({
37
+ type: LAYOUT_PICKER_GRID,
38
+ fields: [],
39
+ titleField: "title",
40
+ mediaField: "url",
41
+ search: "",
42
+ page: 1,
43
+ perPage: 20,
44
+ filters: []
45
+ }));
46
+ const queryArgs = useMemo(() => {
47
+ const filters = {};
48
+ view.filters?.forEach((filter) => {
49
+ if (filter.field === "media_type") {
50
+ filters.media_type = filter.value;
51
+ }
52
+ if (filter.field === "author") {
53
+ filters.author = filter.value;
54
+ }
55
+ if (filter.field === "date") {
56
+ filters.after = filter.value?.after;
57
+ filters.before = filter.value?.before;
58
+ }
59
+ if (filter.field === "mime_type") {
60
+ filters.mime_type = filter.value;
61
+ }
62
+ });
63
+ if (!filters.media_type) {
64
+ filters.media_type = allowedTypes.includes("*") ? void 0 : allowedTypes[0];
65
+ }
66
+ return {
67
+ per_page: view.perPage || 20,
68
+ page: view.page || 1,
69
+ status: "inherit",
70
+ order: view.sort?.direction,
71
+ orderby: view.sort?.field,
72
+ search: view.search,
73
+ ...filters
74
+ };
75
+ }, [view, allowedTypes]);
76
+ const {
77
+ records: mediaRecords,
78
+ isResolving: isLoading,
79
+ totalItems,
80
+ totalPages
81
+ } = useEntityRecordsWithPermissions("postType", "attachment", queryArgs);
82
+ const fields = useMemo(
83
+ () => [
84
+ {
85
+ id: "url",
86
+ type: "media",
87
+ label: __("Media"),
88
+ render: ({ item }) => /* @__PURE__ */ jsx(
89
+ "img",
90
+ {
91
+ src: item.source_url,
92
+ alt: item.alt_text,
93
+ style: {
94
+ width: "100%",
95
+ height: "100%",
96
+ objectFit: "cover",
97
+ borderRadius: "4px"
98
+ }
99
+ }
100
+ )
101
+ },
102
+ {
103
+ id: "title",
104
+ type: "text",
105
+ label: __("Title"),
106
+ getValue: ({ item }) => {
107
+ const titleValue = item.title.raw || item.title.rendered;
108
+ return titleValue || __("(no title)");
109
+ }
110
+ },
111
+ {
112
+ id: "alt",
113
+ type: "text",
114
+ label: __("Alt text"),
115
+ getValue: ({ item }) => item.alt_text
116
+ }
117
+ ],
118
+ []
119
+ );
120
+ const actions = useMemo(
121
+ () => [
122
+ {
123
+ id: "select",
124
+ label: multiple ? __("Select") : __("Select"),
125
+ isPrimary: true,
126
+ supportsBulk: multiple,
127
+ async callback() {
128
+ if (selection.length === 0) {
129
+ return;
130
+ }
131
+ const selectedPostsQuery = {
132
+ include: selection,
133
+ per_page: -1
134
+ };
135
+ const selectedPosts = await resolveSelect(
136
+ coreStore
137
+ ).getEntityRecords(
138
+ "postType",
139
+ "attachment",
140
+ selectedPostsQuery
141
+ );
142
+ const transformedPosts = selectedPosts?.map(transformAttachment);
143
+ const selectedItems = multiple ? transformedPosts : transformedPosts?.[0];
144
+ onSelect(selectedItems);
145
+ }
146
+ }
147
+ ],
148
+ [multiple, onSelect, selection]
149
+ );
150
+ const handleModalClose = useCallback(() => {
151
+ onClose?.();
152
+ }, [onClose]);
153
+ const paginationInfo = useMemo(
154
+ () => ({
155
+ totalItems,
156
+ totalPages
157
+ }),
158
+ [totalItems, totalPages]
159
+ );
160
+ const defaultLayouts = useMemo(
161
+ () => ({
162
+ [LAYOUT_PICKER_GRID]: {}
163
+ }),
164
+ []
165
+ );
166
+ if (!isOpen) {
167
+ return null;
168
+ }
169
+ const handleUpload = onUpload || uploadMedia;
170
+ return /* @__PURE__ */ jsxs(
171
+ Modal,
172
+ {
173
+ title,
174
+ onRequestClose: handleModalClose,
175
+ isDismissible,
176
+ className: modalClass,
177
+ size: "fill",
178
+ children: [
179
+ /* @__PURE__ */ jsx(
180
+ DropZone,
181
+ {
182
+ onFilesDrop: (files) => {
183
+ let filteredFiles = files;
184
+ if (allowedTypes && !allowedTypes.includes("*")) {
185
+ filteredFiles = files.filter(
186
+ (file) => allowedTypes.some((allowedType) => {
187
+ return file.type === allowedType || file.type.startsWith(
188
+ allowedType.replace("*", "")
189
+ );
190
+ })
191
+ );
192
+ }
193
+ if (filteredFiles.length > 0) {
194
+ handleUpload({
195
+ allowedTypes,
196
+ filesList: filteredFiles,
197
+ multiple
198
+ });
199
+ }
200
+ },
201
+ label: __("Drop files to upload")
202
+ }
203
+ ),
204
+ /* @__PURE__ */ jsx(
205
+ DataViewsPicker,
206
+ {
207
+ data: mediaRecords || [],
208
+ fields,
209
+ view,
210
+ onChangeView: setView,
211
+ actions,
212
+ selection,
213
+ onChangeSelection: setSelection,
214
+ isLoading,
215
+ paginationInfo,
216
+ defaultLayouts,
217
+ getItemId: (item) => String(item.id),
218
+ search,
219
+ searchLabel,
220
+ itemListLabel: __("Media items")
221
+ }
222
+ )
223
+ ]
224
+ }
225
+ );
226
+ }
227
+ var media_upload_modal_default = MediaUploadModal;
228
+ export {
229
+ MediaUploadModal,
230
+ media_upload_modal_default as default
231
+ };
232
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/components/media-upload-modal/index.tsx"],
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useState, useCallback, useMemo } from '@wordpress/element';\nimport { __ } from '@wordpress/i18n';\nimport {\n\tprivateApis as coreDataPrivateApis,\n\tstore as coreStore,\n} from '@wordpress/core-data';\nimport { resolveSelect } from '@wordpress/data';\nimport { Modal, DropZone } from '@wordpress/components';\n\n/**\n * Internal dependencies\n */\nimport { DataViewsPicker } from '@wordpress/dataviews';\nimport type { View, Field, ActionButton } from '@wordpress/dataviews';\nimport type { Attachment, RestAttachment } from '../../utils/types';\nimport { transformAttachment } from '../../utils/transform-attachment';\nimport { uploadMedia } from '../../utils/upload-media';\nimport { unlock } from '../../lock-unlock';\n\nconst { useEntityRecordsWithPermissions } = unlock( coreDataPrivateApis );\n\n// Layout constant - matching the picker grid layout type\nconst LAYOUT_PICKER_GRID = 'pickerGrid';\n\ninterface MediaUploadModalProps {\n\t/**\n\t * Array of allowed media types.\n\t * @default ['image']\n\t */\n\tallowedTypes?: string[];\n\n\t/**\n\t * Whether multiple files can be selected.\n\t * @default false\n\t */\n\tmultiple?: boolean;\n\n\t/**\n\t * The currently selected media item(s).\n\t * Can be a single ID number or array of IDs for multiple selection.\n\t */\n\tvalue?: number | number[];\n\n\t/**\n\t * Function called when media is selected.\n\t * Receives single attachment object or array of attachments.\n\t */\n\tonSelect: ( media: Attachment | Attachment[] ) => void;\n\n\t/**\n\t * Function called when the modal is closed without selection.\n\t */\n\tonClose?: () => void;\n\n\t/**\n\t * Function to handle media uploads.\n\t * If not provided, drag and drop will be disabled.\n\t */\n\tonUpload?: ( args: {\n\t\tallowedTypes?: string[];\n\t\tfilesList: File[];\n\t\tonFileChange?: ( attachments: Partial< Attachment >[] ) => void;\n\t\tonError?: ( error: Error ) => void;\n\t\tmultiple?: boolean;\n\t} ) => void;\n\n\t/**\n\t * Title for the modal.\n\t * @default 'Select Media'\n\t */\n\ttitle?: string;\n\n\t/**\n\t * Whether the modal is open.\n\t */\n\tisOpen: boolean;\n\n\t/**\n\t * Whether the modal can be closed by clicking outside or pressing escape.\n\t * @default true\n\t */\n\tisDismissible?: boolean;\n\n\t/**\n\t * Additional CSS class for the modal.\n\t */\n\tmodalClass?: string;\n\n\t/**\n\t * Whether to show a search input.\n\t * @default true\n\t */\n\tsearch?: boolean;\n\n\t/**\n\t * Label for the search input.\n\t */\n\tsearchLabel?: string;\n}\n\n/**\n * MediaUploadModal component that uses Modal and DataViewsPicker for media selection.\n *\n * This is a modern functional component alternative to the legacy MediaUpload class component.\n * It provides a cleaner API and better integration with the WordPress block editor.\n *\n * @param props Component props\n * @param props.allowedTypes Array of allowed media types\n * @param props.multiple Whether multiple files can be selected\n * @param props.value Currently selected media item(s)\n * @param props.onSelect Function called when media is selected\n * @param props.onClose Function called when modal is closed\n * @param props.onUpload Function to handle media uploads\n * @param props.title Title for the modal\n * @param props.isOpen Whether the modal is open\n * @param props.isDismissible Whether modal can be dismissed\n * @param props.modalClass Additional CSS class for modal\n * @param props.search Whether to show search input\n * @param props.searchLabel Label for search input\n * @return JSX element or null\n */\nexport function MediaUploadModal( {\n\tallowedTypes = [ 'image' ],\n\tmultiple = false,\n\tvalue,\n\tonSelect,\n\tonClose,\n\tonUpload,\n\ttitle = __( 'Select Media' ),\n\tisOpen,\n\tisDismissible = true,\n\tmodalClass,\n\tsearch = true,\n\tsearchLabel = __( 'Search media' ),\n}: MediaUploadModalProps ) {\n\tconst [ selection, setSelection ] = useState< string[] >( () => {\n\t\tif ( ! value ) {\n\t\t\treturn [];\n\t\t}\n\t\treturn Array.isArray( value )\n\t\t\t? value.map( String )\n\t\t\t: [ String( value ) ];\n\t} );\n\n\t// DataViews configuration - allow view updates\n\tconst [ view, setView ] = useState< View >( () => ( {\n\t\ttype: LAYOUT_PICKER_GRID,\n\t\tfields: [],\n\t\ttitleField: 'title',\n\t\tmediaField: 'url',\n\t\tsearch: '',\n\t\tpage: 1,\n\t\tperPage: 20,\n\t\tfilters: [],\n\t} ) );\n\n\t// Build query args based on view properties, similar to PostList\n\tconst queryArgs = useMemo( () => {\n\t\tconst filters: Record< string, any > = {};\n\n\t\tview.filters?.forEach( ( filter ) => {\n\t\t\t// Handle media type filters\n\t\t\tif ( filter.field === 'media_type' ) {\n\t\t\t\tfilters.media_type = filter.value;\n\t\t\t}\n\t\t\t// Handle author filters\n\t\t\tif ( filter.field === 'author' ) {\n\t\t\t\tfilters.author = filter.value;\n\t\t\t}\n\t\t\t// Handle date filters\n\t\t\tif ( filter.field === 'date' ) {\n\t\t\t\tfilters.after = filter.value?.after;\n\t\t\t\tfilters.before = filter.value?.before;\n\t\t\t}\n\t\t\t// Handle mime type filters\n\t\t\tif ( filter.field === 'mime_type' ) {\n\t\t\t\tfilters.mime_type = filter.value;\n\t\t\t}\n\t\t} );\n\n\t\t// Base media type on allowedTypes if no filter is set\n\t\tif ( ! filters.media_type ) {\n\t\t\tfilters.media_type = allowedTypes.includes( '*' )\n\t\t\t\t? undefined\n\t\t\t\t: allowedTypes[ 0 ];\n\t\t}\n\n\t\treturn {\n\t\t\tper_page: view.perPage || 20,\n\t\t\tpage: view.page || 1,\n\t\t\tstatus: 'inherit',\n\t\t\torder: view.sort?.direction,\n\t\t\torderby: view.sort?.field,\n\t\t\tsearch: view.search,\n\t\t\t...filters,\n\t\t};\n\t}, [ view, allowedTypes ] );\n\n\t// Fetch all media attachments using WordPress core data with permissions\n\tconst {\n\t\trecords: mediaRecords,\n\t\tisResolving: isLoading,\n\t\ttotalItems,\n\t\ttotalPages,\n\t} = useEntityRecordsWithPermissions( 'postType', 'attachment', queryArgs );\n\n\tconst fields: Field< RestAttachment >[] = useMemo(\n\t\t() => [\n\t\t\t{\n\t\t\t\tid: 'url',\n\t\t\t\ttype: 'media' as const,\n\t\t\t\tlabel: __( 'Media' ),\n\t\t\t\trender: ( { item }: { item: RestAttachment } ) => (\n\t\t\t\t\t<img\n\t\t\t\t\t\tsrc={ item.source_url }\n\t\t\t\t\t\talt={ item.alt_text }\n\t\t\t\t\t\tstyle={ {\n\t\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t\t\theight: '100%',\n\t\t\t\t\t\t\tobjectFit: 'cover',\n\t\t\t\t\t\t\tborderRadius: '4px',\n\t\t\t\t\t\t} }\n\t\t\t\t\t/>\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'title',\n\t\t\t\ttype: 'text' as const,\n\t\t\t\tlabel: __( 'Title' ),\n\t\t\t\tgetValue: ( { item }: { item: RestAttachment } ) => {\n\t\t\t\t\tconst titleValue = item.title.raw || item.title.rendered;\n\t\t\t\t\treturn titleValue || __( '(no title)' );\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'alt',\n\t\t\t\ttype: 'text' as const,\n\t\t\t\tlabel: __( 'Alt text' ),\n\t\t\t\tgetValue: ( { item }: { item: RestAttachment } ) =>\n\t\t\t\t\titem.alt_text,\n\t\t\t},\n\t\t],\n\t\t[]\n\t);\n\n\tconst actions: ActionButton< RestAttachment >[] = useMemo(\n\t\t() => [\n\t\t\t{\n\t\t\t\tid: 'select',\n\t\t\t\tlabel: multiple ? __( 'Select' ) : __( 'Select' ),\n\t\t\t\tisPrimary: true,\n\t\t\t\tsupportsBulk: multiple,\n\t\t\t\tasync callback() {\n\t\t\t\t\tif ( selection.length === 0 ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst selectedPostsQuery = {\n\t\t\t\t\t\tinclude: selection,\n\t\t\t\t\t\tper_page: -1,\n\t\t\t\t\t};\n\n\t\t\t\t\tconst selectedPosts = await resolveSelect(\n\t\t\t\t\t\tcoreStore\n\t\t\t\t\t).getEntityRecords(\n\t\t\t\t\t\t'postType',\n\t\t\t\t\t\t'attachment',\n\t\t\t\t\t\tselectedPostsQuery\n\t\t\t\t\t);\n\n\t\t\t\t\t// Transform the selected posts to the expected Attachment format\n\t\t\t\t\tconst transformedPosts =\n\t\t\t\t\t\tselectedPosts?.map( transformAttachment );\n\n\t\t\t\t\tconst selectedItems = multiple\n\t\t\t\t\t\t? transformedPosts\n\t\t\t\t\t\t: transformedPosts?.[ 0 ];\n\n\t\t\t\t\tonSelect( selectedItems );\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[ multiple, onSelect, selection ]\n\t);\n\n\tconst handleModalClose = useCallback( () => {\n\t\tonClose?.();\n\t}, [ onClose ] );\n\n\tconst paginationInfo = useMemo(\n\t\t() => ( {\n\t\t\ttotalItems,\n\t\t\ttotalPages,\n\t\t} ),\n\t\t[ totalItems, totalPages ]\n\t);\n\n\tconst defaultLayouts = useMemo(\n\t\t() => ( {\n\t\t\t[ LAYOUT_PICKER_GRID ]: {},\n\t\t} ),\n\t\t[]\n\t);\n\n\tif ( ! isOpen ) {\n\t\treturn null;\n\t}\n\n\t// Use onUpload if provided, otherwise fall back to uploadMedia\n\tconst handleUpload = onUpload || uploadMedia;\n\n\treturn (\n\t\t<Modal\n\t\t\ttitle={ title }\n\t\t\tonRequestClose={ handleModalClose }\n\t\t\tisDismissible={ isDismissible }\n\t\t\tclassName={ modalClass }\n\t\t\tsize=\"fill\"\n\t\t>\n\t\t\t<DropZone\n\t\t\t\tonFilesDrop={ ( files ) => {\n\t\t\t\t\tlet filteredFiles = files;\n\t\t\t\t\t// Filter files by allowed types if specified\n\t\t\t\t\tif ( allowedTypes && ! allowedTypes.includes( '*' ) ) {\n\t\t\t\t\t\tfilteredFiles = files.filter( ( file ) =>\n\t\t\t\t\t\t\tallowedTypes.some( ( allowedType ) => {\n\t\t\t\t\t\t\t\t// Check if the file type matches the allowed MIME type\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\tfile.type === allowedType ||\n\t\t\t\t\t\t\t\t\tfile.type.startsWith(\n\t\t\t\t\t\t\t\t\t\tallowedType.replace( '*', '' )\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif ( filteredFiles.length > 0 ) {\n\t\t\t\t\t\thandleUpload( {\n\t\t\t\t\t\t\tallowedTypes,\n\t\t\t\t\t\t\tfilesList: filteredFiles,\n\t\t\t\t\t\t\tmultiple,\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t} }\n\t\t\t\tlabel={ __( 'Drop files to upload' ) }\n\t\t\t/>\n\t\t\t<DataViewsPicker\n\t\t\t\tdata={ mediaRecords || [] }\n\t\t\t\tfields={ fields }\n\t\t\t\tview={ view }\n\t\t\t\tonChangeView={ setView }\n\t\t\t\tactions={ actions }\n\t\t\t\tselection={ selection }\n\t\t\t\tonChangeSelection={ setSelection }\n\t\t\t\tisLoading={ isLoading }\n\t\t\t\tpaginationInfo={ paginationInfo }\n\t\t\t\tdefaultLayouts={ defaultLayouts }\n\t\t\t\tgetItemId={ ( item: RestAttachment ) => String( item.id ) }\n\t\t\t\tsearch={ search }\n\t\t\t\tsearchLabel={ searchLabel }\n\t\t\t\titemListLabel={ __( 'Media items' ) }\n\t\t\t/>\n\t\t</Modal>\n\t);\n}\n\nexport default MediaUploadModal;\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,8 +1,10 @@
1
1
  import { sideloadMedia } from "./utils/sideload-media";
2
+ import { MediaUploadModal } from "./components/media-upload-modal";
2
3
  import { lock } from "./lock-unlock";
3
4
  const privateApis = {};
4
5
  lock(privateApis, {
5
- sideloadMedia
6
+ sideloadMedia,
7
+ MediaUploadModal
6
8
  });
7
9
  export {
8
10
  privateApis
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/private-apis.ts"],
4
- "sourcesContent": ["/**\n * Internal dependencies\n */\nimport { sideloadMedia } from './utils/sideload-media';\nimport { lock } from './lock-unlock';\n\n/**\n * Private @wordpress/media-utils APIs.\n */\nexport const privateApis = {};\n\nlock( privateApis, {\n\tsideloadMedia,\n} );\n"],
5
- "mappings": "AAGA,SAAS,qBAAqB;AAC9B,SAAS,YAAY;AAKd,MAAM,cAAc,CAAC;AAE5B,KAAM,aAAa;AAAA,EAClB;AACD,CAAE;",
4
+ "sourcesContent": ["/**\n * Internal dependencies\n */\nimport { sideloadMedia } from './utils/sideload-media';\nimport { MediaUploadModal } from './components/media-upload-modal';\nimport { lock } from './lock-unlock';\n\n/**\n * Private @wordpress/media-utils APIs.\n */\nexport const privateApis = {};\n\nlock( privateApis, {\n\tsideloadMedia,\n\tMediaUploadModal,\n} );\n"],
5
+ "mappings": "AAGA,SAAS,qBAAqB;AAC9B,SAAS,wBAAwB;AACjC,SAAS,YAAY;AAKd,MAAM,cAAc,CAAC;AAE5B,KAAM,aAAa;AAAA,EAClB;AAAA,EACA;AACD,CAAE;",
6
6
  "names": []
7
7
  }