sanity-plugin-s3-media 1.2.2 → 1.3.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/README.md +10 -5
- package/dist/_chunks-cjs/asset-utils.js +60 -7
- package/dist/_chunks-cjs/asset-utils.js.map +1 -1
- package/dist/_chunks-cjs/client.js +66 -30
- package/dist/_chunks-cjs/client.js.map +1 -1
- package/dist/_chunks-es/asset-utils.mjs +61 -8
- package/dist/_chunks-es/asset-utils.mjs.map +1 -1
- package/dist/_chunks-es/client.mjs +67 -31
- package/dist/_chunks-es/client.mjs.map +1 -1
- package/dist/asset-utils.d.mts +78 -3
- package/dist/asset-utils.d.ts +78 -3
- package/dist/asset-utils.js +3 -0
- package/dist/asset-utils.js.map +1 -1
- package/dist/asset-utils.mjs +5 -2
- package/dist/client.d.mts +2 -1
- package/dist/client.d.ts +2 -1
- package/dist/index.d.mts +207 -0
- package/dist/index.d.ts +207 -0
- package/dist/index.js +328 -195
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +330 -197
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# sanity-plugin-s3-media
|
|
2
2
|
|
|
3
3
|
Sanity Studio plugin that adds an S3-backed media browser, asset sources, and
|
|
4
|
-
schema types for files and
|
|
4
|
+
schema types for files, images, and videos stored in AWS S3.
|
|
5
5
|
|
|
6
6
|
## Features
|
|
7
7
|
|
|
8
8
|
- Media tool in Studio for browsing, searching, and managing S3 assets.
|
|
9
|
-
- Asset sources for `s3Image` and `
|
|
9
|
+
- Asset sources for `s3Image`, `s3File`, and `s3Video` inputs.
|
|
10
10
|
- Direct uploads to S3 via a signed URL endpoint.
|
|
11
11
|
- Optional CloudFront domain for delivery URLs.
|
|
12
12
|
- Utilities to build S3 asset URLs from document IDs.
|
|
@@ -42,8 +42,8 @@ Plugin options:
|
|
|
42
42
|
|
|
43
43
|
### 2) Add schema types
|
|
44
44
|
|
|
45
|
-
This plugin provides `s3Image` and `
|
|
46
|
-
`s3ImageAsset` and `
|
|
45
|
+
This plugin provides `s3Image`, `s3File`, and `s3Video` object types that reference
|
|
46
|
+
`s3ImageAsset`, `s3FileAsset`, and `s3VideoAsset` documents. Use them like any other field:
|
|
47
47
|
|
|
48
48
|
```ts
|
|
49
49
|
import {defineField, defineType} from 'sanity'
|
|
@@ -66,6 +66,10 @@ export const product = defineType({
|
|
|
66
66
|
accept: 'application/pdf',
|
|
67
67
|
},
|
|
68
68
|
}),
|
|
69
|
+
defineField({
|
|
70
|
+
name: 'promoVideo',
|
|
71
|
+
type: 's3Video',
|
|
72
|
+
}),
|
|
69
73
|
],
|
|
70
74
|
})
|
|
71
75
|
```
|
|
@@ -140,10 +144,11 @@ Response: any 2xx status is treated as success.
|
|
|
140
144
|
The package also exports helpers for constructing asset URLs:
|
|
141
145
|
|
|
142
146
|
```ts
|
|
143
|
-
import {buildS3FileUrl, buildS3ImageUrl} from 'sanity-plugin-s3-media'
|
|
147
|
+
import {buildS3FileUrl, buildS3ImageUrl, buildS3VideoUrl} from 'sanity-plugin-s3-media'
|
|
144
148
|
|
|
145
149
|
const fileUrl = buildS3FileUrl('s3File-<assetId>-<ext>', {baseUrl})
|
|
146
150
|
const imageUrl = buildS3ImageUrl('s3Image-<assetId>-<width>x<height>-<ext>', {baseUrl})
|
|
151
|
+
const videoUrl = buildS3VideoUrl('s3Video-<assetId>-<width>x<height>-<ext>', {baseUrl})
|
|
147
152
|
```
|
|
148
153
|
|
|
149
154
|
## Troubleshooting
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var sanity = require("sanity");
|
|
3
3
|
let S3AssetType = /* @__PURE__ */ (function(S3AssetType2) {
|
|
4
|
-
return S3AssetType2.FILE = "s3File", S3AssetType2.IMAGE = "s3Image", S3AssetType2;
|
|
4
|
+
return S3AssetType2.FILE = "s3File", S3AssetType2.IMAGE = "s3Image", S3AssetType2.VIDEO = "s3Video", S3AssetType2;
|
|
5
5
|
})({});
|
|
6
6
|
function parseFileAssetId(documentId) {
|
|
7
7
|
const [, assetId, extension] = documentId.split("-");
|
|
8
8
|
if (!assetId || !extension)
|
|
9
9
|
throw new Error(`Malformed file asset ID '${documentId}'.`);
|
|
10
10
|
return {
|
|
11
|
-
type:
|
|
11
|
+
type: S3AssetType.FILE,
|
|
12
12
|
assetId,
|
|
13
13
|
extension
|
|
14
14
|
};
|
|
@@ -18,7 +18,19 @@ function parseImageAssetId(documentId) {
|
|
|
18
18
|
if (!assetId || !dimensionString || !extension || !(width > 0) || !(height > 0))
|
|
19
19
|
throw new Error(`Malformed asset ID '${documentId}'.`);
|
|
20
20
|
return {
|
|
21
|
-
type:
|
|
21
|
+
type: S3AssetType.IMAGE,
|
|
22
|
+
assetId,
|
|
23
|
+
width,
|
|
24
|
+
height,
|
|
25
|
+
extension
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function parseVideoAssetId(documentId) {
|
|
29
|
+
const [, assetId, dimensionString, extension] = documentId.split("-"), [width, height] = (dimensionString || "").split("x").map(Number);
|
|
30
|
+
if (!assetId || !dimensionString || !extension || !(width > 0) || !(height > 0))
|
|
31
|
+
throw new Error(`Malformed asset ID '${documentId}'.`);
|
|
32
|
+
return {
|
|
33
|
+
type: S3AssetType.VIDEO,
|
|
22
34
|
assetId,
|
|
23
35
|
width,
|
|
24
36
|
height,
|
|
@@ -47,10 +59,22 @@ function buildS3ImagePath(documentId) {
|
|
|
47
59
|
function buildS3ImageUrl(assetId, options) {
|
|
48
60
|
return `${options?.baseUrl}/${buildS3ImagePath(assetId)}`;
|
|
49
61
|
}
|
|
62
|
+
function buildS3VideoPath(documentId) {
|
|
63
|
+
const {
|
|
64
|
+
assetId,
|
|
65
|
+
width,
|
|
66
|
+
height,
|
|
67
|
+
extension
|
|
68
|
+
} = parseVideoAssetId(documentId);
|
|
69
|
+
return `${assetId}-${width}x${height}.${extension}`;
|
|
70
|
+
}
|
|
71
|
+
function buildS3VideoUrl(assetId, options) {
|
|
72
|
+
return `${options?.baseUrl}/${buildS3VideoPath(assetId)}`;
|
|
73
|
+
}
|
|
50
74
|
function isObject(obj) {
|
|
51
75
|
return obj !== null && !Array.isArray(obj) && typeof obj == "object";
|
|
52
76
|
}
|
|
53
|
-
const idPattern = new RegExp(`^(?:${S3AssetType.IMAGE}-(?:[a-zA-Z0-9_]{24,40}|[a-f0-9]{40})+-\\d+x\\d+-[a-z0-9]+|${S3AssetType.FILE}-(?:[a-zA-Z0-9_]{24,40}|[a-f0-9]{40})+-[a-z0-9]+)$`), inProgressAssetId = "upload-in-progress-placeholder", inProgressAssetExtension = "tmp";
|
|
77
|
+
const idPattern = new RegExp(`^(?:${S3AssetType.IMAGE}-(?:[a-zA-Z0-9_]{24,40}|[a-f0-9]{40})+-\\d+x\\d+-[a-z0-9]+|${S3AssetType.VIDEO}-(?:[a-zA-Z0-9_]{24,40}|[a-f0-9]{40})+-\\d+x\\d+-[a-z0-9]+|${S3AssetType.FILE}-(?:[a-zA-Z0-9_]{24,40}|[a-f0-9]{40})+-[a-z0-9]+)$`), inProgressAssetId = "upload-in-progress-placeholder", inProgressAssetExtension = "tmp";
|
|
54
78
|
class UnresolvableError extends Error {
|
|
55
79
|
unresolvable = !0;
|
|
56
80
|
// The input may not be a valid source, so let's not type it as one
|
|
@@ -110,12 +134,31 @@ function getS3ImageDimensions(src) {
|
|
|
110
134
|
_type: "s3ImageDimensions"
|
|
111
135
|
};
|
|
112
136
|
}
|
|
113
|
-
|
|
137
|
+
function getS3VideoDimensions(src) {
|
|
138
|
+
if (isInProgressUpload(src))
|
|
139
|
+
return {
|
|
140
|
+
width: 0,
|
|
141
|
+
height: 0,
|
|
142
|
+
aspectRatio: 0,
|
|
143
|
+
_type: "s3VideoDimensions"
|
|
144
|
+
};
|
|
145
|
+
const videoId = getS3AssetDocumentId(src), {
|
|
146
|
+
width,
|
|
147
|
+
height
|
|
148
|
+
} = parseVideoAssetId(videoId), aspectRatio = width / height;
|
|
149
|
+
return {
|
|
150
|
+
width,
|
|
151
|
+
height,
|
|
152
|
+
aspectRatio,
|
|
153
|
+
_type: "s3VideoDimensions"
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
const tryGetS3ImageDimensions = getForgivingResolver(getS3ImageDimensions), tryGetS3VideoDimensions = getForgivingResolver(getS3VideoDimensions);
|
|
114
157
|
function getS3AssetExtension(src) {
|
|
115
158
|
if (isInProgressUpload(src))
|
|
116
159
|
return inProgressAssetExtension;
|
|
117
160
|
const assetId = getS3AssetDocumentId(src);
|
|
118
|
-
return isS3FileSource(src) ? parseFileAssetId(assetId).extension : parseImageAssetId(assetId).extension;
|
|
161
|
+
return isS3FileSource(src) ? parseFileAssetId(assetId).extension : isS3VideoSource(src) ? parseVideoAssetId(assetId).extension : parseImageAssetId(assetId).extension;
|
|
119
162
|
}
|
|
120
163
|
const tryGetS3AssetExtension = getForgivingResolver(getS3AssetExtension);
|
|
121
164
|
function isS3FileSource(src) {
|
|
@@ -126,20 +169,30 @@ function isS3ImageSource(src) {
|
|
|
126
169
|
const assetId = tryGetS3AssetDocumentId(src);
|
|
127
170
|
return assetId ? assetId.startsWith(`${S3AssetType.IMAGE}-`) : !1;
|
|
128
171
|
}
|
|
129
|
-
|
|
172
|
+
function isS3VideoSource(src) {
|
|
173
|
+
const assetId = tryGetS3AssetDocumentId(src);
|
|
174
|
+
return assetId ? assetId.startsWith(`${S3AssetType.VIDEO}-`) : !1;
|
|
175
|
+
}
|
|
176
|
+
const isS3FileAsset = (asset) => asset._type === "s3FileAsset", isS3ImageAsset = (asset) => asset._type === "s3ImageAsset", isS3VideoAsset = (asset) => asset._type === "s3VideoAsset";
|
|
130
177
|
exports.S3AssetType = S3AssetType;
|
|
131
178
|
exports.buildS3FilePath = buildS3FilePath;
|
|
132
179
|
exports.buildS3FileUrl = buildS3FileUrl;
|
|
133
180
|
exports.buildS3ImagePath = buildS3ImagePath;
|
|
134
181
|
exports.buildS3ImageUrl = buildS3ImageUrl;
|
|
182
|
+
exports.buildS3VideoPath = buildS3VideoPath;
|
|
183
|
+
exports.buildS3VideoUrl = buildS3VideoUrl;
|
|
135
184
|
exports.getS3AssetExtension = getS3AssetExtension;
|
|
136
185
|
exports.getS3ImageDimensions = getS3ImageDimensions;
|
|
186
|
+
exports.getS3VideoDimensions = getS3VideoDimensions;
|
|
137
187
|
exports.isInProgressUpload = isInProgressUpload;
|
|
138
188
|
exports.isObject = isObject;
|
|
139
189
|
exports.isS3FileAsset = isS3FileAsset;
|
|
140
190
|
exports.isS3FileSource = isS3FileSource;
|
|
141
191
|
exports.isS3ImageAsset = isS3ImageAsset;
|
|
142
192
|
exports.isS3ImageSource = isS3ImageSource;
|
|
193
|
+
exports.isS3VideoAsset = isS3VideoAsset;
|
|
194
|
+
exports.isS3VideoSource = isS3VideoSource;
|
|
143
195
|
exports.tryGetS3AssetExtension = tryGetS3AssetExtension;
|
|
144
196
|
exports.tryGetS3ImageDimensions = tryGetS3ImageDimensions;
|
|
197
|
+
exports.tryGetS3VideoDimensions = tryGetS3VideoDimensions;
|
|
145
198
|
//# sourceMappingURL=asset-utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asset-utils.js","sources":["../../src/types/asset.ts","../../src/utils/asset/parse.ts","../../src/utils/asset/paths.ts","../../src/utils/isObject.ts","../../src/utils/resolve.ts"],"sourcesContent":["import type {ComponentType, ReactNode} from 'react'\nimport type {\n AssetFromSource,\n AssetSourceComponentAction,\n AssetSourceUploaderClass,\n SanityDocument,\n} from 'sanity'\n\nimport type {S3FileSchemaType, S3ImageMetaData, S3ImageSchemaType} from './schema'\n\n/** @public */\nexport interface S3AssetDocument extends SanityDocument {\n _id: string\n _type: 's3FileAsset' | 's3ImageAsset'\n assetId: string\n extension: string\n mimeType: string\n sha1hash: string\n size: number\n originalFilename?: string\n}\n\n/** @public */\nexport type S3FileAsset = S3AssetDocument & {_type: 's3FileAsset'}\n\n/** @public */\nexport type S3ImageAsset = S3AssetDocument & {_type: 's3ImageAsset'; metadata: S3ImageMetaData}\n\n/** @public */\nexport type S3Asset = S3FileAsset | S3ImageAsset\n\n/** @public */\nexport enum S3AssetType {\n FILE = 's3File',\n IMAGE = 's3Image',\n}\n\nexport interface S3AssetSourceComponentProps {\n action?: AssetSourceComponentAction\n assetSource: S3AssetSource\n assetType?: S3AssetType\n accept: string\n selectionType: 'single'\n dialogHeaderTitle?: ReactNode\n selectedAssets: S3AssetDocument[]\n onClose: () => void\n onSelect: (assetFromSource: AssetFromSource[]) => void\n onChangeAction?: (action: AssetSourceComponentAction) => void\n schemaType?: S3ImageSchemaType | S3FileSchemaType\n assetToOpen?: S3AssetDocument\n}\n\nexport interface S3AssetSource {\n name: string\n title?: string\n component: ComponentType<S3AssetSourceComponentProps>\n icon?: ComponentType\n Uploader?: AssetSourceUploaderClass\n}\n\nexport interface S3FileAssetIdParts {\n type: 's3File'\n assetId: string\n extension: string\n}\n\nexport interface S3ImageAssetIdParts {\n type: 's3Image'\n assetId: string\n extension: string\n width: number\n height: number\n}\n","import type {S3FileAssetIdParts, S3ImageAssetIdParts} from '../../types'\n\n/**\n * Parses a S3 file asset document ID into individual parts (type, id, extension)\n *\n * @param documentId - File asset document ID to parse into named parts\n * @returns Object of named properties\n * @public\n * @throws If document ID invalid\n */\nexport function parseFileAssetId(documentId: string): S3FileAssetIdParts {\n const [, assetId, extension] = documentId.split('-')\n\n if (!assetId || !extension) {\n throw new Error(`Malformed file asset ID '${documentId}'.`)\n }\n\n return {type: 's3File', assetId, extension}\n}\n\n/**\n * Parses a S3 image asset document ID into individual parts (type, id, extension, width, height)\n *\n * @param documentId - Image asset document ID to parse into named parts\n * @returns Object of named properties\n * @public\n * @throws If document ID invalid\n */\nexport function parseImageAssetId(documentId: string): S3ImageAssetIdParts {\n const [, assetId, dimensionString, extension] = documentId.split('-')\n const [width, height] = (dimensionString || '').split('x').map(Number)\n\n if (!assetId || !dimensionString || !extension || !(width > 0) || !(height > 0)) {\n throw new Error(`Malformed asset ID '${documentId}'.`)\n }\n\n return {type: 's3Image', assetId, width, height, extension}\n}\n","import {parseFileAssetId, parseImageAssetId} from './parse'\n\ninterface UrlBuilderOptions {\n baseUrl: string\n}\n\n/**\n * Builds the base file path from the minimal set of parts required to assemble it\n *\n * @param asset - An asset-like shape defining ID, dimensions and extension\n * @param options - Project ID and dataset the file belongs to, along with other options\n * @returns The path to the file\n * @public\n */\nexport function buildS3FilePath(documentId: string): string {\n const {assetId, extension} = parseFileAssetId(documentId)\n\n return `${assetId}.${extension}`\n}\n\n/**\n * Builds the base file URL from the minimal set of parts required to assemble it\n *\n * @param asset - An asset-like shape defining ID and extension\n * @param options - Project ID and dataset the file belongs to, along with other options\n * @returns The URL to the file, as a string\n * @public\n */\nexport function buildS3FileUrl(assetId: string, options: UrlBuilderOptions): string {\n const baseUrl = options?.baseUrl\n\n return `${baseUrl}/${buildS3FilePath(assetId)}`\n}\n\n/**\n * Builds the base image path from the minimal set of parts required to assemble it\n *\n * @param asset - An asset-like shape defining ID, dimensions and extension\n * @param options - Project ID and dataset the image belongs to, along with other options\n * @returns The path to the image\n * @public\n */\nexport function buildS3ImagePath(documentId: string): string {\n const {assetId, width, height, extension} = parseImageAssetId(documentId)\n\n return `${assetId}-${width}x${height}.${extension}`\n}\n\n/**\n * Builds the base image URL from the minimal set of parts required to assemble it\n *\n * @param asset - An asset-like shape defining ID, dimensions and extension\n * @param options - Project ID and dataset the image belongs to\n * @returns The URL to the image, as a string\n * @public\n */\nexport function buildS3ImageUrl(assetId: string, options: UrlBuilderOptions): string {\n const baseUrl = options?.baseUrl\n return `${baseUrl}/${buildS3ImagePath(assetId)}`\n}\n","/**\n * Checks whether or not the passed object is an object (and not `null`)\n *\n * @param obj Item to check whether or not is an object\n * @returns Whether or not `obj` is an object\n * @internal\n */\nexport function isObject(obj: unknown): obj is object {\n return obj !== null && !Array.isArray(obj) && typeof obj === 'object'\n}\n","import {isReference} from 'sanity'\n\nimport {\n type S3Asset,\n type S3AssetObjectStub,\n S3AssetType,\n type S3FileAsset,\n type S3FileSource,\n type S3FileUploadStub,\n type S3ImageAsset,\n type S3ImageDimensions,\n type S3ImageSource,\n type S3ImageUploadStub,\n} from '../types'\nimport {parseFileAssetId, parseImageAssetId} from './asset/parse'\nimport {isObject} from './isObject'\n\n/**\n * A \"safe function\" is a wrapped function that would normally throw an UnresolvableError,\n * but will instead return `undefined`. Other errors are still thrown.\n *\n * @public\n */\ntype SafeFunction<Args extends unknown[], Return> = (...args: Args) => Return | undefined\n\nconst idPattern = new RegExp(\n `^(?:` +\n `${S3AssetType.IMAGE}-(?:[a-zA-Z0-9_]{24,40}|[a-f0-9]{40})+-\\\\d+x\\\\d+-[a-z0-9]+` +\n `|` +\n `${S3AssetType.FILE}-(?:[a-zA-Z0-9_]{24,40}|[a-f0-9]{40})+-[a-z0-9]+` +\n `)$`,\n)\n\n/**\n * Placeholder asset _ids for in-progress uploads\n * @internal\n */\nconst inProgressAssetId = 'upload-in-progress-placeholder'\n\n/**\n * Placeholder extension for in-progress uploads\n * @internal\n */\nconst inProgressAssetExtension = 'tmp'\n\n/**\n * Error type thrown when the library fails to resolve a value, such as an asset ID,\n * filename or project ID/dataset information.\n *\n * The `input` property holds the value passed as the input, which failed to be\n * resolved to something meaningful.\n *\n * @public\n */\nclass UnresolvableError extends Error {\n unresolvable = true\n\n // The input may not be a valid source, so let's not type it as one\n input?: unknown\n\n constructor(inputSource: unknown, message = 'Failed to resolve asset ID from source') {\n super(message)\n this.input = inputSource\n }\n}\n\n/**\n * Checks whether or not an error instance is of type UnresolvableError\n *\n * @param err - Error to check for unresolvable error type\n * @returns True if the passed error instance appears to be an unresolvable error\n * @public\n */\nfunction isUnresolvableError(err: unknown): err is UnresolvableError {\n const error = err as UnresolvableError\n return Boolean(error.unresolvable && 'input' in error)\n}\n\n/**\n * Returns a getter which returns `undefined` instead of throwing,\n * if encountering an `UnresolvableError`\n *\n * @param method - Function to use as resolver\n * @returns Function that returns `undefined` if passed resolver throws UnresolvableError\n * @internal\n */\nfunction getForgivingResolver<Args extends unknown[], Return>(\n method: (...args: Args) => Return,\n): SafeFunction<Args, Return> {\n return (...args: Args): Return | undefined => {\n try {\n return method(...args)\n } catch (err) {\n if (isUnresolvableError(err)) {\n return undefined\n }\n\n throw err\n }\n }\n}\n\n/**\n * Checks whether or not the given source is an in-progress upload\n * (has upload property but no asset property)\n *\n * @param stub - Possible in-progress upload\n * @returns Whether or not the passed object is an in-progress upload\n * @public\n */\nexport function isInProgressUpload(stub: unknown): stub is S3ImageUploadStub | S3FileUploadStub {\n const item = stub as S3ImageUploadStub | S3FileUploadStub\n return isObject(item) && Boolean(item._upload) && !('asset' in item)\n}\n\n/**\n * Checks whether or not the given source is an asset object stub\n *\n * @param stub - Possible asset object stub\n * @returns Whether or not the passed object is an object stub\n * @public\n */\nexport function isS3AssetObjectStub(stub: unknown): stub is S3AssetObjectStub {\n const item = stub as S3AssetObjectStub\n return isObject(item) && Boolean(item.asset) && typeof item.asset === 'object'\n}\n\n/**\n * Tries to resolve the asset document ID from any inferrable structure\n *\n * @param src - Input source (image/file object, asset, reference, id, url, path)\n * @returns The asset document ID\n *\n * @throws {@link UnresolvableError}\n * Throws if passed asset source could not be resolved to an asset document ID\n * @public\n */\nexport function getS3AssetDocumentId(src: S3FileSource | S3ImageSource): string {\n // Check if this is an in-progress upload (has upload but no asset)\n if (isInProgressUpload(src)) {\n // Return a placeholder ID that indicates in-progress state\n // This allows the render cycle to continue until asset is available\n return inProgressAssetId\n }\n\n const source = isS3AssetObjectStub(src) ? src.asset : src\n\n let id = ''\n\n if (isReference(source)) {\n id = source._ref\n } else {\n id = source._id\n }\n\n const hasId = id && idPattern.test(id)\n\n if (!hasId) {\n throw new UnresolvableError(src)\n }\n\n return id\n}\n\n/**\n * {@inheritDoc getS3AssetDocumentId}\n * @returns Returns `undefined` instead of throwing if a value cannot be resolved\n * @public\n */\nconst tryGetS3AssetDocumentId = getForgivingResolver(getS3AssetDocumentId)\n\n/**\n * Returns the width, height and aspect ratio of a passed image asset, from any\n * inferrable structure (id, url, path, asset document, image object etc)\n *\n * @param src - Input source (image object, asset, reference, id, url, path)\n * @returns Object with width, height and aspect ratio properties\n *\n * @throws {@link UnresolvableError}\n * Throws if passed image source could not be resolved to an asset ID\n * @public\n */\nexport function getS3ImageDimensions(src: S3ImageSource): S3ImageDimensions {\n // Check if this is an in-progress upload\n if (isInProgressUpload(src)) {\n // Return placeholder dimensions for in-progress uploads\n return {width: 0, height: 0, aspectRatio: 0, _type: 's3ImageDimensions'}\n }\n\n const imageId = getS3AssetDocumentId(src)\n const {width, height} = parseImageAssetId(imageId)\n const aspectRatio = width / height\n\n return {width, height, aspectRatio, _type: 's3ImageDimensions'}\n}\n\n/**\n * {@inheritDoc getS3ImageDimensions}\n * @returns Returns `undefined` instead of throwing if a value cannot be resolved\n * @public\n */\nexport const tryGetS3ImageDimensions = getForgivingResolver(getS3ImageDimensions)\n\n/**\n * Returns the file extension for a given asset\n *\n * @param src - Input source (file/image object, asset, reference, id, url, path)\n * @returns The file extension, if resolvable (no `.` included)\n *\n * @throws {@link UnresolvableError}\n * Throws if passed asset source could not be resolved to an asset ID\n * @public\n */\nexport function getS3AssetExtension(src: S3FileSource | S3ImageSource): string {\n // Check if this is an in-progress upload\n if (isInProgressUpload(src)) {\n // Return placeholder extension for in-progress uploads\n return inProgressAssetExtension\n }\n\n const assetId = getS3AssetDocumentId(src)\n\n return isS3FileSource(src)\n ? parseFileAssetId(assetId).extension\n : parseImageAssetId(assetId).extension\n}\n\n/**\n * {@inheritDoc getS3AssetExtension}\n * @returns Returns `undefined` instead of throwing if a value cannot be resolved\n * @public\n */\nexport const tryGetS3AssetExtension = getForgivingResolver(getS3AssetExtension)\n\n/**\n * Return whether or not the passed source is an s3 file source\n *\n * @param src - Source to check\n * @returns Whether or not the given source is an s3 file source\n * @public\n */\nexport function isS3FileSource(src: unknown): src is S3FileSource {\n const assetId = tryGetS3AssetDocumentId(src as S3FileSource)\n return assetId ? assetId.startsWith(`${S3AssetType.FILE}-`) : false\n}\n\n/**\n * Return whether or not the passed source is an s3 image source\n *\n * @param src - Source to check\n * @returns Whether or not the given source is an s3 image source\n * @public\n */\nexport function isS3ImageSource(src: unknown): src is S3ImageSource {\n const assetId = tryGetS3AssetDocumentId(src as S3ImageSource)\n\n return assetId ? assetId.startsWith(`${S3AssetType.IMAGE}-`) : false\n}\n\nexport const isS3FileAsset = (asset: S3Asset): asset is S3FileAsset => {\n return (asset as S3FileAsset)._type === 's3FileAsset'\n}\n\nexport const isS3ImageAsset = (asset: S3Asset): asset is S3ImageAsset => {\n return (asset as S3ImageAsset)._type === 's3ImageAsset'\n}\n"],"names":["S3AssetType","parseFileAssetId","documentId","assetId","extension","split","Error","type","parseImageAssetId","dimensionString","width","height","map","Number","buildS3FilePath","buildS3FileUrl","options","baseUrl","buildS3ImagePath","buildS3ImageUrl","isObject","obj","Array","isArray","idPattern","RegExp","IMAGE","FILE","inProgressAssetId","inProgressAssetExtension","UnresolvableError","unresolvable","constructor","inputSource","message","input","isUnresolvableError","err","error","Boolean","getForgivingResolver","method","args","isInProgressUpload","stub","item","_upload","isS3AssetObjectStub","asset","getS3AssetDocumentId","src","source","id","isReference","_ref","_id","test","tryGetS3AssetDocumentId","getS3ImageDimensions","aspectRatio","_type","imageId","tryGetS3ImageDimensions","getS3AssetExtension","isS3FileSource","tryGetS3AssetExtension","startsWith","isS3ImageSource","isS3FileAsset","isS3ImageAsset"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"asset-utils.js","sources":["../../src/types/asset.ts","../../src/utils/asset/parse.ts","../../src/utils/asset/paths.ts","../../src/utils/isObject.ts","../../src/utils/resolve.ts"],"sourcesContent":["import type {ComponentType, ReactNode} from 'react'\nimport type {\n AssetFromSource,\n AssetSourceComponentAction,\n AssetSourceUploaderClass,\n SanityDocument,\n} from 'sanity'\n\nimport type {\n S3FileSchemaType,\n S3ImageMetaData,\n S3ImageSchemaType,\n S3VideoMetaData,\n S3VideoSchemaType,\n} from './schema'\n\n/** @public */\nexport interface S3AssetDocument extends SanityDocument {\n _id: string\n _type: 's3FileAsset' | 's3ImageAsset' | 's3VideoAsset'\n assetId: string\n extension: string\n mimeType: string\n sha1hash: string\n size: number\n originalFilename?: string\n}\n\n/** @public */\nexport type S3FileAsset = S3AssetDocument & {_type: 's3FileAsset'}\n\n/** @public */\nexport type S3ImageAsset = S3AssetDocument & {_type: 's3ImageAsset'; metadata: S3ImageMetaData}\n\n/** @public */\nexport type S3VideoAsset = S3AssetDocument & {_type: 's3VideoAsset'; metadata: S3VideoMetaData}\n\n/** @public */\nexport type S3Asset = S3FileAsset | S3ImageAsset | S3VideoAsset\n\n/** @public */\nexport enum S3AssetType {\n FILE = 's3File',\n IMAGE = 's3Image',\n VIDEO = 's3Video',\n}\n\nexport interface S3AssetSourceComponentProps {\n action?: AssetSourceComponentAction\n assetSource: S3AssetSource\n assetType?: S3AssetType\n accept: string\n selectionType: 'single'\n dialogHeaderTitle?: ReactNode\n selectedAssets: S3AssetDocument[]\n onClose: () => void\n onSelect: (assetFromSource: AssetFromSource[]) => void\n onChangeAction?: (action: AssetSourceComponentAction) => void\n schemaType?: S3ImageSchemaType | S3FileSchemaType | S3VideoSchemaType\n assetToOpen?: S3AssetDocument\n}\n\nexport interface S3AssetSource {\n name: string\n title?: string\n component: ComponentType<S3AssetSourceComponentProps>\n icon?: ComponentType\n Uploader?: AssetSourceUploaderClass\n}\n\nexport interface S3FileAssetIdParts {\n type: 's3File'\n assetId: string\n extension: string\n}\n\nexport interface S3ImageAssetIdParts {\n type: 's3Image'\n assetId: string\n extension: string\n width: number\n height: number\n}\n\nexport interface S3VideoAssetIdParts {\n type: 's3Video'\n assetId: string\n extension: string\n width: number\n height: number\n}\n","import {\n S3AssetType,\n type S3FileAssetIdParts,\n type S3ImageAssetIdParts,\n type S3VideoAssetIdParts,\n} from '../../types'\n\n/**\n * Parses a S3 file asset document ID into individual parts (type, id, extension)\n *\n * @param documentId - File asset document ID to parse into named parts\n * @returns Object of named properties\n * @public\n * @throws If document ID invalid\n */\nexport function parseFileAssetId(documentId: string): S3FileAssetIdParts {\n const [, assetId, extension] = documentId.split('-')\n\n if (!assetId || !extension) {\n throw new Error(`Malformed file asset ID '${documentId}'.`)\n }\n\n return {type: S3AssetType.FILE, assetId, extension}\n}\n\n/**\n * Parses a S3 image asset document ID into individual parts (type, id, extension, width, height)\n *\n * @param documentId - Image asset document ID to parse into named parts\n * @returns Object of named properties\n * @public\n * @throws If document ID invalid\n */\nexport function parseImageAssetId(documentId: string): S3ImageAssetIdParts {\n const [, assetId, dimensionString, extension] = documentId.split('-')\n const [width, height] = (dimensionString || '').split('x').map(Number)\n\n if (!assetId || !dimensionString || !extension || !(width > 0) || !(height > 0)) {\n throw new Error(`Malformed asset ID '${documentId}'.`)\n }\n\n return {type: S3AssetType.IMAGE, assetId, width, height, extension}\n}\n\n/**\n * Parses a S3 video asset document ID into individual parts (type, id, extension, width, height)\n *\n * @param documentId - Video asset document ID to parse into named parts\n * @returns Object of named properties\n * @public\n * @throws If document ID invalid\n */\nexport function parseVideoAssetId(documentId: string): S3VideoAssetIdParts {\n const [, assetId, dimensionString, extension] = documentId.split('-')\n const [width, height] = (dimensionString || '').split('x').map(Number)\n\n if (!assetId || !dimensionString || !extension || !(width > 0) || !(height > 0)) {\n throw new Error(`Malformed asset ID '${documentId}'.`)\n }\n\n return {type: S3AssetType.VIDEO, assetId, width, height, extension}\n}\n","import {parseFileAssetId, parseImageAssetId, parseVideoAssetId} from './parse'\n\ninterface UrlBuilderOptions {\n baseUrl: string\n}\n\n/**\n * Builds the base file path from the minimal set of parts required to assemble it\n *\n * @param asset - An asset-like shape defining ID, dimensions and extension\n * @param options - Project ID and dataset the file belongs to, along with other options\n * @returns The path to the file\n * @public\n */\nexport function buildS3FilePath(documentId: string): string {\n const {assetId, extension} = parseFileAssetId(documentId)\n\n return `${assetId}.${extension}`\n}\n\n/**\n * Builds the base file URL from the minimal set of parts required to assemble it\n *\n * @param asset - An asset-like shape defining ID and extension\n * @param options - Project ID and dataset the file belongs to, along with other options\n * @returns The URL to the file, as a string\n * @public\n */\nexport function buildS3FileUrl(assetId: string, options: UrlBuilderOptions): string {\n const baseUrl = options?.baseUrl\n\n return `${baseUrl}/${buildS3FilePath(assetId)}`\n}\n\n/**\n * Builds the base image path from the minimal set of parts required to assemble it\n *\n * @param asset - An asset-like shape defining ID, dimensions and extension\n * @param options - Project ID and dataset the image belongs to, along with other options\n * @returns The path to the image\n * @public\n */\nexport function buildS3ImagePath(documentId: string): string {\n const {assetId, width, height, extension} = parseImageAssetId(documentId)\n\n return `${assetId}-${width}x${height}.${extension}`\n}\n\n/**\n * Builds the base image URL from the minimal set of parts required to assemble it\n *\n * @param asset - An asset-like shape defining ID, dimensions and extension\n * @param options - Project ID and dataset the image belongs to\n * @returns The URL to the image, as a string\n * @public\n */\nexport function buildS3ImageUrl(assetId: string, options: UrlBuilderOptions): string {\n const baseUrl = options?.baseUrl\n return `${baseUrl}/${buildS3ImagePath(assetId)}`\n}\n\n/**\n * Builds the base video path from the minimal set of parts required to assemble it\n *\n * @param asset - An asset-like shape defining ID, dimensions and extension\n * @returns The path to the video\n * @public\n */\nexport function buildS3VideoPath(documentId: string): string {\n const {assetId, width, height, extension} = parseVideoAssetId(documentId)\n\n return `${assetId}-${width}x${height}.${extension}`\n}\n\n/**\n * Builds the base video URL from the minimal set of parts required to assemble it\n *\n * @param asset - An asset-like shape defining ID, dimensions and extension\n * @param options - Base URL configuration\n * @returns The URL to the video, as a string\n * @public\n */\nexport function buildS3VideoUrl(assetId: string, options: UrlBuilderOptions): string {\n const baseUrl = options?.baseUrl\n return `${baseUrl}/${buildS3VideoPath(assetId)}`\n}\n","/**\n * Checks whether or not the passed object is an object (and not `null`)\n *\n * @param obj Item to check whether or not is an object\n * @returns Whether or not `obj` is an object\n * @internal\n */\nexport function isObject(obj: unknown): obj is object {\n return obj !== null && !Array.isArray(obj) && typeof obj === 'object'\n}\n","import {isReference} from 'sanity'\n\nimport {\n type S3Asset,\n type S3AssetObjectStub,\n S3AssetType,\n type S3FileAsset,\n type S3FileSource,\n type S3FileUploadStub,\n type S3ImageAsset,\n type S3ImageDimensions,\n type S3ImageSource,\n type S3ImageUploadStub,\n type S3VideoAsset,\n type S3VideoDimensions,\n type S3VideoSource,\n type S3VideoUploadStub,\n} from '../types'\nimport {parseFileAssetId, parseImageAssetId, parseVideoAssetId} from './asset/parse'\nimport {isObject} from './isObject'\n\n/**\n * A \"safe function\" is a wrapped function that would normally throw an UnresolvableError,\n * but will instead return `undefined`. Other errors are still thrown.\n *\n * @public\n */\ntype SafeFunction<Args extends unknown[], Return> = (...args: Args) => Return | undefined\n\nconst idPattern = new RegExp(\n `^(?:` +\n `${S3AssetType.IMAGE}-(?:[a-zA-Z0-9_]{24,40}|[a-f0-9]{40})+-\\\\d+x\\\\d+-[a-z0-9]+` +\n `|` +\n `${S3AssetType.VIDEO}-(?:[a-zA-Z0-9_]{24,40}|[a-f0-9]{40})+-\\\\d+x\\\\d+-[a-z0-9]+` +\n `|` +\n `${S3AssetType.FILE}-(?:[a-zA-Z0-9_]{24,40}|[a-f0-9]{40})+-[a-z0-9]+` +\n `)$`,\n)\n\n/**\n * Placeholder asset _ids for in-progress uploads\n * @internal\n */\nconst inProgressAssetId = 'upload-in-progress-placeholder'\n\n/**\n * Placeholder extension for in-progress uploads\n * @internal\n */\nconst inProgressAssetExtension = 'tmp'\n\n/**\n * Error type thrown when the library fails to resolve a value, such as an asset ID,\n * filename or project ID/dataset information.\n *\n * The `input` property holds the value passed as the input, which failed to be\n * resolved to something meaningful.\n *\n * @public\n */\nclass UnresolvableError extends Error {\n unresolvable = true\n\n // The input may not be a valid source, so let's not type it as one\n input?: unknown\n\n constructor(inputSource: unknown, message = 'Failed to resolve asset ID from source') {\n super(message)\n this.input = inputSource\n }\n}\n\n/**\n * Checks whether or not an error instance is of type UnresolvableError\n *\n * @param err - Error to check for unresolvable error type\n * @returns True if the passed error instance appears to be an unresolvable error\n * @public\n */\nfunction isUnresolvableError(err: unknown): err is UnresolvableError {\n const error = err as UnresolvableError\n return Boolean(error.unresolvable && 'input' in error)\n}\n\n/**\n * Returns a getter which returns `undefined` instead of throwing,\n * if encountering an `UnresolvableError`\n *\n * @param method - Function to use as resolver\n * @returns Function that returns `undefined` if passed resolver throws UnresolvableError\n * @internal\n */\nfunction getForgivingResolver<Args extends unknown[], Return>(\n method: (...args: Args) => Return,\n): SafeFunction<Args, Return> {\n return (...args: Args): Return | undefined => {\n try {\n return method(...args)\n } catch (err) {\n if (isUnresolvableError(err)) {\n return undefined\n }\n\n throw err\n }\n }\n}\n\n/**\n * Checks whether or not the given source is an in-progress upload\n * (has upload property but no asset property)\n *\n * @param stub - Possible in-progress upload\n * @returns Whether or not the passed object is an in-progress upload\n * @public\n */\nexport function isInProgressUpload(\n stub: unknown,\n): stub is S3ImageUploadStub | S3FileUploadStub | S3VideoUploadStub {\n const item = stub as S3ImageUploadStub | S3FileUploadStub | S3VideoUploadStub\n return isObject(item) && Boolean(item._upload) && !('asset' in item)\n}\n\n/**\n * Checks whether or not the given source is an asset object stub\n *\n * @param stub - Possible asset object stub\n * @returns Whether or not the passed object is an object stub\n * @public\n */\nexport function isS3AssetObjectStub(stub: unknown): stub is S3AssetObjectStub {\n const item = stub as S3AssetObjectStub\n return isObject(item) && Boolean(item.asset) && typeof item.asset === 'object'\n}\n\n/**\n * Tries to resolve the asset document ID from any inferrable structure\n *\n * @param src - Input source (image/file object, asset, reference, id, url, path)\n * @returns The asset document ID\n *\n * @throws {@link UnresolvableError}\n * Throws if passed asset source could not be resolved to an asset document ID\n * @public\n */\nexport function getS3AssetDocumentId(src: S3FileSource | S3ImageSource | S3VideoSource): string {\n // Check if this is an in-progress upload (has upload but no asset)\n if (isInProgressUpload(src)) {\n // Return a placeholder ID that indicates in-progress state\n // This allows the render cycle to continue until asset is available\n return inProgressAssetId\n }\n\n const source = isS3AssetObjectStub(src) ? src.asset : src\n\n let id = ''\n\n if (isReference(source)) {\n id = source._ref\n } else {\n id = source._id\n }\n\n const hasId = id && idPattern.test(id)\n\n if (!hasId) {\n throw new UnresolvableError(src)\n }\n\n return id\n}\n\n/**\n * {@inheritDoc getS3AssetDocumentId}\n * @returns Returns `undefined` instead of throwing if a value cannot be resolved\n * @public\n */\nconst tryGetS3AssetDocumentId = getForgivingResolver(getS3AssetDocumentId)\n\n/**\n * Returns the width, height and aspect ratio of a passed image asset, from any\n * inferrable structure (id, url, path, asset document, image object etc)\n *\n * @param src - Input source (image object, asset, reference, id, url, path)\n * @returns Object with width, height and aspect ratio properties\n *\n * @throws {@link UnresolvableError}\n * Throws if passed image source could not be resolved to an asset ID\n * @public\n */\nexport function getS3ImageDimensions(src: S3ImageSource): S3ImageDimensions {\n // Check if this is an in-progress upload\n if (isInProgressUpload(src)) {\n // Return placeholder dimensions for in-progress uploads\n return {width: 0, height: 0, aspectRatio: 0, _type: 's3ImageDimensions'}\n }\n\n const imageId = getS3AssetDocumentId(src)\n const {width, height} = parseImageAssetId(imageId)\n const aspectRatio = width / height\n\n return {width, height, aspectRatio, _type: 's3ImageDimensions'}\n}\n\n/**\n * Returns the width, height and aspect ratio of a passed video asset, from any\n * inferrable structure (id, url, path, asset document, video object etc)\n *\n * @param src - Input source (video object, asset, reference, id, url, path)\n * @returns Object with width, height and aspect ratio properties\n *\n * @throws {@link UnresolvableError}\n * Throws if passed video source could not be resolved to an asset ID\n * @public\n */\nexport function getS3VideoDimensions(src: S3VideoSource): S3VideoDimensions {\n // Check if this is an in-progress upload\n if (isInProgressUpload(src)) {\n // Return placeholder dimensions for in-progress uploads\n return {width: 0, height: 0, aspectRatio: 0, _type: 's3VideoDimensions'}\n }\n\n const videoId = getS3AssetDocumentId(src)\n const {width, height} = parseVideoAssetId(videoId)\n const aspectRatio = width / height\n\n return {width, height, aspectRatio, _type: 's3VideoDimensions'}\n}\n\n/**\n * {@inheritDoc getS3ImageDimensions}\n * @returns Returns `undefined` instead of throwing if a value cannot be resolved\n * @public\n */\nexport const tryGetS3ImageDimensions = getForgivingResolver(getS3ImageDimensions)\n\n/**\n * {@inheritDoc getS3VideoDimensions}\n * @returns Returns `undefined` instead of throwing if a value cannot be resolved\n * @public\n */\nexport const tryGetS3VideoDimensions = getForgivingResolver(getS3VideoDimensions)\n\n/**\n * Returns the file extension for a given asset\n *\n * @param src - Input source (file/image object, asset, reference, id, url, path)\n * @returns The file extension, if resolvable (no `.` included)\n *\n * @throws {@link UnresolvableError}\n * Throws if passed asset source could not be resolved to an asset ID\n * @public\n */\nexport function getS3AssetExtension(src: S3FileSource | S3ImageSource | S3VideoSource): string {\n // Check if this is an in-progress upload\n if (isInProgressUpload(src)) {\n // Return placeholder extension for in-progress uploads\n return inProgressAssetExtension\n }\n\n const assetId = getS3AssetDocumentId(src)\n\n if (isS3FileSource(src)) {\n return parseFileAssetId(assetId).extension\n }\n\n if (isS3VideoSource(src)) {\n return parseVideoAssetId(assetId).extension\n }\n\n return parseImageAssetId(assetId).extension\n}\n\n/**\n * {@inheritDoc getS3AssetExtension}\n * @returns Returns `undefined` instead of throwing if a value cannot be resolved\n * @public\n */\nexport const tryGetS3AssetExtension = getForgivingResolver(getS3AssetExtension)\n\n/**\n * Return whether or not the passed source is an s3 file source\n *\n * @param src - Source to check\n * @returns Whether or not the given source is an s3 file source\n * @public\n */\nexport function isS3FileSource(src: unknown): src is S3FileSource {\n const assetId = tryGetS3AssetDocumentId(src as S3FileSource)\n return assetId ? assetId.startsWith(`${S3AssetType.FILE}-`) : false\n}\n\n/**\n * Return whether or not the passed source is an s3 image source\n *\n * @param src - Source to check\n * @returns Whether or not the given source is an s3 image source\n * @public\n */\nexport function isS3ImageSource(src: unknown): src is S3ImageSource {\n const assetId = tryGetS3AssetDocumentId(src as S3ImageSource)\n\n return assetId ? assetId.startsWith(`${S3AssetType.IMAGE}-`) : false\n}\n\n/**\n * Return whether or not the passed source is an s3 video source\n *\n * @param src - Source to check\n * @returns Whether or not the given source is an s3 video source\n * @public\n */\nexport function isS3VideoSource(src: unknown): src is S3VideoSource {\n const assetId = tryGetS3AssetDocumentId(src as S3VideoSource)\n\n return assetId ? assetId.startsWith(`${S3AssetType.VIDEO}-`) : false\n}\n\nexport const isS3FileAsset = (asset: S3Asset): asset is S3FileAsset => {\n return (asset as S3FileAsset)._type === 's3FileAsset'\n}\n\nexport const isS3ImageAsset = (asset: S3Asset): asset is S3ImageAsset => {\n return (asset as S3ImageAsset)._type === 's3ImageAsset'\n}\n\nexport const isS3VideoAsset = (asset: S3Asset): asset is S3VideoAsset => {\n return (asset as S3VideoAsset)._type === 's3VideoAsset'\n}\n"],"names":["S3AssetType","parseFileAssetId","documentId","assetId","extension","split","Error","type","FILE","parseImageAssetId","dimensionString","width","height","map","Number","IMAGE","parseVideoAssetId","VIDEO","buildS3FilePath","buildS3FileUrl","options","baseUrl","buildS3ImagePath","buildS3ImageUrl","buildS3VideoPath","buildS3VideoUrl","isObject","obj","Array","isArray","idPattern","RegExp","inProgressAssetId","inProgressAssetExtension","UnresolvableError","unresolvable","constructor","inputSource","message","input","isUnresolvableError","err","error","Boolean","getForgivingResolver","method","args","isInProgressUpload","stub","item","_upload","isS3AssetObjectStub","asset","getS3AssetDocumentId","src","source","id","isReference","_ref","_id","test","tryGetS3AssetDocumentId","getS3ImageDimensions","aspectRatio","_type","imageId","getS3VideoDimensions","videoId","tryGetS3ImageDimensions","tryGetS3VideoDimensions","getS3AssetExtension","isS3FileSource","isS3VideoSource","tryGetS3AssetExtension","startsWith","isS3ImageSource","isS3FileAsset","isS3ImageAsset","isS3VideoAsset"],"mappings":"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"}
|
|
@@ -327,7 +327,7 @@ const constructFilter = ({
|
|
|
327
327
|
try {
|
|
328
328
|
canvas.getContext("2d")?.drawImage(img, 0, 0, PREVIEW_WIDTH, PREVIEW_WIDTH / imageAspect), canvas.toBlob(resolve, "image/jpeg");
|
|
329
329
|
} catch (err) {
|
|
330
|
-
console.warn("Unable to generate preview image:", err);
|
|
330
|
+
console.warn("Unable to generate preview image:", err), resolve(null);
|
|
331
331
|
}
|
|
332
332
|
}), createImageEl = (file) => new Promise((resolve) => {
|
|
333
333
|
const blobUrlLarge = window.URL.createObjectURL(file), img = new Image();
|
|
@@ -380,7 +380,7 @@ function getUniqueDocuments(documents) {
|
|
|
380
380
|
const draftIds = documents.reduce((acc, doc) => doc._id.startsWith("drafts.") ? acc.concat(doc._id.slice(7)) : acc, []);
|
|
381
381
|
return documents.filter((doc) => !draftIds.includes(doc._id));
|
|
382
382
|
}
|
|
383
|
-
const UPLOAD_STATUS_KEY = "_upload", STALE_UPLOAD_MS = 1e3 * 60 * 2, SUPPORTED_ASSET_TYPES = [assetUtils.S3AssetType.FILE, assetUtils.S3AssetType.IMAGE], ORDER_OPTIONS = [{
|
|
383
|
+
const UPLOAD_STATUS_KEY = "_upload", STALE_UPLOAD_MS = 1e3 * 60 * 2, SUPPORTED_ASSET_TYPES = [assetUtils.S3AssetType.FILE, assetUtils.S3AssetType.IMAGE, assetUtils.S3AssetType.VIDEO], ORDER_OPTIONS = [{
|
|
384
384
|
direction: "desc",
|
|
385
385
|
field: "_createdAt"
|
|
386
386
|
}, {
|
|
@@ -466,10 +466,25 @@ const createThrottler = (concurrency = DEFAULT_CONCURRENCY) => {
|
|
|
466
466
|
}, img.onerror = () => {
|
|
467
467
|
subscriber.error(new Error("Failed to load image")), cleanup();
|
|
468
468
|
}, img.src = url;
|
|
469
|
-
}).pipe(operators.catchError(() => rxjs.of(null))) : rxjs.of(null),
|
|
469
|
+
}).pipe(operators.catchError(() => rxjs.of(null))) : rxjs.of(null), getVideoDimensions = (file) => file.type.startsWith("video/") ? new rxjs.Observable((subscriber) => {
|
|
470
|
+
const video = document.createElement("video"), url = URL.createObjectURL(file), cleanup = () => {
|
|
471
|
+
URL.revokeObjectURL(url), video.removeAttribute("src"), video.load();
|
|
472
|
+
};
|
|
473
|
+
video.onloadedmetadata = () => {
|
|
474
|
+
subscriber.next({
|
|
475
|
+
width: video.videoWidth,
|
|
476
|
+
height: video.videoHeight
|
|
477
|
+
}), subscriber.complete(), cleanup();
|
|
478
|
+
}, video.onerror = () => {
|
|
479
|
+
subscriber.error(new Error("Failed to load video metadata")), cleanup();
|
|
480
|
+
}, video.preload = "metadata", video.src = url;
|
|
481
|
+
}).pipe(operators.catchError(() => rxjs.of(null))) : rxjs.of(null), getFileExtension = (filename) => {
|
|
482
|
+
const segments = filename.split(".");
|
|
483
|
+
return segments[segments.length - 1];
|
|
484
|
+
}, buildFileName$1 = (fileId, extension, dimensions) => dimensions ? `${fileId}-${dimensions.width}x${dimensions.height}.${extension}` : `${fileId}.${extension}`, buildDocumentId = (assetType, fileId, extension, dimensions) => assetType === assetUtils.S3AssetType.IMAGE && dimensions ? `${assetUtils.S3AssetType.IMAGE}-${fileId}-${dimensions.width}x${dimensions.height}-${extension}` : assetType === assetUtils.S3AssetType.VIDEO && dimensions ? `${assetUtils.S3AssetType.VIDEO}-${fileId}-${dimensions.width}x${dimensions.height}-${extension}` : `${assetUtils.S3AssetType.FILE}-${fileId}-${extension}`, buildAssetDocument = (assetType, fileId, file, documentId, hash, dimensions, storeOriginalFilename) => {
|
|
470
485
|
const baseDocument = {
|
|
471
486
|
_id: documentId,
|
|
472
|
-
_type: assetType === assetUtils.S3AssetType.IMAGE ? "s3ImageAsset" : "s3FileAsset",
|
|
487
|
+
_type: assetType === assetUtils.S3AssetType.IMAGE ? "s3ImageAsset" : assetType === assetUtils.S3AssetType.VIDEO ? "s3VideoAsset" : "s3FileAsset",
|
|
473
488
|
assetId: fileId,
|
|
474
489
|
originalFilename: storeOriginalFilename ? file.name : void 0,
|
|
475
490
|
sha1hash: hash,
|
|
@@ -489,6 +504,18 @@ const createThrottler = (concurrency = DEFAULT_CONCURRENCY) => {
|
|
|
489
504
|
aspectRatio: dimensions.width / dimensions.height
|
|
490
505
|
}
|
|
491
506
|
}
|
|
507
|
+
} : assetType === assetUtils.S3AssetType.VIDEO && dimensions ? {
|
|
508
|
+
...baseDocument,
|
|
509
|
+
_type: "s3VideoAsset",
|
|
510
|
+
metadata: {
|
|
511
|
+
_type: "s3VideoMetadata",
|
|
512
|
+
dimensions: {
|
|
513
|
+
_type: "s3VideoDimensions",
|
|
514
|
+
height: dimensions.height,
|
|
515
|
+
width: dimensions.width,
|
|
516
|
+
aspectRatio: dimensions.width / dimensions.height
|
|
517
|
+
}
|
|
518
|
+
}
|
|
492
519
|
} : baseDocument;
|
|
493
520
|
}, createCompleteEvent = ({
|
|
494
521
|
asset,
|
|
@@ -508,13 +535,15 @@ const createThrottler = (concurrency = DEFAULT_CONCURRENCY) => {
|
|
|
508
535
|
const {
|
|
509
536
|
storeOriginalFilename = !0
|
|
510
537
|
} = options, extension = getFileExtension(file.name);
|
|
511
|
-
return hashFile(file).pipe(operators.mergeMap((hash) => (assetType === assetUtils.S3AssetType.IMAGE ? getImageDimensions(file) : rxjs.of(null)).pipe(operators.map((dimensions) => ({
|
|
538
|
+
return hashFile(file).pipe(operators.mergeMap((hash) => (assetType === assetUtils.S3AssetType.IMAGE ? getImageDimensions(file) : assetType === assetUtils.S3AssetType.VIDEO ? getVideoDimensions(file) : rxjs.of(null)).pipe(operators.map((dimensions) => ({
|
|
512
539
|
hash,
|
|
513
540
|
dimensions
|
|
514
541
|
})))), operators.mergeMap(({
|
|
515
542
|
hash,
|
|
516
543
|
dimensions
|
|
517
544
|
}) => {
|
|
545
|
+
if (assetType === assetUtils.S3AssetType.VIDEO && !dimensions)
|
|
546
|
+
throw new Error("Unable to determine video dimensions");
|
|
518
547
|
if (hash) {
|
|
519
548
|
const documentId = buildDocumentId(assetType, hash, extension, dimensions);
|
|
520
549
|
return fetchExistingAsset(sanityClient, assetType, documentId).pipe(operators.map((existing) => ({
|
|
@@ -697,15 +726,14 @@ const validateAssetType = (type) => {
|
|
|
697
726
|
return new rxjs.Observable((subscriber) => {
|
|
698
727
|
(async () => {
|
|
699
728
|
try {
|
|
700
|
-
|
|
729
|
+
subscriber.next({
|
|
701
730
|
type: "progress",
|
|
702
731
|
stage: "upload",
|
|
703
732
|
percent: 5,
|
|
704
733
|
loaded: 0,
|
|
705
734
|
total: fileSize,
|
|
706
735
|
lengthComputable: !0
|
|
707
|
-
})
|
|
708
|
-
throw new Error("getSignedUrlEndpoint is not defined");
|
|
736
|
+
});
|
|
709
737
|
const signedUrlResponse = await fetch(getSignedUrlEndpoint, {
|
|
710
738
|
method: "POST",
|
|
711
739
|
body: JSON.stringify({
|
|
@@ -1002,7 +1030,7 @@ const exp = defineCreateClientExports(S3Client), createS3Client = exp.createClie
|
|
|
1002
1030
|
if (!assetId || !assetType)
|
|
1003
1031
|
throw new Error("");
|
|
1004
1032
|
if (!s3AssetBaseUrl)
|
|
1005
|
-
|
|
1033
|
+
throw new Error("S3 Base URL is not defined");
|
|
1006
1034
|
if (assetType === assetUtils.S3AssetType.IMAGE)
|
|
1007
1035
|
return assetUtils.buildS3ImageUrl(assetId, {
|
|
1008
1036
|
baseUrl: s3AssetBaseUrl
|
|
@@ -1011,7 +1039,11 @@ const exp = defineCreateClientExports(S3Client), createS3Client = exp.createClie
|
|
|
1011
1039
|
return assetUtils.buildS3FileUrl(assetId, {
|
|
1012
1040
|
baseUrl: s3AssetBaseUrl
|
|
1013
1041
|
});
|
|
1014
|
-
|
|
1042
|
+
if (assetType === assetUtils.S3AssetType.VIDEO)
|
|
1043
|
+
return assetUtils.buildS3VideoUrl(assetId, {
|
|
1044
|
+
baseUrl: s3AssetBaseUrl
|
|
1045
|
+
});
|
|
1046
|
+
throw new Error("Can't build asset id");
|
|
1015
1047
|
}, $[6] = s3AssetBaseUrl, $[7] = t1) : t1 = $[7];
|
|
1016
1048
|
const buildAssetUrl = t1;
|
|
1017
1049
|
let t2;
|
|
@@ -1106,6 +1138,8 @@ const exp = defineCreateClientExports(S3Client), createS3Client = exp.createClie
|
|
|
1106
1138
|
}, buildFileName = (asset) => {
|
|
1107
1139
|
if (assetUtils.isS3ImageAsset(asset))
|
|
1108
1140
|
return assetUtils.buildS3ImagePath(asset._id);
|
|
1141
|
+
if (assetUtils.isS3VideoAsset(asset))
|
|
1142
|
+
return assetUtils.buildS3VideoPath(asset._id);
|
|
1109
1143
|
if (assetUtils.isS3FileAsset(asset))
|
|
1110
1144
|
return assetUtils.buildS3FilePath(asset._id);
|
|
1111
1145
|
throw new Error("Unsupported asset type");
|
|
@@ -1319,8 +1353,8 @@ const exp = defineCreateClientExports(S3Client), createS3Client = exp.createClie
|
|
|
1319
1353
|
},
|
|
1320
1354
|
sort(state) {
|
|
1321
1355
|
state.allIds.sort((a, b) => {
|
|
1322
|
-
const tagA = state.byIds[a].asset[state.order.field], tagB = state.byIds[b].asset[state.order.field];
|
|
1323
|
-
return tagA < tagB ?
|
|
1356
|
+
const tagA = state.byIds[a].asset[state.order.field], tagB = state.byIds[b].asset[state.order.field], direction = state.order.direction === "asc" ? 1 : -1;
|
|
1357
|
+
return tagA < tagB ? -1 * direction : tagA > tagB ? 1 * direction : 0;
|
|
1324
1358
|
});
|
|
1325
1359
|
},
|
|
1326
1360
|
updateComplete(state, action) {
|
|
@@ -1513,12 +1547,9 @@ const exp = defineCreateClientExports(S3Client), createS3Client = exp.createClie
|
|
|
1513
1547
|
});
|
|
1514
1548
|
}
|
|
1515
1549
|
}
|
|
1516
|
-
}), dialogClearOnAssetUpdateEpic = (action$) => action$.pipe(reduxObservable.ofType(assetsActions.deleteComplete.type, assetsActions.updateComplete.type), operators.filter((action) => !!action?.payload?.closeDialogId), operators.mergeMap((action) => {
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
id: dialogId
|
|
1520
|
-
})) : rxjs.EMPTY;
|
|
1521
|
-
})), dialogActions = {
|
|
1550
|
+
}), dialogClearOnAssetUpdateEpic = (action$) => action$.pipe(reduxObservable.ofType(assetsActions.deleteComplete.type, assetsActions.updateComplete.type), operators.filter((action) => !!action?.payload?.closeDialogId), operators.mergeMap((action) => rxjs.of(dialogSlice.actions.remove({
|
|
1551
|
+
id: action.payload.closeDialogId
|
|
1552
|
+
})))), dialogActions = {
|
|
1522
1553
|
...dialogSlice.actions
|
|
1523
1554
|
}, dialogReducer = dialogSlice.reducer, initialState$2 = {
|
|
1524
1555
|
allIds: [],
|
|
@@ -1641,7 +1672,7 @@ const exp = defineCreateClientExports(S3Client), createS3Client = exp.createClie
|
|
|
1641
1672
|
operators.filter((hash) => !state.uploads.byIds[hash]),
|
|
1642
1673
|
// Dispatch start action and begin upload process
|
|
1643
1674
|
operators.mergeMap((hash) => {
|
|
1644
|
-
const assetType = forceAsAssetType || (file.type.indexOf("image") >= 0 ? assetUtils.S3AssetType.IMAGE : assetUtils.S3AssetType.FILE), uploadItem = {
|
|
1675
|
+
const assetType = forceAsAssetType || (file.type.indexOf("image") >= 0 ? assetUtils.S3AssetType.IMAGE : file.type.indexOf("video") >= 0 ? assetUtils.S3AssetType.VIDEO : assetUtils.S3AssetType.FILE), uploadItem = {
|
|
1645
1676
|
hash,
|
|
1646
1677
|
_type: "upload",
|
|
1647
1678
|
assetType,
|
|
@@ -1787,7 +1818,7 @@ const exp = defineCreateClientExports(S3Client), createS3Client = exp.createClie
|
|
|
1787
1818
|
} = useS3MediaContext();
|
|
1788
1819
|
let t0;
|
|
1789
1820
|
$[0] !== asset || $[1] !== buildAssetUrl ? (t0 = asset ? buildAssetUrl({
|
|
1790
|
-
assetType: assetUtils.S3AssetType.FILE,
|
|
1821
|
+
assetType: asset._type === "s3VideoAsset" ? assetUtils.S3AssetType.VIDEO : assetUtils.S3AssetType.FILE,
|
|
1791
1822
|
assetId: asset._id
|
|
1792
1823
|
}) : null, $[0] = asset, $[1] = buildAssetUrl, $[2] = t0) : t0 = $[2];
|
|
1793
1824
|
const assetUrl = t0;
|
|
@@ -1921,7 +1952,7 @@ const exp = defineCreateClientExports(S3Client), createS3Client = exp.createClie
|
|
|
1921
1952
|
opacity: opacityPreview
|
|
1922
1953
|
}, $[18] = opacityPreview, $[19] = t5) : t5 = $[19];
|
|
1923
1954
|
let t6;
|
|
1924
|
-
$[20] !== asset ? (t6 = assetUtils.isS3FileAsset(asset) && /* @__PURE__ */ jsxRuntime.jsx(FileIcon, { asset, extension: asset.extension, width: "80px" }), $[20] = asset, $[21] = t6) : t6 = $[21];
|
|
1955
|
+
$[20] !== asset ? (t6 = (assetUtils.isS3FileAsset(asset) || assetUtils.isS3VideoAsset(asset)) && /* @__PURE__ */ jsxRuntime.jsx(FileIcon, { asset, extension: asset.extension, width: "80px" }), $[20] = asset, $[21] = t6) : t6 = $[21];
|
|
1925
1956
|
let t7;
|
|
1926
1957
|
$[22] !== asset || $[23] !== buildAssetUrl || $[24] !== scheme ? (t7 = assetUtils.isS3ImageAsset(asset) && /* @__PURE__ */ jsxRuntime.jsx(Image$1, { draggable: !1, $scheme: scheme, $showCheckerboard: !0, src: buildAssetUrl({
|
|
1927
1958
|
assetId: asset._id,
|
|
@@ -2054,7 +2085,7 @@ const CardWrapper = styledComponents.styled(ui.Flex)`
|
|
|
2054
2085
|
opacity: 0.4
|
|
2055
2086
|
} }), $[14] = item.assetType, $[15] = item.objectUrl, $[16] = scheme, $[17] = t8) : t8 = $[17];
|
|
2056
2087
|
let t9;
|
|
2057
|
-
$[18] !== item.assetType ? (t9 = item.assetType === assetUtils.S3AssetType.FILE && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
2088
|
+
$[18] !== item.assetType ? (t9 = (item.assetType === assetUtils.S3AssetType.FILE || item.assetType === assetUtils.S3AssetType.VIDEO) && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
2058
2089
|
height: "100%",
|
|
2059
2090
|
opacity: 0.1
|
|
2060
2091
|
}, children: /* @__PURE__ */ jsxRuntime.jsx(FileIcon, { width: "80px" }) }), $[18] = item.assetType, $[19] = t9) : t9 = $[19];
|
|
@@ -2399,7 +2430,7 @@ const REFERENCE_COUNT_VISIBILITY_DELAY = 750, ContainerGrid = styledComponents.s
|
|
|
2399
2430
|
position: "relative"
|
|
2400
2431
|
}, $[34] = opacityPreview, $[35] = t16) : t16 = $[35];
|
|
2401
2432
|
let t17;
|
|
2402
|
-
$[36] !== asset ? (t17 = assetUtils.isS3FileAsset(asset) && /* @__PURE__ */ jsxRuntime.jsx(FileIcon, { asset, extension: asset.extension, width: "40px" }), $[36] = asset, $[37] = t17) : t17 = $[37];
|
|
2433
|
+
$[36] !== asset ? (t17 = (assetUtils.isS3FileAsset(asset) || assetUtils.isS3VideoAsset(asset)) && /* @__PURE__ */ jsxRuntime.jsx(FileIcon, { asset, extension: asset.extension, width: "40px" }), $[36] = asset, $[37] = t17) : t17 = $[37];
|
|
2403
2434
|
let t18;
|
|
2404
2435
|
$[38] !== asset || $[39] !== buildAssetUrl || $[40] !== scheme ? (t18 = assetUtils.isS3ImageAsset(asset) && /* @__PURE__ */ jsxRuntime.jsx(Image$1, { draggable: !1, $scheme: scheme, $showCheckerboard: !0, src: buildAssetUrl({
|
|
2405
2436
|
assetId: asset._id,
|
|
@@ -2459,7 +2490,7 @@ const REFERENCE_COUNT_VISIBILITY_DELAY = 750, ContainerGrid = styledComponents.s
|
|
|
2459
2490
|
lineHeight: "2em"
|
|
2460
2491
|
}, $[69] = t33) : t33 = $[69];
|
|
2461
2492
|
let t34;
|
|
2462
|
-
$[70] !== asset ? (t34 = assetUtils.isS3ImageAsset(asset) && getAssetResolution(asset), $[70] = asset, $[71] = t34) : t34 = $[71];
|
|
2493
|
+
$[70] !== asset ? (t34 = (assetUtils.isS3ImageAsset(asset) || assetUtils.isS3VideoAsset(asset)) && getAssetResolution(asset), $[70] = asset, $[71] = t34) : t34 = $[71];
|
|
2463
2494
|
let t35;
|
|
2464
2495
|
$[72] !== t34 ? (t35 = /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, style: t33, textOverflow: "ellipsis", children: t34 }), $[72] = t34, $[73] = t35) : t35 = $[73];
|
|
2465
2496
|
let t36;
|
|
@@ -2641,7 +2672,7 @@ const UploadDropzone = (props) => {
|
|
|
2641
2672
|
directUploads
|
|
2642
2673
|
} = useS3MediaOptionsContext(), {
|
|
2643
2674
|
onSelect
|
|
2644
|
-
} = useAssetSourceActions(), dispatch = reactRedux.useDispatch(), assetTypes = useTypedSelector(_temp$3), isImageAssetType = assetTypes.length === 1 && assetTypes[0] === assetUtils.S3AssetType.IMAGE;
|
|
2675
|
+
} = useAssetSourceActions(), dispatch = reactRedux.useDispatch(), assetTypes = useTypedSelector(_temp$3), isImageAssetType = assetTypes.length === 1 && assetTypes[0] === assetUtils.S3AssetType.IMAGE, isVideoAssetType = assetTypes.length === 1 && assetTypes[0] === assetUtils.S3AssetType.VIDEO;
|
|
2645
2676
|
let t0;
|
|
2646
2677
|
$[0] !== assetTypes[0] || $[1] !== assetTypes.length || $[2] !== dispatch ? (t0 = async (acceptedFiles) => {
|
|
2647
2678
|
acceptedFiles.forEach((file) => dispatch(uploadsActions.uploadRequest({
|
|
@@ -2673,7 +2704,7 @@ const UploadDropzone = (props) => {
|
|
|
2673
2704
|
title: "Unable to upload some items (folders and packages aren't supported)"
|
|
2674
2705
|
})), files;
|
|
2675
2706
|
}, $[6] = dispatch, $[7] = t2) : t2 = $[7];
|
|
2676
|
-
const handleFileGetter = t2, t3 = isImageAssetType ? "image/*" : "", t4 = !!onSelect, t5 = !directUploads;
|
|
2707
|
+
const handleFileGetter = t2, t3 = isImageAssetType ? "image/*" : isVideoAssetType ? "video/*" : "", t4 = !!onSelect, t5 = !directUploads;
|
|
2677
2708
|
let t6;
|
|
2678
2709
|
$[8] !== handleDrop || $[9] !== handleDropRejected || $[10] !== handleFileGetter || $[11] !== t3 || $[12] !== t4 || $[13] !== t5 ? (t6 = {
|
|
2679
2710
|
accept: t3,
|
|
@@ -2834,7 +2865,7 @@ const UPLOAD_DROP_DOWN_MENU_POPOVER = {
|
|
|
2834
2865
|
readOnly,
|
|
2835
2866
|
schemaType,
|
|
2836
2867
|
type
|
|
2837
|
-
} = props, [rootElement, setRootElement] = react.useState(null), rect = ui.useElementSize(rootElement), collapsed = rect?.border && rect.border.width < 440, isFileType = type === assetUtils.S3AssetType.FILE, {
|
|
2868
|
+
} = props, [rootElement, setRootElement] = react.useState(null), rect = ui.useElementSize(rootElement), collapsed = rect?.border && rect.border.width < 440, isFileType = type === assetUtils.S3AssetType.FILE, isVideoType = type === assetUtils.S3AssetType.VIDEO, {
|
|
2838
2869
|
t
|
|
2839
2870
|
} = sanity.useTranslation();
|
|
2840
2871
|
let t0;
|
|
@@ -2844,7 +2875,7 @@ const UPLOAD_DROP_DOWN_MENU_POPOVER = {
|
|
|
2844
2875
|
$[2] !== onUpload ? (t1 = (assetSource, files) => {
|
|
2845
2876
|
onUpload && onUpload(assetSource, files);
|
|
2846
2877
|
}, $[2] = onUpload, $[3] = t1) : t1 = $[3];
|
|
2847
|
-
const handleSelectFiles = t1, t2 = isFileType ? "" : "image/*";
|
|
2878
|
+
const handleSelectFiles = t1, t2 = isFileType ? "" : isVideoType ? "video/*" : "image/*";
|
|
2848
2879
|
let t3;
|
|
2849
2880
|
$[4] !== schemaType || $[5] !== t2 ? (t3 = get__default.default(schemaType, "options.accept", t2), $[4] = schemaType, $[5] = t2, $[6] = t3) : t3 = $[6];
|
|
2850
2881
|
const accept = t3;
|
|
@@ -2884,8 +2915,13 @@ const UPLOAD_DROP_DOWN_MENU_POPOVER = {
|
|
|
2884
2915
|
$[24] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t63 = /* @__PURE__ */ jsxRuntime.jsx(icons.AccessDeniedIcon, {}), $[24] = t63) : t63 = $[24], t5 = t63;
|
|
2885
2916
|
break bb1;
|
|
2886
2917
|
}
|
|
2918
|
+
if (isVideoType || isFileType) {
|
|
2919
|
+
let t63;
|
|
2920
|
+
$[25] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t63 = /* @__PURE__ */ jsxRuntime.jsx(icons.BinaryDocumentIcon, {}), $[25] = t63) : t63 = $[25], t5 = t63;
|
|
2921
|
+
break bb1;
|
|
2922
|
+
}
|
|
2887
2923
|
let t62;
|
|
2888
|
-
$[
|
|
2924
|
+
$[26] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t62 = /* @__PURE__ */ jsxRuntime.jsx(icons.ImageIcon, {}), $[26] = t62) : t62 = $[26], t5 = t62;
|
|
2889
2925
|
}
|
|
2890
2926
|
const messageIcon = t5;
|
|
2891
2927
|
let t6;
|
|
@@ -2898,7 +2934,7 @@ const UPLOAD_DROP_DOWN_MENU_POPOVER = {
|
|
|
2898
2934
|
t6 = "Read only";
|
|
2899
2935
|
break bb2;
|
|
2900
2936
|
}
|
|
2901
|
-
t6 = isFileType ? "Drag or paste file here" : "Drag or paste image here";
|
|
2937
|
+
t6 = isVideoType ? "Drag or paste video here" : isFileType ? "Drag or paste file here" : "Drag or paste image here";
|
|
2902
2938
|
}
|
|
2903
2939
|
const messageText = t6;
|
|
2904
2940
|
let t7;
|