sanity-plugin-mux-input 2.2.4 → 2.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.
Files changed (49) hide show
  1. package/README.md +148 -16
  2. package/lib/index.cjs +3995 -3676
  3. package/lib/index.cjs.map +1 -1
  4. package/lib/index.d.cts +210 -0
  5. package/lib/index.d.ts +109 -25
  6. package/lib/index.esm.js +4384 -0
  7. package/lib/index.esm.js.map +1 -0
  8. package/lib/index.js +3957 -3625
  9. package/lib/index.js.map +1 -1
  10. package/package.json +47 -51
  11. package/src/_exports/index.ts +32 -0
  12. package/src/actions/upload.ts +35 -40
  13. package/src/clients/upChunkObservable.ts +5 -1
  14. package/src/components/ConfigureApi.tsx +0 -1
  15. package/src/components/FileInputArea.tsx +92 -0
  16. package/src/components/FileInputButton.tsx +3 -2
  17. package/src/components/FileInputMenuItem.styled.tsx +2 -2
  18. package/src/components/FileInputMenuItem.tsx +2 -10
  19. package/src/components/ImportVideosFromMux.tsx +317 -0
  20. package/src/components/Input.tsx +3 -3
  21. package/src/components/PlayerActionsMenu.tsx +14 -12
  22. package/src/components/SelectAsset.tsx +1 -1
  23. package/src/components/StudioTool.tsx +11 -6
  24. package/src/components/TextTracksEditor.tsx +214 -0
  25. package/src/components/UploadConfiguration.tsx +390 -0
  26. package/src/components/UploadPlaceholder.tsx +41 -55
  27. package/src/components/Uploader.styled.tsx +0 -1
  28. package/src/components/Uploader.tsx +384 -0
  29. package/src/components/VideoDetails/DeleteDialog.tsx +20 -24
  30. package/src/components/VideoPlayer.tsx +33 -5
  31. package/src/components/VideoThumbnail.tsx +21 -7
  32. package/src/components/VideosBrowser.tsx +6 -3
  33. package/src/components/withFocusRing/withFocusRing.ts +20 -22
  34. package/src/hooks/useClient.ts +1 -1
  35. package/src/hooks/useImportMuxAssets.ts +127 -0
  36. package/src/hooks/useMuxAssets.ts +168 -0
  37. package/src/plugin.tsx +5 -5
  38. package/src/util/asserters.ts +9 -0
  39. package/src/util/createSearchFilter.ts +1 -1
  40. package/src/util/formatBytes.ts +32 -0
  41. package/src/util/generateJwt.ts +1 -0
  42. package/src/util/getAnimatedPosterSrc.ts +1 -1
  43. package/src/util/getPlaybackId.ts +1 -1
  44. package/src/util/getPlaybackPolicy.ts +1 -1
  45. package/src/util/parsers.ts +5 -0
  46. package/src/util/types.ts +195 -12
  47. package/lib/index.cjs.js +0 -5
  48. package/src/components/__legacy__Uploader.tsx +0 -280
  49. package/src/index.ts +0 -29
@@ -0,0 +1,4384 @@
1
+ import { useClient as useClient$1, createHookFromObservableFactory, useDocumentStore, collate, useDocumentValues, truncateString, useFormattedDuration, SanityDefaultPreview, useTimeAgo, TextWithTone, isRecord, getPreviewStateObservable, getPreviewValueWithFallback, DocumentPreviewPresence, useDocumentPreviewStore, useSchema, useDocumentPresence, PreviewCard, isReference, useProjectId, useDataset, PatchEvent, unset, setIfMissing, set, LinearProgress, FormField as FormField$2, definePlugin } from "sanity";
2
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
3
+ import { ErrorOutlineIcon, RetrieveIcon, RetryIcon, CheckmarkCircleIcon, SortIcon, WarningOutlineIcon, EditIcon, PublishIcon, DocumentIcon, TrashIcon, CheckmarkIcon, RevertIcon, SearchIcon, ClockIcon, CropIcon, CalendarIcon, TagIcon, LockIcon, PlayIcon, PlugIcon, UploadIcon, ResetIcon, EllipsisHorizontalIcon, AddIcon, TranslateIcon, DocumentVideoIcon } from "@sanity/icons";
4
+ import { Card, Box, Spinner, Stack, Text, Checkbox, Button, Dialog, Flex, Heading, Code, MenuButton, Menu, MenuItem, Tooltip, Inline, useToast, TabList, Tab, TabPanel, TextInput, Label as Label$1, Grid, useClickOutside, Popover, MenuDivider, Radio, Autocomplete, rem } from "@sanity/ui";
5
+ import React, { useState, useMemo, useEffect, useRef, useId, memo, isValidElement, useCallback, useReducer, createElement, forwardRef, Suspense } from "react";
6
+ import { words, trim, toLower, uniq, compact, isString, isNumber } from "lodash";
7
+ import styled, { css } from "styled-components";
8
+ import { uuid } from "@sanity/uuid";
9
+ import { defer, timer, of, Observable, concat, throwError, from, Subject } from "rxjs";
10
+ import { expand, concatMap, tap, switchMap, mergeMap, catchError, mergeMapTo, takeUntil } from "rxjs/operators";
11
+ import { suspend, clear, preload } from "suspend-react";
12
+ import MuxPlayer from "@mux/mux-player-react";
13
+ import { usePaneRouter } from "sanity/desk";
14
+ import { IntentLink } from "sanity/router";
15
+ import { useMemoObservable } from "react-rx";
16
+ import useSWR from "swr";
17
+ import scrollIntoView from "scroll-into-view-if-needed";
18
+ import { useErrorBoundary } from "use-error-boundary";
19
+ import { UpChunk } from "@mux/upchunk";
20
+ import { isValidElementType } from "react-is";
21
+ import LanguagesList from "iso-639-1";
22
+ const ToolIcon = () => /* @__PURE__ */ jsx(
23
+ "svg",
24
+ {
25
+ stroke: "currentColor",
26
+ fill: "currentColor",
27
+ strokeWidth: "0",
28
+ viewBox: "0 0 24 24",
29
+ height: "1em",
30
+ width: "1em",
31
+ xmlns: "http://www.w3.org/2000/svg",
32
+ children: /* @__PURE__ */ jsx("path", { d: "M21 3H3c-1.11 0-2 .89-2 2v12c0 1.1.89 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.11-.9-2-2-2zm0 14H3V5h18v12zm-5-6l-7 4V7z" })
33
+ }
34
+ ), SANITY_API_VERSION = "2024-03-05";
35
+ function useClient() {
36
+ return useClient$1({ apiVersion: SANITY_API_VERSION });
37
+ }
38
+ const SPECIAL_CHARS = /([^!@#$%^&*(),\\/?";:{}|[\]+<>\s-])+/g, STRIP_EDGE_CHARS = /(^[.]+)|([.]+$)/;
39
+ function tokenize(string) {
40
+ return (string.match(SPECIAL_CHARS) || []).map((token) => token.replace(STRIP_EDGE_CHARS, ""));
41
+ }
42
+ function toGroqParams(terms) {
43
+ const params = {};
44
+ return terms.reduce((acc, term, i) => (acc[`t${i}`] = `*${term}*`, acc), params);
45
+ }
46
+ function extractTermsFromQuery(query) {
47
+ const quotedQueries = [], unquotedQuery = query.replace(/("[^"]*")/g, (match) => words(match).length > 1 ? (quotedQueries.push(match), "") : match), quotedTerms = quotedQueries.map((str) => trim(toLower(str))), remainingTerms = uniq(compact(tokenize(toLower(unquotedQuery))));
48
+ return [...quotedTerms, ...remainingTerms];
49
+ }
50
+ function createConstraints(terms, includeAssetId) {
51
+ const searchPaths = includeAssetId ? ["filename", "assetId"] : ["filename"];
52
+ return terms.map((_term, i) => searchPaths.map((joinedPath) => `${joinedPath} match $t${i}`)).filter((constraint) => constraint.length > 0).map((constraint) => `(${constraint.join(" || ")})`);
53
+ }
54
+ function createSearchFilter(query) {
55
+ const terms = extractTermsFromQuery(query);
56
+ return {
57
+ filter: createConstraints(terms, query.length >= 8),
58
+ // if the search is big enough, include the assetId (mux id) in the results
59
+ params: {
60
+ ...toGroqParams(terms)
61
+ }
62
+ };
63
+ }
64
+ const ASSET_SORT_OPTIONS = {
65
+ createdDesc: { groq: "_createdAt desc", label: "Newest first" },
66
+ createdAsc: { groq: "_createdAt asc", label: "First created (oldest)" },
67
+ filenameAsc: { groq: "filename asc", label: "By filename (A-Z)" },
68
+ filenameDesc: { groq: "filename desc", label: "By filename (Z-A)" }
69
+ }, useAssetDocuments = createHookFromObservableFactory(({ documentStore, sort, searchQuery }) => {
70
+ const search = createSearchFilter(searchQuery), filter = ['_type == "mux.videoAsset"', ...search.filter].filter(Boolean).join(" && "), sortFragment = ASSET_SORT_OPTIONS[sort].groq;
71
+ return documentStore.listenQuery(
72
+ /* groq */
73
+ `*[${filter}] | order(${sortFragment})`,
74
+ search.params,
75
+ {
76
+ apiVersion: SANITY_API_VERSION
77
+ }
78
+ );
79
+ });
80
+ function useAssets() {
81
+ const documentStore = useDocumentStore(), [sort, setSort] = useState("createdDesc"), [searchQuery, setSearchQuery] = useState(""), [assetDocuments = [], isLoading] = useAssetDocuments({ documentStore, sort, searchQuery });
82
+ return {
83
+ assets: useMemo(
84
+ () => (
85
+ // Avoid displaying both drafts & published assets by collating them together and giving preference to drafts
86
+ collate(assetDocuments).map(
87
+ (collated) => ({
88
+ ...collated.draft || collated.published || {},
89
+ _id: collated.id
90
+ })
91
+ )
92
+ ),
93
+ [assetDocuments]
94
+ ),
95
+ isLoading,
96
+ sort,
97
+ searchQuery,
98
+ setSort,
99
+ setSearchQuery
100
+ };
101
+ }
102
+ function parseMuxDate(date) {
103
+ return new Date(Number(date) * 1e3);
104
+ }
105
+ const FIRST_PAGE = 1, ASSETS_PER_PAGE = 100;
106
+ async function fetchMuxAssetsPage({ secretKey, token }, pageNum) {
107
+ try {
108
+ const json = await (await fetch(
109
+ `https://api.mux.com/video/v1/assets?limit=${ASSETS_PER_PAGE}&page=${pageNum}`,
110
+ {
111
+ headers: {
112
+ Authorization: `Basic ${btoa(`${token}:${secretKey}`)}`
113
+ }
114
+ }
115
+ )).json();
116
+ return json.error ? {
117
+ pageNum,
118
+ error: {
119
+ _tag: "MuxError",
120
+ error: json.error
121
+ }
122
+ } : {
123
+ pageNum,
124
+ data: json.data
125
+ };
126
+ } catch {
127
+ return {
128
+ pageNum,
129
+ error: { _tag: "FetchError" }
130
+ };
131
+ }
132
+ }
133
+ function accumulateIntermediateState(currentState, pageResult) {
134
+ const currentData = "data" in currentState && currentState.data || [];
135
+ return {
136
+ ...currentState,
137
+ data: [
138
+ ...currentData,
139
+ ...("data" in pageResult && pageResult.data || []).filter(
140
+ // De-duplicate assets for safety
141
+ (asset) => !currentData.some((a) => a.id === asset.id)
142
+ )
143
+ ],
144
+ error: "error" in pageResult ? pageResult.error : (
145
+ // Reset error if current page is successful
146
+ void 0
147
+ ),
148
+ pageNum: pageResult.pageNum,
149
+ loading: !0
150
+ };
151
+ }
152
+ function hasMorePages(pageResult) {
153
+ return typeof pageResult == "object" && "data" in pageResult && Array.isArray(pageResult.data) && pageResult.data.length > 0;
154
+ }
155
+ function useMuxAssets({ secrets, enabled }) {
156
+ const [state, setState] = useState({ loading: !0, pageNum: FIRST_PAGE });
157
+ return useEffect(() => {
158
+ if (!enabled)
159
+ return;
160
+ const subscription = defer(
161
+ () => fetchMuxAssetsPage(
162
+ secrets,
163
+ // When we've already successfully loaded before (fully or partially), we start from the following page to avoid re-fetching
164
+ "data" in state && state.data && state.data.length > 0 && !state.error ? state.pageNum + 1 : state.pageNum
165
+ )
166
+ ).pipe(
167
+ // Here we replace "concatMap" with "expand" to recursively fetch next pages
168
+ expand((pageResult) => hasMorePages(pageResult) ? timer(2e3).pipe(
169
+ // eslint-disable-next-line max-nested-callbacks
170
+ concatMap(() => defer(() => fetchMuxAssetsPage(secrets, pageResult.pageNum + 1)))
171
+ ) : of()),
172
+ // On each iteration, persist intermediate states to give feedback to users
173
+ tap(
174
+ (pageResult) => setState((prevState) => accumulateIntermediateState(prevState, pageResult))
175
+ )
176
+ ).subscribe({
177
+ // Once done, let the user know we've stopped loading
178
+ complete: () => {
179
+ setState((prev) => ({
180
+ ...prev,
181
+ loading: !1
182
+ }));
183
+ }
184
+ });
185
+ return () => subscription.unsubscribe();
186
+ }, [enabled]), state;
187
+ }
188
+ const name$1 = "mux-input", cacheNs = "sanity-plugin-mux-input", muxSecretsDocumentId = "secrets.mux", DIALOGS_Z_INDEX = 6e4, THUMBNAIL_ASPECT_RATIO = 1.7777777777777777, MIN_ASPECT_RATIO = 5 / 4, path$1 = ["token", "secretKey", "enableSignedUrls", "signingKeyId", "signingKeyPrivate"], useSecretsDocumentValues = () => {
189
+ const { error, isLoading, value } = useDocumentValues(
190
+ muxSecretsDocumentId,
191
+ path$1
192
+ ), cache = useMemo(() => {
193
+ const exists = !!value, secrets = {
194
+ token: (value == null ? void 0 : value.token) || null,
195
+ secretKey: (value == null ? void 0 : value.secretKey) || null,
196
+ enableSignedUrls: (value == null ? void 0 : value.enableSignedUrls) || !1,
197
+ signingKeyId: (value == null ? void 0 : value.signingKeyId) || null,
198
+ signingKeyPrivate: (value == null ? void 0 : value.signingKeyPrivate) || null
199
+ };
200
+ return {
201
+ isInitialSetup: !exists,
202
+ needsSetup: !(secrets != null && secrets.token) || !(secrets != null && secrets.secretKey),
203
+ secrets
204
+ };
205
+ }, [value]);
206
+ return { error, isLoading, value: cache };
207
+ };
208
+ function useImportMuxAssets() {
209
+ var _a;
210
+ const documentStore = useDocumentStore(), client = useClient$1({
211
+ apiVersion: SANITY_API_VERSION
212
+ }), [assetsInSanity, assetsInSanityLoading] = useAssetsInSanity(documentStore), secretDocumentValues = useSecretsDocumentValues(), hasSecrets = !!((_a = secretDocumentValues.value.secrets) != null && _a.secretKey), [importError, setImportError] = useState(), [importState, setImportState] = useState("closed"), dialogOpen = importState !== "closed", muxAssets = useMuxAssets({
213
+ secrets: secretDocumentValues.value.secrets,
214
+ enabled: hasSecrets && dialogOpen
215
+ }), missingAssets = useMemo(() => assetsInSanity && muxAssets.data ? muxAssets.data.filter((a) => !assetExistsInSanity(a, assetsInSanity)) : void 0, [assetsInSanity, muxAssets.data]), [selectedAssets, setSelectedAssets] = useState([]), closeDialog = () => {
216
+ importState !== "importing" && setImportState("closed");
217
+ }, openDialog = () => {
218
+ importState === "closed" && setImportState("idle");
219
+ };
220
+ async function importAssets() {
221
+ setImportState("importing");
222
+ const documents = selectedAssets.map(muxAssetToSanityDocument), tx = client.transaction();
223
+ documents.forEach((doc) => tx.create(doc));
224
+ try {
225
+ await tx.commit({ returnDocuments: !1 }), setSelectedAssets([]), setImportState("done");
226
+ } catch (error) {
227
+ setImportState("error"), setImportError(error);
228
+ }
229
+ }
230
+ return {
231
+ assetsInSanityLoading,
232
+ closeDialog,
233
+ dialogOpen,
234
+ importState,
235
+ importError,
236
+ hasSecrets,
237
+ importAssets,
238
+ missingAssets,
239
+ muxAssets,
240
+ openDialog,
241
+ selectedAssets,
242
+ setSelectedAssets
243
+ };
244
+ }
245
+ function muxAssetToSanityDocument(asset) {
246
+ var _a;
247
+ return {
248
+ _id: uuid(),
249
+ _type: "mux.videoAsset",
250
+ _updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
251
+ _createdAt: parseMuxDate(asset.created_at).toISOString(),
252
+ assetId: asset.id,
253
+ playbackId: (_a = asset.playback_ids.find((p) => p.id)) == null ? void 0 : _a.id,
254
+ filename: `Asset #${truncateString(asset.id, 15)}`,
255
+ status: asset.status,
256
+ data: asset
257
+ };
258
+ }
259
+ const useAssetsInSanity = createHookFromObservableFactory(
260
+ (documentStore) => documentStore.listenQuery(
261
+ /* groq */
262
+ `*[_type == "mux.videoAsset"] {
263
+ "uploadId": coalesce(uploadId, data.upload_id),
264
+ "assetId": coalesce(assetId, data.id),
265
+ }`,
266
+ {},
267
+ {
268
+ apiVersion: SANITY_API_VERSION
269
+ }
270
+ )
271
+ );
272
+ function assetExistsInSanity(asset, existingAssets) {
273
+ return asset.status !== "ready" ? !1 : existingAssets.some(
274
+ (existing) => existing.assetId === asset.id || existing.uploadId === asset.upload_id
275
+ );
276
+ }
277
+ function useInView(options = {}) {
278
+ const [inView, setInView] = useState(!1), ref = useRef(null);
279
+ return useEffect(() => {
280
+ if (!ref.current)
281
+ return;
282
+ const observer = new IntersectionObserver(([entry], obs) => {
283
+ var _a;
284
+ const nowInView = entry.isIntersecting && obs.thresholds.some((threshold) => entry.intersectionRatio >= threshold);
285
+ setInView(nowInView), (_a = options == null ? void 0 : options.onChange) == null || _a.call(options, nowInView);
286
+ }, options), toObserve = ref.current;
287
+ return observer.observe(toObserve), () => {
288
+ toObserve && observer.unobserve(toObserve);
289
+ };
290
+ }, [options]), { inView, ref };
291
+ }
292
+ const _id = "secrets.mux";
293
+ function readSecrets(client) {
294
+ const { projectId, dataset } = client.config();
295
+ return suspend(async () => {
296
+ const data = await client.fetch(
297
+ /* groq */
298
+ `*[_id == $_id][0]{
299
+ token,
300
+ secretKey,
301
+ enableSignedUrls,
302
+ signingKeyId,
303
+ signingKeyPrivate
304
+ }`,
305
+ { _id }
306
+ );
307
+ return {
308
+ token: (data == null ? void 0 : data.token) || null,
309
+ secretKey: (data == null ? void 0 : data.secretKey) || null,
310
+ enableSignedUrls: !!(data != null && data.enableSignedUrls) || !1,
311
+ signingKeyId: (data == null ? void 0 : data.signingKeyId) || null,
312
+ signingKeyPrivate: (data == null ? void 0 : data.signingKeyPrivate) || null
313
+ };
314
+ }, [cacheNs, _id, projectId, dataset]);
315
+ }
316
+ function generateJwt(client, playbackId, aud, payload) {
317
+ const { signingKeyId, signingKeyPrivate } = readSecrets(client);
318
+ if (!signingKeyId)
319
+ throw new TypeError("Missing signingKeyId");
320
+ if (!signingKeyPrivate)
321
+ throw new TypeError("Missing signingKeyPrivate");
322
+ const { default: sign } = suspend(() => import("jsonwebtoken-esm/sign"), ["jsonwebtoken-esm/sign"]);
323
+ return sign(
324
+ payload ? JSON.parse(JSON.stringify(payload, (_, v) => v != null ? v : void 0)) : {},
325
+ atob(signingKeyPrivate),
326
+ {
327
+ algorithm: "RS256",
328
+ keyid: signingKeyId,
329
+ audience: aud,
330
+ subject: playbackId,
331
+ noTimestamp: !0,
332
+ expiresIn: "12h"
333
+ }
334
+ );
335
+ }
336
+ function getPlaybackId(asset) {
337
+ if (!(asset != null && asset.playbackId))
338
+ throw console.error("Asset is missing a playbackId", { asset }), new TypeError("Missing playbackId");
339
+ return asset.playbackId;
340
+ }
341
+ function getPlaybackPolicy(asset) {
342
+ var _a, _b, _c, _d;
343
+ return (_d = (_c = (_b = (_a = asset.data) == null ? void 0 : _a.playback_ids) == null ? void 0 : _b[0]) == null ? void 0 : _c.policy) != null ? _d : "public";
344
+ }
345
+ function getAnimatedPosterSrc({
346
+ asset,
347
+ client,
348
+ height,
349
+ width,
350
+ start = asset.thumbTime ? Math.max(0, asset.thumbTime - 2.5) : 0,
351
+ end = start + 5,
352
+ fps = 15
353
+ }) {
354
+ const params = { height, width, start, end, fps }, playbackId = getPlaybackId(asset);
355
+ let searchParams = new URLSearchParams(
356
+ JSON.parse(JSON.stringify(params, (_, v) => v != null ? v : void 0))
357
+ );
358
+ if (getPlaybackPolicy(asset) === "signed") {
359
+ const token = generateJwt(client, playbackId, "g", params);
360
+ searchParams = new URLSearchParams({ token });
361
+ }
362
+ return `https://image.mux.com/${playbackId}/animated.gif?${searchParams}`;
363
+ }
364
+ const Image = styled.img`
365
+ transition: opacity 0.175s ease-out 0s;
366
+ display: block;
367
+ width: 100%;
368
+ height: 100%;
369
+ object-fit: contain;
370
+ object-position: center center;
371
+ `, STATUS_TO_TONE = {
372
+ loading: "transparent",
373
+ error: "critical",
374
+ loaded: "default"
375
+ };
376
+ function VideoThumbnail({
377
+ asset,
378
+ width
379
+ }) {
380
+ const { inView, ref } = useInView(), posterWidth = width || 250, [status, setStatus] = useState("loading"), client = useClient(), animatedSrc = useMemo(() => {
381
+ try {
382
+ return getAnimatedPosterSrc({ asset, client, width: posterWidth });
383
+ } catch {
384
+ status !== "error" && setStatus("error");
385
+ return;
386
+ }
387
+ }, [asset, client, width, status, setStatus]);
388
+ function handleLoad() {
389
+ setStatus("loaded");
390
+ }
391
+ function handleError() {
392
+ setStatus("error");
393
+ }
394
+ return /* @__PURE__ */ jsx(
395
+ Card,
396
+ {
397
+ style: {
398
+ aspectRatio: THUMBNAIL_ASPECT_RATIO,
399
+ position: "relative",
400
+ maxWidth: width ? `${width}px` : void 0,
401
+ width: "100%",
402
+ flex: 1
403
+ },
404
+ border: !0,
405
+ radius: 2,
406
+ ref,
407
+ tone: STATUS_TO_TONE[status],
408
+ children: inView ? /* @__PURE__ */ jsxs(Fragment, { children: [
409
+ status === "loading" && /* @__PURE__ */ jsx(
410
+ Box,
411
+ {
412
+ style: {
413
+ position: "absolute",
414
+ left: "50%",
415
+ top: "50%",
416
+ transform: "translate(-50%, -50%)"
417
+ },
418
+ children: /* @__PURE__ */ jsx(Spinner, {})
419
+ }
420
+ ),
421
+ status === "error" && /* @__PURE__ */ jsxs(
422
+ Stack,
423
+ {
424
+ space: 4,
425
+ style: {
426
+ position: "absolute",
427
+ width: "100%",
428
+ left: 0,
429
+ top: "50%",
430
+ transform: "translateY(-50%)",
431
+ justifyItems: "center"
432
+ },
433
+ children: [
434
+ /* @__PURE__ */ jsx(Text, { size: 4, muted: !0, children: /* @__PURE__ */ jsx(ErrorOutlineIcon, { style: { fontSize: "1.75em" } }) }),
435
+ /* @__PURE__ */ jsx(Text, { muted: !0, align: "center", children: "Failed loading thumbnail" })
436
+ ]
437
+ }
438
+ ),
439
+ /* @__PURE__ */ jsx(
440
+ Image,
441
+ {
442
+ src: animatedSrc,
443
+ alt: `Preview for video ${asset.filename || asset.assetId}`,
444
+ onLoad: handleLoad,
445
+ onError: handleError,
446
+ style: {
447
+ opacity: status === "loaded" ? 1 : 0
448
+ }
449
+ }
450
+ )
451
+ ] }) : null
452
+ }
453
+ );
454
+ }
455
+ const MissingAssetCheckbox = styled(Checkbox)`
456
+ position: static !important;
457
+
458
+ input::after {
459
+ content: '';
460
+ position: absolute;
461
+ inset: 0;
462
+ display: block;
463
+ cursor: pointer;
464
+ z-index: 1000;
465
+ }
466
+ `;
467
+ function MissingAsset({
468
+ asset,
469
+ selectAsset,
470
+ selected
471
+ }) {
472
+ var _a;
473
+ const duration = useFormattedDuration(asset.duration * 1e3);
474
+ return /* @__PURE__ */ jsx(
475
+ Card,
476
+ {
477
+ tone: selected ? "positive" : void 0,
478
+ border: !0,
479
+ paddingX: 2,
480
+ paddingY: 3,
481
+ style: { position: "relative" },
482
+ radius: 1,
483
+ children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
484
+ /* @__PURE__ */ jsx(
485
+ MissingAssetCheckbox,
486
+ {
487
+ checked: selected,
488
+ onChange: (e) => {
489
+ selectAsset(e.currentTarget.checked);
490
+ },
491
+ "aria-label": selected ? `Import video ${asset.id}` : `Skip import of video ${asset.id}`
492
+ }
493
+ ),
494
+ /* @__PURE__ */ jsx(
495
+ VideoThumbnail,
496
+ {
497
+ asset: {
498
+ assetId: asset.id,
499
+ data: asset,
500
+ filename: asset.id,
501
+ playbackId: (_a = asset.playback_ids.find((p) => p.id)) == null ? void 0 : _a.id
502
+ },
503
+ width: 150
504
+ }
505
+ ),
506
+ /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
507
+ /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 1, children: [
508
+ /* @__PURE__ */ jsx(Code, { size: 2, children: truncateString(asset.id, 15) }),
509
+ " ",
510
+ /* @__PURE__ */ jsxs(Text, { muted: !0, size: 2, children: [
511
+ "(",
512
+ duration.formatted,
513
+ ")"
514
+ ] })
515
+ ] }),
516
+ /* @__PURE__ */ jsxs(Text, { size: 1, children: [
517
+ "Uploaded at",
518
+ " ",
519
+ new Date(Number(asset.created_at) * 1e3).toLocaleDateString("en", {
520
+ year: "numeric",
521
+ day: "2-digit",
522
+ month: "2-digit"
523
+ })
524
+ ] })
525
+ ] })
526
+ ] })
527
+ },
528
+ asset.id
529
+ );
530
+ }
531
+ function ImportVideosDialog(props) {
532
+ var _a, _b;
533
+ const { importState } = props, canTriggerImport = (importState === "idle" || importState === "error") && props.selectedAssets.length > 0, isImporting = importState === "importing", noAssetsToImport = ((_a = props.missingAssets) == null ? void 0 : _a.length) === 0 && !props.muxAssets.loading && !props.assetsInSanityLoading;
534
+ return /* @__PURE__ */ jsx(
535
+ Dialog,
536
+ {
537
+ header: "Import videos from Mux",
538
+ zOffset: DIALOGS_Z_INDEX,
539
+ id: "video-details-dialog",
540
+ onClose: props.closeDialog,
541
+ onClickOutside: props.closeDialog,
542
+ width: 1,
543
+ position: "fixed",
544
+ footer: importState !== "done" && !noAssetsToImport && /* @__PURE__ */ jsx(Card, { padding: 3, children: /* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
545
+ /* @__PURE__ */ jsx(
546
+ Button,
547
+ {
548
+ fontSize: 2,
549
+ padding: 3,
550
+ mode: "bleed",
551
+ text: "Cancel",
552
+ tone: "critical",
553
+ onClick: props.closeDialog,
554
+ disabled: isImporting
555
+ }
556
+ ),
557
+ props.missingAssets && /* @__PURE__ */ jsx(
558
+ Button,
559
+ {
560
+ icon: RetrieveIcon,
561
+ fontSize: 2,
562
+ padding: 3,
563
+ mode: "ghost",
564
+ text: ((_b = props.selectedAssets) == null ? void 0 : _b.length) > 0 ? `Import ${props.selectedAssets.length} video(s)` : "No video(s) selected",
565
+ tone: "positive",
566
+ onClick: props.importAssets,
567
+ iconRight: isImporting && Spinner,
568
+ disabled: !canTriggerImport
569
+ }
570
+ )
571
+ ] }) }),
572
+ children: /* @__PURE__ */ jsxs(Box, { padding: 3, children: [
573
+ (props.muxAssets.loading || props.assetsInSanityLoading) && /* @__PURE__ */ jsx(Card, { tone: "primary", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 4, children: [
574
+ /* @__PURE__ */ jsx(Spinner, { muted: !0, size: 4 }),
575
+ /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
576
+ /* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "Loading assets from Mux" }),
577
+ /* @__PURE__ */ jsxs(Text, { size: 1, children: [
578
+ "This may take a while.",
579
+ props.missingAssets && props.missingAssets.length > 0 && ` There are at least ${props.missingAssets.length} video${props.missingAssets.length > 1 ? "s" : ""} currently not in Sanity...`
580
+ ] })
581
+ ] })
582
+ ] }) }),
583
+ props.muxAssets.error && /* @__PURE__ */ jsx(Card, { tone: "critical", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
584
+ /* @__PURE__ */ jsx(ErrorOutlineIcon, { fontSize: 36 }),
585
+ /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
586
+ /* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "There was an error getting all data from Mux" }),
587
+ /* @__PURE__ */ jsx(Text, { size: 1, children: props.missingAssets ? `But we've found ${props.missingAssets.length} video${props.missingAssets.length > 1 ? "s" : ""} not in Sanity, which you can start importing now.` : "Please try again or contact a developer for help." })
588
+ ] })
589
+ ] }) }),
590
+ importState === "importing" && /* @__PURE__ */ jsx(Card, { tone: "primary", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 4, children: [
591
+ /* @__PURE__ */ jsx(Spinner, { muted: !0, size: 4 }),
592
+ /* @__PURE__ */ jsx(Stack, { space: 2, children: /* @__PURE__ */ jsxs(Text, { size: 2, weight: "semibold", children: [
593
+ "Importing ",
594
+ props.selectedAssets.length,
595
+ " video",
596
+ props.selectedAssets.length > 1 && "s",
597
+ " from Mux"
598
+ ] }) })
599
+ ] }) }),
600
+ importState === "error" && /* @__PURE__ */ jsx(Card, { tone: "critical", marginBottom: 5, padding: 3, border: !0, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
601
+ /* @__PURE__ */ jsx(ErrorOutlineIcon, { fontSize: 36 }),
602
+ /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
603
+ /* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "There was an error importing videos" }),
604
+ /* @__PURE__ */ jsx(Text, { size: 1, children: props.importError ? `Error: ${props.importError}` : "Please try again or contact a developer for help." }),
605
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
606
+ Button,
607
+ {
608
+ icon: RetryIcon,
609
+ text: "Retry",
610
+ tone: "primary",
611
+ onClick: props.importAssets
612
+ }
613
+ ) })
614
+ ] })
615
+ ] }) }),
616
+ (noAssetsToImport || importState === "done") && /* @__PURE__ */ jsxs(Stack, { paddingY: 5, marginBottom: 4, space: 3, style: { textAlign: "center" }, children: [
617
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(CheckmarkCircleIcon, { fontSize: 48 }) }),
618
+ /* @__PURE__ */ jsx(Heading, { size: 2, children: importState === "done" ? "Videos imported successfully" : "There are no Mux videos to import" }),
619
+ /* @__PURE__ */ jsx(Text, { size: 2, children: importState === "done" ? "You can now use them in your Sanity content." : "They're all in Sanity and ready to be used in your content." })
620
+ ] }),
621
+ props.missingAssets && props.missingAssets.length > 0 && (importState === "idle" || importState === "error") && /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
622
+ /* @__PURE__ */ jsxs(Heading, { size: 1, children: [
623
+ "There are ",
624
+ props.missingAssets.length,
625
+ props.muxAssets.loading && "+",
626
+ " Mux video",
627
+ props.missingAssets.length > 1 && "s",
628
+ " ",
629
+ "not in Sanity"
630
+ ] }),
631
+ !props.muxAssets.loading && /* @__PURE__ */ jsxs(Flex, { align: "center", paddingX: 2, children: [
632
+ /* @__PURE__ */ jsx(
633
+ Checkbox,
634
+ {
635
+ id: "import-all",
636
+ style: { display: "block" },
637
+ onClick: (e) => {
638
+ e.currentTarget.checked ? props.missingAssets && props.setSelectedAssets(props.missingAssets) : props.setSelectedAssets([]);
639
+ },
640
+ checked: props.selectedAssets.length === props.missingAssets.length
641
+ }
642
+ ),
643
+ /* @__PURE__ */ jsx(Box, { flex: 1, paddingLeft: 3, as: "label", htmlFor: "import-all", children: /* @__PURE__ */ jsx(Text, { children: "Import all" }) })
644
+ ] }),
645
+ props.missingAssets.map((asset) => /* @__PURE__ */ jsx(
646
+ MissingAsset,
647
+ {
648
+ asset,
649
+ selectAsset: (selected) => {
650
+ selected ? props.setSelectedAssets([...props.selectedAssets, asset]) : props.setSelectedAssets(props.selectedAssets.filter((a) => a.id !== asset.id));
651
+ },
652
+ selected: props.selectedAssets.some((a) => a.id === asset.id)
653
+ },
654
+ asset.id
655
+ ))
656
+ ] })
657
+ ] })
658
+ }
659
+ );
660
+ }
661
+ function ImportVideosFromMux() {
662
+ const importAssets = useImportMuxAssets();
663
+ if (importAssets.hasSecrets)
664
+ return importAssets.dialogOpen ? /* @__PURE__ */ jsx(ImportVideosDialog, { ...importAssets }) : /* @__PURE__ */ jsx(Button, { mode: "bleed", text: "Import from Mux", onClick: importAssets.openDialog });
665
+ }
666
+ const CONTEXT_MENU_POPOVER_PROPS = {
667
+ constrainSize: !0,
668
+ placement: "bottom",
669
+ portal: !0,
670
+ width: 0
671
+ };
672
+ function SelectSortOptions(props) {
673
+ const id = useId();
674
+ return /* @__PURE__ */ jsx(
675
+ MenuButton,
676
+ {
677
+ button: /* @__PURE__ */ jsx(Button, { text: "Sort", icon: SortIcon, mode: "bleed", padding: 3, style: { cursor: "pointer" } }),
678
+ id,
679
+ menu: /* @__PURE__ */ jsx(Menu, { children: Object.entries(ASSET_SORT_OPTIONS).map(([type2, { label }]) => /* @__PURE__ */ jsx(
680
+ MenuItem,
681
+ {
682
+ "data-as": "button",
683
+ onClick: () => props.setSort(type2),
684
+ padding: 3,
685
+ tone: "default",
686
+ text: label,
687
+ pressed: type2 === props.sort
688
+ },
689
+ type2
690
+ )) }),
691
+ popover: CONTEXT_MENU_POPOVER_PROPS
692
+ }
693
+ );
694
+ }
695
+ const SpinnerBox = () => /* @__PURE__ */ jsx(
696
+ Box,
697
+ {
698
+ style: {
699
+ display: "flex",
700
+ alignItems: "center",
701
+ justifyContent: "center",
702
+ minHeight: "150px"
703
+ },
704
+ children: /* @__PURE__ */ jsx(Spinner, {})
705
+ }
706
+ );
707
+ function FormField(props) {
708
+ const { children, title, description: description2, inputId } = props;
709
+ return /* @__PURE__ */ jsxs(Stack, { space: 1, children: [
710
+ /* @__PURE__ */ jsx(Flex, { align: "flex-end", children: /* @__PURE__ */ jsx(Box, { flex: 1, paddingY: 2, children: /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
711
+ /* @__PURE__ */ jsx(Text, { as: "label", htmlFor: inputId, weight: "semibold", size: 1, children: title || /* @__PURE__ */ jsx("em", { children: "Untitled" }) }),
712
+ description2 && /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: description2 })
713
+ ] }) }) }),
714
+ /* @__PURE__ */ jsx("div", { children })
715
+ ] });
716
+ }
717
+ var FormField$1 = memo(FormField);
718
+ const IconInfo = (props) => {
719
+ const Icon = props.icon;
720
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, align: "center", padding: 1, children: [
721
+ /* @__PURE__ */ jsx(Text, { size: (props.size || 1) + 1, muted: !0, children: /* @__PURE__ */ jsx(Icon, {}) }),
722
+ /* @__PURE__ */ jsx(Text, { size: props.size || 1, muted: props.muted, children: props.text })
723
+ ] });
724
+ };
725
+ function ResolutionIcon(props) {
726
+ return /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1em", height: "1em", viewBox: "0 0 24 24", ...props, children: /* @__PURE__ */ jsx(
727
+ "path",
728
+ {
729
+ fill: "currentColor",
730
+ d: "M20 9V6h-3V4h5v5h-2ZM2 9V4h5v2H4v3H2Zm15 11v-2h3v-3h2v5h-5ZM2 20v-5h2v3h3v2H2Zm4-4V8h12v8H6Zm2-2h8v-4H8v4Zm0 0v-4v4Z"
731
+ }
732
+ ) });
733
+ }
734
+ function StopWatchIcon(props) {
735
+ return /* @__PURE__ */ jsxs(
736
+ "svg",
737
+ {
738
+ xmlns: "http://www.w3.org/2000/svg",
739
+ width: "1em",
740
+ height: "1em",
741
+ viewBox: "0 0 512 512",
742
+ ...props,
743
+ children: [
744
+ /* @__PURE__ */ jsx("path", { d: "M232 306.667h48V176h-48v130.667z", fill: "currentColor" }),
745
+ /* @__PURE__ */ jsx(
746
+ "path",
747
+ {
748
+ d: "M407.67 170.271l30.786-30.786-33.942-33.941-30.785 30.786C341.217 111.057 300.369 96 256 96 149.961 96 64 181.961 64 288s85.961 192 192 192 192-85.961 192-192c0-44.369-15.057-85.217-40.33-117.729zm-45.604 223.795C333.734 422.398 296.066 438 256 438s-77.735-15.602-106.066-43.934C121.602 365.735 106 328.066 106 288s15.602-77.735 43.934-106.066C178.265 153.602 215.934 138 256 138s77.734 15.602 106.066 43.934C390.398 210.265 406 247.934 406 288s-15.602 77.735-43.934 106.066z",
749
+ fill: "currentColor"
750
+ }
751
+ ),
752
+ /* @__PURE__ */ jsx("path", { d: "M192 32h128v48H192z", fill: "currentColor" })
753
+ ]
754
+ }
755
+ );
756
+ }
757
+ function getVideoSrc({ asset, client }) {
758
+ const playbackId = getPlaybackId(asset), searchParams = new URLSearchParams();
759
+ if (getPlaybackPolicy(asset) === "signed") {
760
+ const token = generateJwt(client, playbackId, "v");
761
+ searchParams.set("token", token);
762
+ }
763
+ return `https://stream.mux.com/${playbackId}.m3u8?${searchParams}`;
764
+ }
765
+ var name = "sanity-plugin-mux-input", version = "2.3.0", description = "An input component that integrates Sanity Studio with Mux video encoding/hosting service.", keywords = [
766
+ "sanity",
767
+ "video",
768
+ "mux",
769
+ "input",
770
+ "plugin",
771
+ "sanity-plugin",
772
+ "media"
773
+ ], homepage = "https://github.com/sanity-io/sanity-plugin-mux-input#readme", bugs = {
774
+ url: "https://github.com/sanity-io/sanity-plugin-mux-input/issues"
775
+ }, repository = {
776
+ type: "git",
777
+ url: "git@github.com:sanity-io/sanity-plugin-mux-input.git"
778
+ }, license = "MIT", author = "Sanity.io <hello@sanity.io>", sideEffects = !1, type = "module", exports = {
779
+ ".": {
780
+ source: "./src/_exports/index.ts",
781
+ import: "./lib/index.js",
782
+ require: "./lib/index.cjs",
783
+ default: "./lib/index.js"
784
+ },
785
+ "./package.json": "./package.json"
786
+ }, main = "./lib/index.cjs", module = "./lib/index.esm.js", source = "./src/_exports/index.ts", types = "./lib/index.d.ts", files = [
787
+ "src",
788
+ "lib",
789
+ "sanity.json",
790
+ "v2-incompatible.js"
791
+ ], scripts = {
792
+ build: "run-s clean && pkg-utils build --strict && pkg-utils --strict",
793
+ clean: "rimraf lib",
794
+ dev: "plugin-kit link-watch",
795
+ format: "prettier --write --cache --ignore-unknown .",
796
+ "link-watch": "plugin-kit link-watch",
797
+ lint: "eslint .",
798
+ prepare: "husky install || true",
799
+ prepublishOnly: "run-s build",
800
+ test: "npm run lint && npm run type-check && npm run build",
801
+ "type-check": "tsc --noEmit",
802
+ watch: "pkg-utils watch --strict"
803
+ }, dependencies = {
804
+ "@mux/mux-player-react": "^2.3.3",
805
+ "@mux/upchunk": "^3.3.2",
806
+ "@sanity/icons": "^2.10.2",
807
+ "@sanity/incompatible-plugin": "^1.0.4",
808
+ "@sanity/ui": "^2.0.3",
809
+ "@sanity/uuid": "^3.0.2",
810
+ "iso-639-1": "^3.1.2",
811
+ "jsonwebtoken-esm": "^1.0.5",
812
+ lodash: "^4.17.21",
813
+ "react-rx": "^2.1.3",
814
+ rxjs: "^7.8.1",
815
+ "scroll-into-view-if-needed": "^3.1.0",
816
+ "suspend-react": "^0.1.3",
817
+ swr: "^2.2.5",
818
+ "type-fest": "^4.10.2",
819
+ "use-error-boundary": "^2.0.6"
820
+ }, devDependencies = {
821
+ "@commitlint/cli": "^18.6.1",
822
+ "@commitlint/config-conventional": "^18.6.2",
823
+ "@sanity/client": "^6.14.0",
824
+ "@sanity/pkg-utils": "^5.1.12",
825
+ "@sanity/plugin-kit": "^3.1.10",
826
+ "@sanity/semantic-release-preset": "^4.1.7",
827
+ "@sanity/vision": "^3.30.0",
828
+ "@types/lodash": "^4.14.202",
829
+ "@types/react": "^18.2.57",
830
+ "@types/react-is": "^18.2.4",
831
+ "@typescript-eslint/eslint-plugin": "^7.5.0",
832
+ "@typescript-eslint/parser": "^7.5.0",
833
+ "cz-conventional-changelog": "^3.3.0",
834
+ eslint: "^8.56.0",
835
+ "eslint-config-prettier": "^9.1.0",
836
+ "eslint-config-sanity": "^7.1.2",
837
+ "eslint-plugin-import": "^2.29.1",
838
+ "eslint-plugin-prettier": "^5.1.3",
839
+ "eslint-plugin-react-hooks": "^4.6.0",
840
+ "eslint-plugin-simple-import-sort": "^12.0.0",
841
+ husky: "^9.0.11",
842
+ "lint-staged": "^15.2.2",
843
+ "npm-run-all": "^4.1.5",
844
+ prettier: "^3.2.5",
845
+ "prettier-plugin-packagejson": "^2.4.11",
846
+ react: "^18.2.0",
847
+ "react-dom": "^18.2.0",
848
+ "react-is": "^18.2.0",
849
+ rimraf: "^5.0.5",
850
+ sanity: "^3.30.0",
851
+ "semantic-release": "^23.0.7",
852
+ "styled-components": "^6.1.8",
853
+ typescript: "5.4.2",
854
+ yalc: "1.0.0-pre.53"
855
+ }, peerDependencies = {
856
+ react: "^18",
857
+ "react-is": "^18",
858
+ sanity: "^3",
859
+ "styled-components": "^6"
860
+ }, engines = {
861
+ node: ">=14"
862
+ }, publishConfig = {
863
+ access: "public",
864
+ provenance: !0
865
+ }, sanityExchangeUrl = "https://www.sanity.io/plugins/sanity-plugin-mux-input", pluginPkg = {
866
+ name,
867
+ version,
868
+ description,
869
+ keywords,
870
+ homepage,
871
+ bugs,
872
+ repository,
873
+ license,
874
+ author,
875
+ sideEffects,
876
+ type,
877
+ exports,
878
+ main,
879
+ module,
880
+ source,
881
+ types,
882
+ files,
883
+ scripts,
884
+ dependencies,
885
+ devDependencies,
886
+ peerDependencies,
887
+ engines,
888
+ publishConfig,
889
+ sanityExchangeUrl
890
+ };
891
+ function VideoPlayer({
892
+ asset,
893
+ children,
894
+ ...props
895
+ }) {
896
+ var _a, _b;
897
+ const client = useClient(), { src: videoSrc, error } = useMemo(() => {
898
+ try {
899
+ const src = (asset == null ? void 0 : asset.playbackId) && getVideoSrc({ client, asset });
900
+ return src ? { src } : { error: new TypeError("Asset has no playback ID") };
901
+ } catch (error2) {
902
+ return { error: error2 };
903
+ }
904
+ }, [asset, client]), signedToken = useMemo(() => {
905
+ try {
906
+ return new URL(videoSrc).searchParams.get("token");
907
+ } catch {
908
+ return !1;
909
+ }
910
+ }, [videoSrc]), [width, height] = ((_b = (_a = asset == null ? void 0 : asset.data) == null ? void 0 : _a.aspect_ratio) != null ? _b : "16:9").split(":").map(Number), targetAspectRatio = props.forceAspectRatio || (Number.isNaN(width) ? 16 / 9 : width / height), aspectRatio = Math.max(MIN_ASPECT_RATIO, targetAspectRatio);
911
+ return /* @__PURE__ */ jsxs(Card, { tone: "transparent", style: { aspectRatio, position: "relative" }, children: [
912
+ videoSrc && /* @__PURE__ */ jsxs(Fragment, { children: [
913
+ /* @__PURE__ */ jsx(
914
+ MuxPlayer,
915
+ {
916
+ ...props,
917
+ playsInline: !0,
918
+ playbackId: asset.playbackId,
919
+ tokens: signedToken ? { playback: signedToken, thumbnail: signedToken, storyboard: signedToken } : void 0,
920
+ preload: "metadata",
921
+ crossOrigin: "anonymous",
922
+ metadata: {
923
+ player_name: "Sanity Admin Dashboard",
924
+ player_version: pluginPkg.version,
925
+ page_type: "Preview Player"
926
+ },
927
+ style: {
928
+ height: "100%",
929
+ width: "100%",
930
+ display: "block",
931
+ objectFit: "contain"
932
+ }
933
+ }
934
+ ),
935
+ children
936
+ ] }),
937
+ error ? /* @__PURE__ */ jsx(
938
+ "div",
939
+ {
940
+ style: {
941
+ position: "absolute",
942
+ top: "50%",
943
+ left: "50%",
944
+ transform: "translate(-50%, -50%)"
945
+ },
946
+ children: /* @__PURE__ */ jsxs(Text, { muted: !0, children: [
947
+ /* @__PURE__ */ jsx(ErrorOutlineIcon, { style: { marginRight: "0.15em" } }),
948
+ typeof error == "object" && "message" in error && typeof error.message == "string" ? error.message : "Error loading video"
949
+ ] })
950
+ }
951
+ ) : null,
952
+ children
953
+ ] });
954
+ }
955
+ function deleteAssetOnMux(client, assetId) {
956
+ const { dataset } = client.config();
957
+ return client.request({
958
+ url: `/addons/mux/assets/${dataset}/${assetId}`,
959
+ withCredentials: !0,
960
+ method: "DELETE"
961
+ });
962
+ }
963
+ async function deleteAsset({
964
+ client,
965
+ asset,
966
+ deleteOnMux
967
+ }) {
968
+ if (!(asset != null && asset._id))
969
+ return !0;
970
+ try {
971
+ await client.delete(asset._id);
972
+ } catch {
973
+ return "failed-sanity";
974
+ }
975
+ if (deleteOnMux && asset != null && asset.assetId)
976
+ try {
977
+ await deleteAssetOnMux(client, asset.assetId);
978
+ } catch {
979
+ return "failed-mux";
980
+ }
981
+ return !0;
982
+ }
983
+ function getAsset(client, assetId) {
984
+ const { dataset } = client.config();
985
+ return client.request({
986
+ url: `/addons/mux/assets/${dataset}/data/${assetId}`,
987
+ withCredentials: !0,
988
+ method: "GET"
989
+ });
990
+ }
991
+ const getUnknownTypeFallback = (id, typeName) => ({
992
+ title: /* @__PURE__ */ jsxs("em", { children: [
993
+ "No schema found for type ",
994
+ /* @__PURE__ */ jsx("code", { children: typeName })
995
+ ] }),
996
+ subtitle: /* @__PURE__ */ jsxs("em", { children: [
997
+ "Document: ",
998
+ /* @__PURE__ */ jsx("code", { children: id })
999
+ ] }),
1000
+ media: () => /* @__PURE__ */ jsx(WarningOutlineIcon, {})
1001
+ });
1002
+ function MissingSchemaType(props) {
1003
+ const { layout, value } = props;
1004
+ return /* @__PURE__ */ jsx(SanityDefaultPreview, { ...getUnknownTypeFallback(value._id, value._type), layout });
1005
+ }
1006
+ function TimeAgo({ time }) {
1007
+ const timeAgo = useTimeAgo(time);
1008
+ return /* @__PURE__ */ jsxs("span", { title: timeAgo, children: [
1009
+ timeAgo,
1010
+ " ago"
1011
+ ] });
1012
+ }
1013
+ function DraftStatus(props) {
1014
+ const { document: document2 } = props, updatedAt = document2 && "_updatedAt" in document2 && document2._updatedAt;
1015
+ return /* @__PURE__ */ jsx(
1016
+ Tooltip,
1017
+ {
1018
+ portal: !0,
1019
+ content: /* @__PURE__ */ jsx(Box, { padding: 2, children: /* @__PURE__ */ jsx(Text, { size: 1, children: document2 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1020
+ "Edited ",
1021
+ updatedAt && /* @__PURE__ */ jsx(TimeAgo, { time: updatedAt })
1022
+ ] }) : /* @__PURE__ */ jsx(Fragment, { children: "No unpublished edits" }) }) }),
1023
+ children: /* @__PURE__ */ jsx(TextWithTone, { tone: "caution", dimmed: !document2, muted: !document2, size: 1, children: /* @__PURE__ */ jsx(EditIcon, {}) })
1024
+ }
1025
+ );
1026
+ }
1027
+ function PublishedStatus(props) {
1028
+ const { document: document2 } = props, updatedAt = document2 && "_updatedAt" in document2 && document2._updatedAt;
1029
+ return /* @__PURE__ */ jsx(
1030
+ Tooltip,
1031
+ {
1032
+ portal: !0,
1033
+ content: /* @__PURE__ */ jsx(Box, { padding: 2, children: /* @__PURE__ */ jsx(Text, { size: 1, children: document2 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1034
+ "Published ",
1035
+ updatedAt && /* @__PURE__ */ jsx(TimeAgo, { time: updatedAt })
1036
+ ] }) : /* @__PURE__ */ jsx(Fragment, { children: "Not published" }) }) }),
1037
+ children: /* @__PURE__ */ jsx(TextWithTone, { tone: "positive", dimmed: !document2, muted: !document2, size: 1, children: /* @__PURE__ */ jsx(PublishIcon, {}) })
1038
+ }
1039
+ );
1040
+ }
1041
+ function PaneItemPreview(props) {
1042
+ const { icon, layout, presence, schemaType, value } = props, title = isRecord(value.title) && isValidElement(value.title) || isString(value.title) || isNumber(value.title) ? value.title : null, { draft, published, isLoading } = useMemoObservable(
1043
+ () => getPreviewStateObservable(props.documentPreviewStore, schemaType, value._id, title),
1044
+ [props.documentPreviewStore, schemaType, value._id, title]
1045
+ ), status = isLoading ? null : /* @__PURE__ */ jsxs(Inline, { space: 4, children: [
1046
+ presence && presence.length > 0 && /* @__PURE__ */ jsx(DocumentPreviewPresence, { presence }),
1047
+ /* @__PURE__ */ jsx(PublishedStatus, { document: published }),
1048
+ /* @__PURE__ */ jsx(DraftStatus, { document: draft })
1049
+ ] });
1050
+ return /* @__PURE__ */ jsx(
1051
+ SanityDefaultPreview,
1052
+ {
1053
+ ...getPreviewValueWithFallback({ value, draft, published }),
1054
+ isPlaceholder: isLoading,
1055
+ icon,
1056
+ layout,
1057
+ status
1058
+ }
1059
+ );
1060
+ }
1061
+ function getIconWithFallback(icon, schemaType, defaultIcon) {
1062
+ return icon === !1 ? !1 : icon || schemaType && schemaType.icon || defaultIcon || !1;
1063
+ }
1064
+ function DocumentPreviewInInput(props) {
1065
+ const { ChildLink } = usePaneRouter();
1066
+ return (linkProps) => /* @__PURE__ */ jsx(
1067
+ ChildLink,
1068
+ {
1069
+ childId: props.documentPair.id,
1070
+ childParameters: { type: props.documentPair.type },
1071
+ children: linkProps.children
1072
+ }
1073
+ );
1074
+ }
1075
+ function DocumentPreviewInRool(props) {
1076
+ return (linkProps) => /* @__PURE__ */ jsx(IntentLink, { intent: "edit", params: { id: props.documentPair.id }, children: linkProps.children });
1077
+ }
1078
+ function DocumentPreview(props) {
1079
+ const { schemaType, documentPair } = props, doc = (documentPair == null ? void 0 : documentPair.draft) || (documentPair == null ? void 0 : documentPair.published), id = documentPair.id || "", documentPreviewStore = useDocumentPreviewStore(), schema = useSchema(), documentPresence = useDocumentPresence(id), hasSchemaType = !!(schemaType && schemaType.name && schema.get(schemaType.name)), PreviewComponent = useMemo(() => doc ? !schemaType || !hasSchemaType ? /* @__PURE__ */ jsx(MissingSchemaType, { value: doc }) : /* @__PURE__ */ jsx(
1080
+ PaneItemPreview,
1081
+ {
1082
+ documentPreviewStore,
1083
+ icon: getIconWithFallback(void 0, schemaType, DocumentIcon),
1084
+ schemaType,
1085
+ layout: "default",
1086
+ value: doc,
1087
+ presence: documentPresence
1088
+ }
1089
+ ) : null, [hasSchemaType, schemaType, documentPresence, doc, documentPreviewStore]);
1090
+ return /* @__PURE__ */ jsx(
1091
+ PreviewCard,
1092
+ {
1093
+ __unstable_focusRing: !0,
1094
+ as: props.placement === "input" ? DocumentPreviewInInput(props) : DocumentPreviewInRool(props),
1095
+ "data-as": "a",
1096
+ "data-ui": "PaneItem",
1097
+ padding: 2,
1098
+ radius: 2,
1099
+ tone: "inherit",
1100
+ children: PreviewComponent
1101
+ }
1102
+ );
1103
+ }
1104
+ const Container = styled(Box)`
1105
+ * {
1106
+ color: ${(props) => props.theme.sanity.color.base.fg};
1107
+ }
1108
+ a {
1109
+ text-decoration: none;
1110
+ }
1111
+ h2 {
1112
+ font-size: ${(props) => props.theme.sanity.fonts.text.sizes[1]};
1113
+ }
1114
+ `, VideoReferences = (props) => {
1115
+ var _a;
1116
+ const schema = useSchema();
1117
+ if (!props.isLoaded)
1118
+ return /* @__PURE__ */ jsx(SpinnerBox, {});
1119
+ if (!((_a = props.references) != null && _a.length))
1120
+ return /* @__PURE__ */ jsx(Card, { border: !0, radius: 3, padding: 3, children: /* @__PURE__ */ jsx(Text, { size: 2, children: "No documents are using this video" }) });
1121
+ const documentPairs = collate(props.references || []);
1122
+ return /* @__PURE__ */ jsx(Container, { children: documentPairs == null ? void 0 : documentPairs.map((documentPair) => {
1123
+ const schemaType = schema.get(documentPair.type);
1124
+ return /* @__PURE__ */ jsx(
1125
+ Card,
1126
+ {
1127
+ marginBottom: 2,
1128
+ padding: 2,
1129
+ radius: 2,
1130
+ shadow: 1,
1131
+ style: { overflow: "hidden" },
1132
+ children: /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
1133
+ DocumentPreview,
1134
+ {
1135
+ documentPair,
1136
+ schemaType,
1137
+ placement: props.placement
1138
+ }
1139
+ ) })
1140
+ },
1141
+ documentPair.id
1142
+ );
1143
+ }) });
1144
+ };
1145
+ function DeleteDialog({
1146
+ asset,
1147
+ references,
1148
+ referencesLoading,
1149
+ cancelDelete,
1150
+ placement,
1151
+ succeededDeleting
1152
+ }) {
1153
+ const client = useClient(), [state, setState] = useState("checkingReferences"), [deleteOnMux, setDeleteOnMux] = useState(!0), toast = useToast();
1154
+ useEffect(() => {
1155
+ state !== "checkingReferences" || referencesLoading || setState(references != null && references.length ? "cantDelete" : "confirm");
1156
+ }, [state, references, referencesLoading]);
1157
+ async function confirmDelete() {
1158
+ if (state !== "confirm")
1159
+ return;
1160
+ setState("processing_deletion");
1161
+ const worked = await deleteAsset({ client, asset, deleteOnMux });
1162
+ worked === !0 ? (toast.push({ title: "Successfully deleted video", status: "success" }), succeededDeleting()) : worked === "failed-mux" ? (toast.push({
1163
+ title: "Deleted video in Sanity",
1164
+ description: "But it wasn't deleted in Mux",
1165
+ status: "warning"
1166
+ }), succeededDeleting()) : (toast.push({ title: "Failed deleting video", status: "error" }), setState("error_deleting"));
1167
+ }
1168
+ return /* @__PURE__ */ jsx(
1169
+ Dialog,
1170
+ {
1171
+ header: "Delete video",
1172
+ zOffset: DIALOGS_Z_INDEX,
1173
+ id: "deleting-video-details-dialog",
1174
+ onClose: cancelDelete,
1175
+ onClickOutside: cancelDelete,
1176
+ width: 1,
1177
+ position: "fixed",
1178
+ children: /* @__PURE__ */ jsx(
1179
+ Card,
1180
+ {
1181
+ padding: 3,
1182
+ style: {
1183
+ minHeight: "150px",
1184
+ display: "flex",
1185
+ alignItems: "center",
1186
+ justifyContent: "center"
1187
+ },
1188
+ children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
1189
+ state === "checkingReferences" && /* @__PURE__ */ jsxs(Fragment, { children: [
1190
+ /* @__PURE__ */ jsx(Heading, { size: 2, children: "Checking if video can be deleted" }),
1191
+ /* @__PURE__ */ jsx(SpinnerBox, {})
1192
+ ] }),
1193
+ state === "cantDelete" && /* @__PURE__ */ jsxs(Fragment, { children: [
1194
+ /* @__PURE__ */ jsx(Heading, { size: 2, children: "Video can't be deleted" }),
1195
+ /* @__PURE__ */ jsxs(Text, { size: 2, style: { marginBottom: "2rem" }, children: [
1196
+ "There are ",
1197
+ references == null ? void 0 : references.length,
1198
+ " document",
1199
+ references && references.length > 0 && "s",
1200
+ " ",
1201
+ "pointing to this video. Remove their references to this file or delete them before proceeding."
1202
+ ] }),
1203
+ /* @__PURE__ */ jsx(
1204
+ VideoReferences,
1205
+ {
1206
+ references,
1207
+ isLoaded: !referencesLoading,
1208
+ placement
1209
+ }
1210
+ )
1211
+ ] }),
1212
+ state === "confirm" && /* @__PURE__ */ jsxs(Fragment, { children: [
1213
+ /* @__PURE__ */ jsx(Heading, { size: 2, children: "Are you sure you want to delete this video?" }),
1214
+ /* @__PURE__ */ jsx(Text, { size: 2, children: "This action is irreversible" }),
1215
+ /* @__PURE__ */ jsxs(Stack, { space: 4, marginY: 4, children: [
1216
+ /* @__PURE__ */ jsxs(Flex, { align: "center", as: "label", children: [
1217
+ /* @__PURE__ */ jsx(
1218
+ Checkbox,
1219
+ {
1220
+ checked: deleteOnMux,
1221
+ onChange: () => setDeleteOnMux((prev) => !prev)
1222
+ }
1223
+ ),
1224
+ /* @__PURE__ */ jsx(Text, { style: { margin: "0 10px" }, children: "Delete asset on Mux" })
1225
+ ] }),
1226
+ /* @__PURE__ */ jsxs(Flex, { align: "center", as: "label", children: [
1227
+ /* @__PURE__ */ jsx(Checkbox, { disabled: !0, checked: !0 }),
1228
+ /* @__PURE__ */ jsx(Text, { style: { margin: "0 10px" }, children: "Delete video from dataset" })
1229
+ ] }),
1230
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
1231
+ Button,
1232
+ {
1233
+ icon: TrashIcon,
1234
+ fontSize: 2,
1235
+ padding: 3,
1236
+ text: "Delete video",
1237
+ tone: "critical",
1238
+ onClick: confirmDelete,
1239
+ disabled: ["processing_deletion", "checkingReferences", "cantDelete"].some(
1240
+ (s) => s === state
1241
+ )
1242
+ }
1243
+ ) })
1244
+ ] })
1245
+ ] }),
1246
+ state === "processing_deletion" && /* @__PURE__ */ jsxs(Fragment, { children: [
1247
+ /* @__PURE__ */ jsx(Heading, { size: 2, children: "Deleting video..." }),
1248
+ /* @__PURE__ */ jsx(SpinnerBox, {})
1249
+ ] }),
1250
+ state === "error_deleting" && /* @__PURE__ */ jsxs(Fragment, { children: [
1251
+ /* @__PURE__ */ jsx(Heading, { size: 2, children: "Something went wrong!" }),
1252
+ /* @__PURE__ */ jsx(Text, { size: 2, children: "Try deleting the video again by clicking the button below" })
1253
+ ] })
1254
+ ] })
1255
+ }
1256
+ )
1257
+ }
1258
+ );
1259
+ }
1260
+ const useDocReferences = createHookFromObservableFactory(({ documentStore, id }) => documentStore.listenQuery(
1261
+ /* groq */
1262
+ "*[references($id)]{_id, _type, _rev, _updatedAt, _createdAt}",
1263
+ { id },
1264
+ {
1265
+ apiVersion: SANITY_API_VERSION
1266
+ }
1267
+ ));
1268
+ function formatSeconds(seconds) {
1269
+ if (typeof seconds != "number" || Number.isNaN(seconds))
1270
+ return "";
1271
+ const hrs = ~~(seconds / 3600), mins = ~~(seconds % 3600 / 60), secs = ~~seconds % 60;
1272
+ let ret = "";
1273
+ return hrs > 0 && (ret += "" + hrs + ":" + (mins < 10 ? "0" : "")), ret += "" + mins + ":" + (secs < 10 ? "0" : ""), ret += "" + secs, ret;
1274
+ }
1275
+ function getVideoMetadata(doc) {
1276
+ var _a, _b, _c, _d, _e, _f;
1277
+ const id = doc.assetId || doc._id || "", date = (_a = doc.data) != null && _a.created_at ? new Date(Number(doc.data.created_at) * 1e3) : new Date(doc._createdAt || doc._updatedAt || Date.now());
1278
+ return {
1279
+ title: doc.filename || id.slice(0, 12),
1280
+ id,
1281
+ createdAt: date,
1282
+ duration: (_b = doc.data) != null && _b.duration ? formatSeconds((_c = doc.data) == null ? void 0 : _c.duration) : void 0,
1283
+ aspect_ratio: (_d = doc.data) == null ? void 0 : _d.aspect_ratio,
1284
+ max_stored_resolution: (_e = doc.data) == null ? void 0 : _e.max_stored_resolution,
1285
+ max_stored_frame_rate: (_f = doc.data) == null ? void 0 : _f.max_stored_frame_rate
1286
+ };
1287
+ }
1288
+ function useVideoDetails(props) {
1289
+ const documentStore = useDocumentStore(), toast = useToast(), client = useClient(), [references, referencesLoading] = useDocReferences({
1290
+ documentStore,
1291
+ id: props.asset._id
1292
+ }), [originalAsset, setOriginalAsset] = useState(() => props.asset), [filename, setFilename] = useState(props.asset.filename), modified = filename !== originalAsset.filename, displayInfo = getVideoMetadata({ ...props.asset, filename }), [state, setState] = useState("idle");
1293
+ function handleClose() {
1294
+ if (state === "idle") {
1295
+ if (modified) {
1296
+ setState("closing");
1297
+ return;
1298
+ }
1299
+ props.closeDialog();
1300
+ }
1301
+ }
1302
+ function confirmClose(shouldClose) {
1303
+ state === "closing" && (shouldClose && props.closeDialog(), setState("idle"));
1304
+ }
1305
+ async function saveChanges() {
1306
+ if (state === "idle") {
1307
+ setState("saving");
1308
+ try {
1309
+ await client.patch(props.asset._id).set({ filename }).commit(), setOriginalAsset((prev) => ({ ...prev, filename })), toast.push({
1310
+ title: "Video title updated",
1311
+ description: `New title: ${filename}`,
1312
+ status: "success"
1313
+ }), props.closeDialog();
1314
+ } catch (error) {
1315
+ toast.push({
1316
+ title: "Failed updating file name",
1317
+ status: "error",
1318
+ description: typeof error == "string" ? error : "Please try again"
1319
+ }), setFilename(originalAsset.filename);
1320
+ }
1321
+ setState("idle");
1322
+ }
1323
+ }
1324
+ return {
1325
+ references,
1326
+ referencesLoading,
1327
+ modified,
1328
+ filename,
1329
+ setFilename,
1330
+ displayInfo,
1331
+ state,
1332
+ setState,
1333
+ handleClose,
1334
+ confirmClose,
1335
+ saveChanges
1336
+ };
1337
+ }
1338
+ const AssetInput = (props) => /* @__PURE__ */ jsx(FormField$1, { title: props.label, description: props.description, inputId: props.label, children: /* @__PURE__ */ jsx(
1339
+ TextInput,
1340
+ {
1341
+ id: props.label,
1342
+ value: props.value,
1343
+ placeholder: props.placeholder,
1344
+ onInput: props.onInput,
1345
+ disabled: props.disabled
1346
+ }
1347
+ ) }), VideoDetails = (props) => {
1348
+ const [tab, setTab] = useState("details"), {
1349
+ displayInfo,
1350
+ filename,
1351
+ modified,
1352
+ references,
1353
+ referencesLoading,
1354
+ setFilename,
1355
+ state,
1356
+ setState,
1357
+ handleClose,
1358
+ confirmClose,
1359
+ saveChanges
1360
+ } = useVideoDetails(props), isSaving = state === "saving", [containerHeight, setContainerHeight] = useState(null), contentsRef = React.useRef(null);
1361
+ return useEffect(() => {
1362
+ !contentsRef.current || !("getBoundingClientRect" in contentsRef.current) || setContainerHeight(contentsRef.current.getBoundingClientRect().height);
1363
+ }, []), /* @__PURE__ */ jsxs(
1364
+ Dialog,
1365
+ {
1366
+ header: displayInfo.title,
1367
+ zOffset: DIALOGS_Z_INDEX,
1368
+ id: "video-details-dialog",
1369
+ onClose: handleClose,
1370
+ onClickOutside: handleClose,
1371
+ width: 2,
1372
+ position: "fixed",
1373
+ footer: /* @__PURE__ */ jsx(Card, { padding: 3, children: /* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
1374
+ /* @__PURE__ */ jsx(
1375
+ Button,
1376
+ {
1377
+ icon: TrashIcon,
1378
+ fontSize: 2,
1379
+ padding: 3,
1380
+ mode: "bleed",
1381
+ text: "Delete",
1382
+ tone: "critical",
1383
+ onClick: () => setState("deleting"),
1384
+ disabled: isSaving
1385
+ }
1386
+ ),
1387
+ modified && /* @__PURE__ */ jsx(
1388
+ Button,
1389
+ {
1390
+ icon: CheckmarkIcon,
1391
+ fontSize: 2,
1392
+ padding: 3,
1393
+ mode: "ghost",
1394
+ text: "Save and close",
1395
+ tone: "positive",
1396
+ onClick: saveChanges,
1397
+ iconRight: isSaving && Spinner,
1398
+ disabled: isSaving
1399
+ }
1400
+ )
1401
+ ] }) }),
1402
+ children: [
1403
+ state === "deleting" && /* @__PURE__ */ jsx(
1404
+ DeleteDialog,
1405
+ {
1406
+ asset: props.asset,
1407
+ cancelDelete: () => setState("idle"),
1408
+ placement: props.placement,
1409
+ referencesLoading,
1410
+ references,
1411
+ succeededDeleting: () => {
1412
+ props.closeDialog();
1413
+ }
1414
+ }
1415
+ ),
1416
+ state === "closing" && /* @__PURE__ */ jsx(
1417
+ Dialog,
1418
+ {
1419
+ header: "You have unsaved changes",
1420
+ zOffset: DIALOGS_Z_INDEX,
1421
+ id: "closing-video-details-dialog",
1422
+ onClose: () => confirmClose(!1),
1423
+ onClickOutside: () => confirmClose(!1),
1424
+ width: 1,
1425
+ position: "fixed",
1426
+ footer: /* @__PURE__ */ jsx(Card, { padding: 3, children: /* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
1427
+ /* @__PURE__ */ jsx(
1428
+ Button,
1429
+ {
1430
+ icon: ErrorOutlineIcon,
1431
+ fontSize: 2,
1432
+ padding: 3,
1433
+ text: "Discard changes",
1434
+ tone: "critical",
1435
+ onClick: () => confirmClose(!0)
1436
+ }
1437
+ ),
1438
+ modified && /* @__PURE__ */ jsx(
1439
+ Button,
1440
+ {
1441
+ icon: RevertIcon,
1442
+ fontSize: 2,
1443
+ padding: 3,
1444
+ mode: "ghost",
1445
+ text: "Keep editing",
1446
+ tone: "primary",
1447
+ onClick: () => confirmClose(!1)
1448
+ }
1449
+ )
1450
+ ] }) }),
1451
+ children: /* @__PURE__ */ jsx(Card, { padding: 5, children: /* @__PURE__ */ jsxs(Stack, { style: { textAlign: "center" }, space: 3, children: [
1452
+ /* @__PURE__ */ jsx(Heading, { size: 2, children: "Unsaved changes will be lost" }),
1453
+ /* @__PURE__ */ jsx(Text, { size: 2, children: "Are you sure you want to discard them?" })
1454
+ ] }) })
1455
+ }
1456
+ ),
1457
+ /* @__PURE__ */ jsx(
1458
+ Card,
1459
+ {
1460
+ padding: 4,
1461
+ sizing: "border",
1462
+ style: {
1463
+ containerType: "inline-size"
1464
+ },
1465
+ children: /* @__PURE__ */ jsxs(
1466
+ Flex,
1467
+ {
1468
+ sizing: "border",
1469
+ gap: 4,
1470
+ direction: ["column", "column", "row"],
1471
+ align: "flex-start",
1472
+ ref: contentsRef,
1473
+ style: typeof containerHeight == "number" ? {
1474
+ minHeight: containerHeight
1475
+ } : void 0,
1476
+ children: [
1477
+ /* @__PURE__ */ jsx(Stack, { space: 4, flex: 1, sizing: "border", children: /* @__PURE__ */ jsx(VideoPlayer, { asset: props.asset, autoPlay: props.asset.autoPlay || !1 }) }),
1478
+ /* @__PURE__ */ jsxs(Stack, { space: 4, flex: 1, sizing: "border", children: [
1479
+ /* @__PURE__ */ jsxs(TabList, { space: 2, children: [
1480
+ /* @__PURE__ */ jsx(
1481
+ Tab,
1482
+ {
1483
+ "aria-controls": "details-panel",
1484
+ icon: EditIcon,
1485
+ id: "details-tab",
1486
+ label: "Details",
1487
+ onClick: () => setTab("details"),
1488
+ selected: tab === "details"
1489
+ }
1490
+ ),
1491
+ /* @__PURE__ */ jsx(
1492
+ Tab,
1493
+ {
1494
+ "aria-controls": "references-panel",
1495
+ icon: SearchIcon,
1496
+ id: "references-tab",
1497
+ label: `Used by ${references ? `(${references.length})` : ""}`,
1498
+ onClick: () => setTab("references"),
1499
+ selected: tab === "references"
1500
+ }
1501
+ )
1502
+ ] }),
1503
+ /* @__PURE__ */ jsx(
1504
+ TabPanel,
1505
+ {
1506
+ "aria-labelledby": "details-tab",
1507
+ id: "details-panel",
1508
+ hidden: tab !== "details",
1509
+ style: { wordBreak: "break-word" },
1510
+ children: /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
1511
+ /* @__PURE__ */ jsx(
1512
+ AssetInput,
1513
+ {
1514
+ label: "Video title or file name",
1515
+ description: "Not visible to users. Useful for finding videos later.",
1516
+ value: filename || "",
1517
+ onInput: (e) => setFilename(e.currentTarget.value),
1518
+ disabled: state !== "idle"
1519
+ }
1520
+ ),
1521
+ /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
1522
+ (displayInfo == null ? void 0 : displayInfo.duration) && /* @__PURE__ */ jsx(
1523
+ IconInfo,
1524
+ {
1525
+ text: `Duration: ${displayInfo.duration}`,
1526
+ icon: ClockIcon,
1527
+ size: 2
1528
+ }
1529
+ ),
1530
+ (displayInfo == null ? void 0 : displayInfo.max_stored_resolution) && /* @__PURE__ */ jsx(
1531
+ IconInfo,
1532
+ {
1533
+ text: `Max Resolution: ${displayInfo.max_stored_resolution}`,
1534
+ icon: ResolutionIcon,
1535
+ size: 2
1536
+ }
1537
+ ),
1538
+ (displayInfo == null ? void 0 : displayInfo.max_stored_frame_rate) && /* @__PURE__ */ jsx(
1539
+ IconInfo,
1540
+ {
1541
+ text: `Frame rate: ${displayInfo.max_stored_frame_rate}`,
1542
+ icon: StopWatchIcon,
1543
+ size: 2
1544
+ }
1545
+ ),
1546
+ (displayInfo == null ? void 0 : displayInfo.aspect_ratio) && /* @__PURE__ */ jsx(
1547
+ IconInfo,
1548
+ {
1549
+ text: `Aspect Ratio: ${displayInfo.aspect_ratio}`,
1550
+ icon: CropIcon,
1551
+ size: 2
1552
+ }
1553
+ ),
1554
+ /* @__PURE__ */ jsx(
1555
+ IconInfo,
1556
+ {
1557
+ text: `Uploaded on: ${displayInfo.createdAt.toLocaleDateString("en", {
1558
+ year: "numeric",
1559
+ month: "2-digit",
1560
+ day: "2-digit",
1561
+ hour: "2-digit",
1562
+ minute: "2-digit",
1563
+ hour12: !0
1564
+ })}`,
1565
+ icon: CalendarIcon,
1566
+ size: 2
1567
+ }
1568
+ ),
1569
+ /* @__PURE__ */ jsx(IconInfo, { text: `Mux ID:
1570
+ ${displayInfo.id}`, icon: TagIcon, size: 2 })
1571
+ ] })
1572
+ ] })
1573
+ }
1574
+ ),
1575
+ /* @__PURE__ */ jsx(
1576
+ TabPanel,
1577
+ {
1578
+ "aria-labelledby": "references-tab",
1579
+ id: "references-panel",
1580
+ hidden: tab !== "references",
1581
+ children: /* @__PURE__ */ jsx(
1582
+ VideoReferences,
1583
+ {
1584
+ references,
1585
+ isLoaded: !referencesLoading,
1586
+ placement: props.placement
1587
+ }
1588
+ )
1589
+ }
1590
+ )
1591
+ ] })
1592
+ ]
1593
+ }
1594
+ )
1595
+ }
1596
+ )
1597
+ ]
1598
+ }
1599
+ );
1600
+ }, VideoMetadata = (props) => {
1601
+ if (!props.asset)
1602
+ return null;
1603
+ const displayInfo = getVideoMetadata(props.asset);
1604
+ return /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
1605
+ displayInfo.title && /* @__PURE__ */ jsx(
1606
+ Text,
1607
+ {
1608
+ size: 1,
1609
+ weight: "semibold",
1610
+ style: {
1611
+ wordWrap: "break-word"
1612
+ },
1613
+ children: displayInfo.title
1614
+ }
1615
+ ),
1616
+ /* @__PURE__ */ jsxs(Inline, { space: 3, children: [
1617
+ (displayInfo == null ? void 0 : displayInfo.duration) && /* @__PURE__ */ jsx(IconInfo, { text: displayInfo.duration, icon: ClockIcon, size: 1, muted: !0 }),
1618
+ /* @__PURE__ */ jsx(
1619
+ IconInfo,
1620
+ {
1621
+ text: displayInfo.createdAt.toISOString().split("T")[0],
1622
+ icon: CalendarIcon,
1623
+ size: 1,
1624
+ muted: !0
1625
+ }
1626
+ ),
1627
+ displayInfo.title != displayInfo.id.slice(0, 12) && /* @__PURE__ */ jsx(IconInfo, { text: displayInfo.id.slice(0, 12), icon: TagIcon, size: 1, muted: !0 })
1628
+ ] })
1629
+ ] });
1630
+ }, PlayButton = styled.button`
1631
+ display: block;
1632
+ padding: 0;
1633
+ margin: 0;
1634
+ border: none;
1635
+ border-radius: 0.1875rem;
1636
+ position: relative;
1637
+ cursor: pointer;
1638
+
1639
+ &::after {
1640
+ content: '';
1641
+ background: var(--card-fg-color);
1642
+ opacity: 0;
1643
+ display: block;
1644
+ position: absolute;
1645
+ inset: 0;
1646
+ z-index: 10;
1647
+ transition: 0.15s ease-out;
1648
+ border-radius: inherit;
1649
+ }
1650
+
1651
+ > div[data-play] {
1652
+ z-index: 11;
1653
+ opacity: 0;
1654
+ transition: 0.15s 0.05s ease-out;
1655
+ position: absolute;
1656
+ left: 50%;
1657
+ top: 50%;
1658
+ transform: translate(-50%, -50%);
1659
+ color: var(--card-fg-color);
1660
+ background: var(--card-bg-color);
1661
+ width: auto;
1662
+ height: 30%;
1663
+ aspect-ratio: 1;
1664
+ border-radius: 100%;
1665
+ display: flex;
1666
+ justify-content: center;
1667
+ align-items: center;
1668
+ box-sizing: border-box;
1669
+ > svg {
1670
+ display: block;
1671
+ width: 70%;
1672
+ height: auto;
1673
+ // Visual balance to center-align the icon
1674
+ transform: translateX(5%);
1675
+ }
1676
+ }
1677
+
1678
+ &:hover,
1679
+ &:focus {
1680
+ &::after {
1681
+ opacity: 0.3;
1682
+ }
1683
+ > div[data-play] {
1684
+ opacity: 1;
1685
+ }
1686
+ }
1687
+ `;
1688
+ function VideoInBrowser({
1689
+ onSelect,
1690
+ onEdit,
1691
+ asset
1692
+ }) {
1693
+ const [renderVideo, setRenderVideo] = useState(!1), select = React.useCallback(() => onSelect == null ? void 0 : onSelect(asset), [onSelect, asset]), edit = React.useCallback(() => onEdit == null ? void 0 : onEdit(asset), [onEdit, asset]);
1694
+ if (!asset)
1695
+ return null;
1696
+ const playbackPolicy = getPlaybackPolicy(asset);
1697
+ return /* @__PURE__ */ jsxs(
1698
+ Card,
1699
+ {
1700
+ border: !0,
1701
+ padding: 2,
1702
+ sizing: "border",
1703
+ radius: 2,
1704
+ style: {
1705
+ position: "relative"
1706
+ },
1707
+ children: [
1708
+ playbackPolicy === "signed" && /* @__PURE__ */ jsx(
1709
+ Tooltip,
1710
+ {
1711
+ content: /* @__PURE__ */ jsx(Card, { padding: 2, radius: 2, children: /* @__PURE__ */ jsx(IconInfo, { icon: LockIcon, text: "Signed playback policy", size: 2 }) }),
1712
+ placement: "right",
1713
+ fallbackPlacements: ["top", "bottom"],
1714
+ portal: !0,
1715
+ children: /* @__PURE__ */ jsx(
1716
+ Card,
1717
+ {
1718
+ tone: "caution",
1719
+ style: {
1720
+ borderRadius: "100%",
1721
+ position: "absolute",
1722
+ left: "1em",
1723
+ top: "1em",
1724
+ zIndex: 10
1725
+ },
1726
+ padding: 2,
1727
+ border: !0,
1728
+ children: /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: /* @__PURE__ */ jsx(LockIcon, {}) })
1729
+ }
1730
+ )
1731
+ }
1732
+ ),
1733
+ /* @__PURE__ */ jsxs(
1734
+ Stack,
1735
+ {
1736
+ space: 3,
1737
+ height: "fill",
1738
+ style: {
1739
+ gridTemplateRows: "min-content min-content 1fr"
1740
+ },
1741
+ children: [
1742
+ renderVideo ? /* @__PURE__ */ jsx(VideoPlayer, { asset, autoPlay: !0, forceAspectRatio: THUMBNAIL_ASPECT_RATIO }) : /* @__PURE__ */ jsxs(PlayButton, { onClick: () => setRenderVideo(!0), children: [
1743
+ /* @__PURE__ */ jsx("div", { "data-play": !0, children: /* @__PURE__ */ jsx(PlayIcon, {}) }),
1744
+ /* @__PURE__ */ jsx(VideoThumbnail, { asset })
1745
+ ] }),
1746
+ /* @__PURE__ */ jsx(VideoMetadata, { asset }),
1747
+ /* @__PURE__ */ jsxs(
1748
+ "div",
1749
+ {
1750
+ style: {
1751
+ display: "flex",
1752
+ width: "100%",
1753
+ alignItems: "flex-end",
1754
+ justifyContent: "flex-start",
1755
+ gap: ".35rem"
1756
+ },
1757
+ children: [
1758
+ onSelect && /* @__PURE__ */ jsx(
1759
+ Button,
1760
+ {
1761
+ icon: CheckmarkIcon,
1762
+ fontSize: 2,
1763
+ padding: 2,
1764
+ mode: "ghost",
1765
+ text: "Select",
1766
+ style: { flex: 1 },
1767
+ tone: "positive",
1768
+ onClick: select
1769
+ }
1770
+ ),
1771
+ /* @__PURE__ */ jsx(
1772
+ Button,
1773
+ {
1774
+ icon: EditIcon,
1775
+ fontSize: 2,
1776
+ padding: 2,
1777
+ mode: "ghost",
1778
+ text: "Details",
1779
+ style: { flex: 1 },
1780
+ onClick: edit
1781
+ }
1782
+ )
1783
+ ]
1784
+ }
1785
+ )
1786
+ ]
1787
+ }
1788
+ )
1789
+ ]
1790
+ }
1791
+ );
1792
+ }
1793
+ function VideosBrowser({ onSelect }) {
1794
+ const { assets, isLoading, searchQuery, setSearchQuery, setSort, sort } = useAssets(), [editedAsset, setEditedAsset] = React.useState(null), freshEditedAsset = React.useMemo(
1795
+ () => assets.find((a) => a._id === (editedAsset == null ? void 0 : editedAsset._id)) || editedAsset,
1796
+ [editedAsset, assets]
1797
+ ), placement = onSelect ? "input" : "tool";
1798
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1799
+ /* @__PURE__ */ jsxs(Stack, { padding: 4, space: 4, style: { minHeight: "50vh" }, children: [
1800
+ /* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
1801
+ /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 3, children: [
1802
+ /* @__PURE__ */ jsx(
1803
+ TextInput,
1804
+ {
1805
+ value: searchQuery,
1806
+ icon: SearchIcon,
1807
+ onInput: (e) => setSearchQuery(e.currentTarget.value),
1808
+ placeholder: "Search videos"
1809
+ }
1810
+ ),
1811
+ /* @__PURE__ */ jsx(SelectSortOptions, { setSort, sort })
1812
+ ] }),
1813
+ placement === "tool" && /* @__PURE__ */ jsx(ImportVideosFromMux, {})
1814
+ ] }),
1815
+ /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
1816
+ (assets == null ? void 0 : assets.length) > 0 && /* @__PURE__ */ jsxs(Label$1, { muted: !0, children: [
1817
+ assets.length,
1818
+ " video",
1819
+ assets.length > 1 ? "s" : null,
1820
+ " ",
1821
+ searchQuery ? `matching "${searchQuery}"` : "found"
1822
+ ] }),
1823
+ /* @__PURE__ */ jsx(
1824
+ Grid,
1825
+ {
1826
+ gap: 2,
1827
+ style: {
1828
+ gridTemplateColumns: "repeat(auto-fill, minmax(250px, 1fr))"
1829
+ },
1830
+ children: assets.map((asset) => /* @__PURE__ */ jsx(
1831
+ VideoInBrowser,
1832
+ {
1833
+ asset,
1834
+ onEdit: setEditedAsset,
1835
+ onSelect
1836
+ },
1837
+ asset._id
1838
+ ))
1839
+ }
1840
+ )
1841
+ ] }),
1842
+ isLoading && /* @__PURE__ */ jsx(SpinnerBox, {}),
1843
+ !isLoading && assets.length === 0 && /* @__PURE__ */ jsx(Card, { marginY: 4, paddingX: 4, paddingY: 6, border: !0, radius: 2, tone: "transparent", children: /* @__PURE__ */ jsx(Text, { align: "center", muted: !0, size: 3, children: searchQuery ? `No videos found for "${searchQuery}"` : "No videos in this dataset" }) })
1844
+ ] }),
1845
+ freshEditedAsset && /* @__PURE__ */ jsx(
1846
+ VideoDetails,
1847
+ {
1848
+ closeDialog: () => setEditedAsset(null),
1849
+ asset: freshEditedAsset,
1850
+ placement
1851
+ }
1852
+ )
1853
+ ] });
1854
+ }
1855
+ const StudioTool = () => /* @__PURE__ */ jsx(VideosBrowser, {}), DEFAULT_TOOL_CONFIG = {
1856
+ icon: ToolIcon,
1857
+ title: "Videos"
1858
+ };
1859
+ function createStudioTool(config) {
1860
+ const toolConfig = typeof config.tool == "object" ? config.tool : DEFAULT_TOOL_CONFIG;
1861
+ return {
1862
+ name: "mux",
1863
+ icon: toolConfig.icon || DEFAULT_TOOL_CONFIG.icon,
1864
+ title: toolConfig.title || DEFAULT_TOOL_CONFIG.title,
1865
+ component: (props) => /* @__PURE__ */ jsx(StudioTool, { ...config, ...props })
1866
+ };
1867
+ }
1868
+ const path = ["assetId", "data", "playbackId", "status", "thumbTime", "filename"], useAssetDocumentValues = (asset) => useDocumentValues(
1869
+ isReference(asset) ? asset._ref : "",
1870
+ path
1871
+ );
1872
+ function useDialogState() {
1873
+ return useState(!1);
1874
+ }
1875
+ const useMuxPolling = (asset) => {
1876
+ var _a, _b;
1877
+ const client = useClient(), projectId = useProjectId(), dataset = useDataset(), shouldFetch = useMemo(
1878
+ () => {
1879
+ var _a2, _b2;
1880
+ return !!(asset != null && asset.assetId) && ((asset == null ? void 0 : asset.status) === "preparing" || ((_b2 = (_a2 = asset == null ? void 0 : asset.data) == null ? void 0 : _a2.static_renditions) == null ? void 0 : _b2.status) === "preparing");
1881
+ },
1882
+ [asset == null ? void 0 : asset.assetId, (_b = (_a = asset == null ? void 0 : asset.data) == null ? void 0 : _a.static_renditions) == null ? void 0 : _b.status, asset == null ? void 0 : asset.status]
1883
+ );
1884
+ return useSWR(
1885
+ shouldFetch ? `/${projectId}/addons/mux/assets/${dataset}/data/${asset == null ? void 0 : asset.assetId}` : null,
1886
+ async () => {
1887
+ const { data } = await client.request({
1888
+ url: `/addons/mux/assets/${dataset}/data/${asset.assetId}`,
1889
+ withCredentials: !0,
1890
+ method: "GET"
1891
+ });
1892
+ client.patch(asset._id).set({ status: data.status, data }).commit({ returnDocuments: !1 });
1893
+ },
1894
+ { refreshInterval: 2e3, refreshWhenHidden: !0, dedupingInterval: 1e3 }
1895
+ );
1896
+ };
1897
+ function saveSecrets(client, token, secretKey, enableSignedUrls, signingKeyId, signingKeyPrivate) {
1898
+ const doc = {
1899
+ _id: "secrets.mux",
1900
+ _type: "mux.apiKey",
1901
+ token,
1902
+ secretKey,
1903
+ enableSignedUrls,
1904
+ signingKeyId,
1905
+ signingKeyPrivate
1906
+ };
1907
+ return client.createOrReplace(doc);
1908
+ }
1909
+ function createSigningKeys(client) {
1910
+ const { dataset } = client.config();
1911
+ return client.request({
1912
+ url: `/addons/mux/signing-keys/${dataset}`,
1913
+ withCredentials: !0,
1914
+ method: "POST"
1915
+ });
1916
+ }
1917
+ function testSecrets(client) {
1918
+ const { dataset } = client.config();
1919
+ return client.request({
1920
+ url: `/addons/mux/secrets/${dataset}/test`,
1921
+ withCredentials: !0,
1922
+ method: "GET"
1923
+ });
1924
+ }
1925
+ async function haveValidSigningKeys(client, signingKeyId, signingKeyPrivate) {
1926
+ if (!(signingKeyId && signingKeyPrivate))
1927
+ return !1;
1928
+ const { dataset } = client.config();
1929
+ try {
1930
+ const res = await client.request({
1931
+ url: `/addons/mux/signing-keys/${dataset}/${signingKeyId}`,
1932
+ withCredentials: !0,
1933
+ method: "GET"
1934
+ });
1935
+ return !!(res.data && res.data.id);
1936
+ } catch {
1937
+ return console.error("Error fetching signingKeyId", signingKeyId, "assuming it is not valid"), !1;
1938
+ }
1939
+ }
1940
+ function testSecretsObservable(client) {
1941
+ const { dataset } = client.config();
1942
+ return defer(
1943
+ () => client.observable.request({
1944
+ url: `/addons/mux/secrets/${dataset}/test`,
1945
+ withCredentials: !0,
1946
+ method: "GET"
1947
+ })
1948
+ );
1949
+ }
1950
+ const useSaveSecrets = (client, secrets) => useCallback(
1951
+ async ({
1952
+ token,
1953
+ secretKey,
1954
+ enableSignedUrls
1955
+ }) => {
1956
+ let { signingKeyId, signingKeyPrivate } = secrets;
1957
+ try {
1958
+ await saveSecrets(
1959
+ client,
1960
+ token,
1961
+ secretKey,
1962
+ enableSignedUrls,
1963
+ signingKeyId,
1964
+ signingKeyPrivate
1965
+ );
1966
+ const valid = await testSecrets(client);
1967
+ if (!(valid != null && valid.status) && token && secretKey)
1968
+ throw new Error("Invalid secrets");
1969
+ } catch (err) {
1970
+ throw console.error("Error while trying to save secrets:", err), err;
1971
+ }
1972
+ if (enableSignedUrls && !await haveValidSigningKeys(
1973
+ client,
1974
+ signingKeyId,
1975
+ signingKeyPrivate
1976
+ ))
1977
+ try {
1978
+ const { data } = await createSigningKeys(client);
1979
+ signingKeyId = data.id, signingKeyPrivate = data.private_key, await saveSecrets(
1980
+ client,
1981
+ token,
1982
+ secretKey,
1983
+ enableSignedUrls,
1984
+ signingKeyId,
1985
+ signingKeyPrivate
1986
+ );
1987
+ } catch (err) {
1988
+ throw console.log("Error while creating and saving signing key:", err == null ? void 0 : err.message), err;
1989
+ }
1990
+ return {
1991
+ token,
1992
+ secretKey,
1993
+ enableSignedUrls,
1994
+ signingKeyId,
1995
+ signingKeyPrivate
1996
+ };
1997
+ },
1998
+ [client, secrets]
1999
+ );
2000
+ function init({ token, secretKey, enableSignedUrls }) {
2001
+ return {
2002
+ submitting: !1,
2003
+ error: null,
2004
+ // Form inputs don't set the state back to null when clearing a field, but uses empty strings
2005
+ // This ensures the `dirty` check works correctly
2006
+ token: token != null ? token : "",
2007
+ secretKey: secretKey != null ? secretKey : "",
2008
+ enableSignedUrls: enableSignedUrls != null ? enableSignedUrls : !1
2009
+ };
2010
+ }
2011
+ function reducer(state, action) {
2012
+ switch (action == null ? void 0 : action.type) {
2013
+ case "submit":
2014
+ return { ...state, submitting: !0, error: null };
2015
+ case "error":
2016
+ return { ...state, submitting: !1, error: action.payload };
2017
+ case "reset":
2018
+ return init(action.payload);
2019
+ case "change":
2020
+ return { ...state, [action.payload.name]: action.payload.value };
2021
+ default:
2022
+ throw new Error(`Unknown action type: ${action == null ? void 0 : action.type}`);
2023
+ }
2024
+ }
2025
+ const useSecretsFormState = (secrets) => useReducer(reducer, secrets, init), ids = [
2026
+ "title",
2027
+ "a",
2028
+ "b",
2029
+ "c",
2030
+ "d",
2031
+ "e",
2032
+ "f",
2033
+ "g",
2034
+ "h",
2035
+ "i",
2036
+ "j",
2037
+ "k",
2038
+ "l",
2039
+ "m",
2040
+ "n",
2041
+ "o",
2042
+ "p",
2043
+ "q",
2044
+ "r"
2045
+ ];
2046
+ function MuxLogo({ height = 26 }) {
2047
+ const id = useId(), [titleId, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r] = useMemo(
2048
+ () => ids.map((field) => `${id}-${field}`),
2049
+ [id]
2050
+ );
2051
+ return /* @__PURE__ */ jsxs(
2052
+ "svg",
2053
+ {
2054
+ "aria-labelledby": titleId,
2055
+ role: "img",
2056
+ xmlns: "http://www.w3.org/2000/svg",
2057
+ xmlSpace: "preserve",
2058
+ viewBox: "92.08878326416016 102.66712188720703 692.76123046875 219.99948120117188",
2059
+ style: { height: `${height}px` },
2060
+ children: [
2061
+ /* @__PURE__ */ jsx("title", { id: titleId, children: "Mux Logo" }),
2062
+ /* @__PURE__ */ jsxs("defs", { children: [
2063
+ /* @__PURE__ */ jsxs(
2064
+ "linearGradient",
2065
+ {
2066
+ id: c,
2067
+ spreadMethod: "pad",
2068
+ gradientTransform: "matrix(528.38055 0 0 -528.38055 63.801 159.5)",
2069
+ gradientUnits: "userSpaceOnUse",
2070
+ y2: 0,
2071
+ x2: 1,
2072
+ y1: 0,
2073
+ x1: 0,
2074
+ children: [
2075
+ /* @__PURE__ */ jsx(
2076
+ "stop",
2077
+ {
2078
+ offset: 0,
2079
+ style: {
2080
+ stopOpacity: 1,
2081
+ stopColor: "#ff4e00"
2082
+ }
2083
+ }
2084
+ ),
2085
+ /* @__PURE__ */ jsx(
2086
+ "stop",
2087
+ {
2088
+ offset: 1,
2089
+ style: {
2090
+ stopOpacity: 1,
2091
+ stopColor: "#ff1791"
2092
+ }
2093
+ }
2094
+ )
2095
+ ]
2096
+ }
2097
+ ),
2098
+ /* @__PURE__ */ jsxs(
2099
+ "linearGradient",
2100
+ {
2101
+ id: d,
2102
+ spreadMethod: "pad",
2103
+ gradientTransform: "matrix(523.66766 0 0 -523.66766 67.897 159.5)",
2104
+ gradientUnits: "userSpaceOnUse",
2105
+ y2: 0,
2106
+ x2: 1,
2107
+ y1: 0,
2108
+ x1: 0,
2109
+ children: [
2110
+ /* @__PURE__ */ jsx(
2111
+ "stop",
2112
+ {
2113
+ offset: 0,
2114
+ style: {
2115
+ stopOpacity: 1,
2116
+ stopColor: "#ff4e00"
2117
+ }
2118
+ }
2119
+ ),
2120
+ /* @__PURE__ */ jsx(
2121
+ "stop",
2122
+ {
2123
+ offset: 1,
2124
+ style: {
2125
+ stopOpacity: 1,
2126
+ stopColor: "#ff1791"
2127
+ }
2128
+ }
2129
+ )
2130
+ ]
2131
+ }
2132
+ ),
2133
+ /* @__PURE__ */ jsxs(
2134
+ "linearGradient",
2135
+ {
2136
+ id: g,
2137
+ spreadMethod: "pad",
2138
+ gradientTransform: "rotate(180 296.075 79.75) scale(524.84045)",
2139
+ gradientUnits: "userSpaceOnUse",
2140
+ y2: 0,
2141
+ x2: 1,
2142
+ y1: 0,
2143
+ x1: 0,
2144
+ children: [
2145
+ /* @__PURE__ */ jsx(
2146
+ "stop",
2147
+ {
2148
+ offset: 0,
2149
+ style: {
2150
+ stopOpacity: 1,
2151
+ stopColor: "#ff4e00"
2152
+ }
2153
+ }
2154
+ ),
2155
+ /* @__PURE__ */ jsx(
2156
+ "stop",
2157
+ {
2158
+ offset: 1,
2159
+ style: {
2160
+ stopOpacity: 1,
2161
+ stopColor: "#ff1791"
2162
+ }
2163
+ }
2164
+ )
2165
+ ]
2166
+ }
2167
+ ),
2168
+ /* @__PURE__ */ jsxs(
2169
+ "linearGradient",
2170
+ {
2171
+ id: i,
2172
+ spreadMethod: "pad",
2173
+ gradientTransform: "matrix(524.84045 0 0 -524.84045 63.801 159.5)",
2174
+ gradientUnits: "userSpaceOnUse",
2175
+ y2: 0,
2176
+ x2: 1,
2177
+ y1: 0,
2178
+ x1: 0,
2179
+ children: [
2180
+ /* @__PURE__ */ jsx(
2181
+ "stop",
2182
+ {
2183
+ offset: 0,
2184
+ style: {
2185
+ stopOpacity: 1,
2186
+ stopColor: "#ff4e00"
2187
+ }
2188
+ }
2189
+ ),
2190
+ /* @__PURE__ */ jsx(
2191
+ "stop",
2192
+ {
2193
+ offset: 1,
2194
+ style: {
2195
+ stopOpacity: 1,
2196
+ stopColor: "#ff1791"
2197
+ }
2198
+ }
2199
+ )
2200
+ ]
2201
+ }
2202
+ ),
2203
+ /* @__PURE__ */ jsxs(
2204
+ "linearGradient",
2205
+ {
2206
+ id: j,
2207
+ spreadMethod: "pad",
2208
+ gradientTransform: "matrix(523.08514 0 0 -523.08514 67.897 224.446)",
2209
+ gradientUnits: "userSpaceOnUse",
2210
+ y2: 0,
2211
+ x2: 1,
2212
+ y1: 0,
2213
+ x1: 0,
2214
+ children: [
2215
+ /* @__PURE__ */ jsx(
2216
+ "stop",
2217
+ {
2218
+ offset: 0,
2219
+ style: {
2220
+ stopOpacity: 1,
2221
+ stopColor: "#ff4e00"
2222
+ }
2223
+ }
2224
+ ),
2225
+ /* @__PURE__ */ jsx(
2226
+ "stop",
2227
+ {
2228
+ offset: 1,
2229
+ style: {
2230
+ stopOpacity: 1,
2231
+ stopColor: "#ff1791"
2232
+ }
2233
+ }
2234
+ )
2235
+ ]
2236
+ }
2237
+ ),
2238
+ /* @__PURE__ */ jsxs(
2239
+ "linearGradient",
2240
+ {
2241
+ id: k,
2242
+ spreadMethod: "pad",
2243
+ gradientTransform: "matrix(524.84045 0 0 -524.84045 63.801 94.553)",
2244
+ gradientUnits: "userSpaceOnUse",
2245
+ y2: 0,
2246
+ x2: 1,
2247
+ y1: 0,
2248
+ x1: 0,
2249
+ children: [
2250
+ /* @__PURE__ */ jsx(
2251
+ "stop",
2252
+ {
2253
+ offset: 0,
2254
+ style: {
2255
+ stopOpacity: 1,
2256
+ stopColor: "#ff4e00"
2257
+ }
2258
+ }
2259
+ ),
2260
+ /* @__PURE__ */ jsx(
2261
+ "stop",
2262
+ {
2263
+ offset: 1,
2264
+ style: {
2265
+ stopOpacity: 1,
2266
+ stopColor: "#ff1791"
2267
+ }
2268
+ }
2269
+ )
2270
+ ]
2271
+ }
2272
+ ),
2273
+ /* @__PURE__ */ jsxs(
2274
+ "linearGradient",
2275
+ {
2276
+ id: l,
2277
+ spreadMethod: "pad",
2278
+ gradientTransform: "matrix(524.84045 0 0 -524.84045 63.801 159.5)",
2279
+ gradientUnits: "userSpaceOnUse",
2280
+ y2: 0,
2281
+ x2: 1,
2282
+ y1: 0,
2283
+ x1: 0,
2284
+ children: [
2285
+ /* @__PURE__ */ jsx(
2286
+ "stop",
2287
+ {
2288
+ offset: 0,
2289
+ style: {
2290
+ stopOpacity: 1,
2291
+ stopColor: "#ff4e00"
2292
+ }
2293
+ }
2294
+ ),
2295
+ /* @__PURE__ */ jsx(
2296
+ "stop",
2297
+ {
2298
+ offset: 1,
2299
+ style: {
2300
+ stopOpacity: 1,
2301
+ stopColor: "#ff1791"
2302
+ }
2303
+ }
2304
+ )
2305
+ ]
2306
+ }
2307
+ ),
2308
+ /* @__PURE__ */ jsxs(
2309
+ "linearGradient",
2310
+ {
2311
+ id: m,
2312
+ spreadMethod: "pad",
2313
+ gradientTransform: "matrix(524.84045 0 0 -524.84045 63.801 94.554)",
2314
+ gradientUnits: "userSpaceOnUse",
2315
+ y2: 0,
2316
+ x2: 1,
2317
+ y1: 0,
2318
+ x1: 0,
2319
+ children: [
2320
+ /* @__PURE__ */ jsx(
2321
+ "stop",
2322
+ {
2323
+ offset: 0,
2324
+ style: {
2325
+ stopOpacity: 1,
2326
+ stopColor: "#ff4e00"
2327
+ }
2328
+ }
2329
+ ),
2330
+ /* @__PURE__ */ jsx(
2331
+ "stop",
2332
+ {
2333
+ offset: 1,
2334
+ style: {
2335
+ stopOpacity: 1,
2336
+ stopColor: "#ff1791"
2337
+ }
2338
+ }
2339
+ )
2340
+ ]
2341
+ }
2342
+ ),
2343
+ /* @__PURE__ */ jsxs(
2344
+ "linearGradient",
2345
+ {
2346
+ id: p,
2347
+ spreadMethod: "pad",
2348
+ gradientTransform: "matrix(521.97632 0 0 -521.97632 69.067 191.973)",
2349
+ gradientUnits: "userSpaceOnUse",
2350
+ y2: 0,
2351
+ x2: 1,
2352
+ y1: 0,
2353
+ x1: 0,
2354
+ children: [
2355
+ /* @__PURE__ */ jsx(
2356
+ "stop",
2357
+ {
2358
+ offset: 0,
2359
+ style: {
2360
+ stopOpacity: 1,
2361
+ stopColor: "#ff4e00"
2362
+ }
2363
+ }
2364
+ ),
2365
+ /* @__PURE__ */ jsx(
2366
+ "stop",
2367
+ {
2368
+ offset: 1,
2369
+ style: {
2370
+ stopOpacity: 1,
2371
+ stopColor: "#ff1791"
2372
+ }
2373
+ }
2374
+ )
2375
+ ]
2376
+ }
2377
+ ),
2378
+ /* @__PURE__ */ jsxs(
2379
+ "linearGradient",
2380
+ {
2381
+ id: q,
2382
+ spreadMethod: "pad",
2383
+ gradientTransform: "matrix(523.09039 0 0 -523.09039 67.312 191.973)",
2384
+ gradientUnits: "userSpaceOnUse",
2385
+ y2: 0,
2386
+ x2: 1,
2387
+ y1: 0,
2388
+ x1: 0,
2389
+ children: [
2390
+ /* @__PURE__ */ jsx(
2391
+ "stop",
2392
+ {
2393
+ offset: 0,
2394
+ style: {
2395
+ stopOpacity: 1,
2396
+ stopColor: "#ff4e00"
2397
+ }
2398
+ }
2399
+ ),
2400
+ /* @__PURE__ */ jsx(
2401
+ "stop",
2402
+ {
2403
+ offset: 1,
2404
+ style: {
2405
+ stopOpacity: 1,
2406
+ stopColor: "#ff1791"
2407
+ }
2408
+ }
2409
+ )
2410
+ ]
2411
+ }
2412
+ ),
2413
+ /* @__PURE__ */ jsxs(
2414
+ "linearGradient",
2415
+ {
2416
+ id: r,
2417
+ spreadMethod: "pad",
2418
+ gradientTransform: "matrix(524.84045 0 0 -524.84045 63.801 159.5)",
2419
+ gradientUnits: "userSpaceOnUse",
2420
+ y2: 0,
2421
+ x2: 1,
2422
+ y1: 0,
2423
+ x1: 0,
2424
+ children: [
2425
+ /* @__PURE__ */ jsx(
2426
+ "stop",
2427
+ {
2428
+ offset: 0,
2429
+ style: {
2430
+ stopOpacity: 1,
2431
+ stopColor: "#ff4e00"
2432
+ }
2433
+ }
2434
+ ),
2435
+ /* @__PURE__ */ jsx(
2436
+ "stop",
2437
+ {
2438
+ offset: 1,
2439
+ style: {
2440
+ stopOpacity: 1,
2441
+ stopColor: "#ff1791"
2442
+ }
2443
+ }
2444
+ )
2445
+ ]
2446
+ }
2447
+ ),
2448
+ /* @__PURE__ */ jsx("clipPath", { id: a, clipPathUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx("path", { d: "M0 319h657.706V0H0Z" }) }),
2449
+ /* @__PURE__ */ jsx("clipPath", { id: b, clipPathUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx("path", { d: "M423.64 242h164.999V77H423.64Z" }) }),
2450
+ /* @__PURE__ */ jsx("clipPath", { id: e, clipPathUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx("path", { d: "M0 319h657.706V0H0Z" }) }),
2451
+ /* @__PURE__ */ jsx("clipPath", { id: f, clipPathUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx("path", { d: "M311.3 242h93.031V77H311.3Z" }) }),
2452
+ /* @__PURE__ */ jsx("clipPath", { id: h, clipPathUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx("path", { d: "M198.96 242h35.106V77H198.96Z" }) }),
2453
+ /* @__PURE__ */ jsx("clipPath", { id: n, clipPathUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx("path", { d: "M0 319h657.706V0H0Z" }) }),
2454
+ /* @__PURE__ */ jsx("clipPath", { id: o, clipPathUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx("path", { d: "M69.067 242H169.12V141.947H69.067Z" }) })
2455
+ ] }),
2456
+ /* @__PURE__ */ jsx("g", { clipPath: `url(#${a})`, transform: "matrix(1.33333 0 0 -1.33333 0 425.333)", children: /* @__PURE__ */ jsx(
2457
+ "g",
2458
+ {
2459
+ style: {
2460
+ opacity: 0.69999701
2461
+ },
2462
+ clipPath: `url(#${b})`,
2463
+ children: /* @__PURE__ */ jsx(
2464
+ "path",
2465
+ {
2466
+ style: {
2467
+ fill: `url(#${c})`,
2468
+ stroke: "none"
2469
+ },
2470
+ d: "M558.674 82.142c6.855-6.855 17.969-6.855 24.824 0 6.854 6.855 6.854 17.969 0 24.823L453.605 236.858c-6.855 6.855-17.969 6.855-24.824 0s-6.855-17.969 0-24.823z"
2471
+ }
2472
+ )
2473
+ }
2474
+ ) }),
2475
+ /* @__PURE__ */ jsx(
2476
+ "path",
2477
+ {
2478
+ style: {
2479
+ fill: `url(#${d})`,
2480
+ stroke: "none"
2481
+ },
2482
+ d: "M558.674 236.858 428.781 106.966c-6.855-6.855-6.855-17.969 0-24.825 6.855-6.854 17.969-6.854 24.823 0l129.894 129.894c6.854 6.855 6.854 17.968 0 24.823A17.498 17.498 0 0 1 571.086 242a17.495 17.495 0 0 1-12.412-5.142",
2483
+ transform: "matrix(1.33333 0 0 -1.33333 0 425.333)"
2484
+ }
2485
+ ),
2486
+ /* @__PURE__ */ jsxs("g", { clipPath: `url(#${e})`, transform: "matrix(1.33333 0 0 -1.33333 0 425.333)", children: [
2487
+ /* @__PURE__ */ jsx(
2488
+ "g",
2489
+ {
2490
+ style: {
2491
+ opacity: 0.69999701
2492
+ },
2493
+ clipPath: `url(#${f})`,
2494
+ children: /* @__PURE__ */ jsx(
2495
+ "path",
2496
+ {
2497
+ style: {
2498
+ fill: `url(#${g})`,
2499
+ stroke: "none"
2500
+ },
2501
+ d: "M328.853 112.107c22.297 0 40.372 18.075 40.372 40.372v71.315c0 10.054 7.505 18.206 17.554 18.206 10.048 0 17.552-8.152 17.552-18.206v-71.315c0-41.686-33.793-75.479-75.478-75.479-9.694 0-17.553 7.859-17.553 17.554 0 9.694 7.859 17.553 17.553 17.553"
2502
+ }
2503
+ )
2504
+ }
2505
+ ),
2506
+ /* @__PURE__ */ jsx(
2507
+ "g",
2508
+ {
2509
+ style: {
2510
+ opacity: 0.69999701
2511
+ },
2512
+ clipPath: `url(#${h})`,
2513
+ children: /* @__PURE__ */ jsx(
2514
+ "path",
2515
+ {
2516
+ style: {
2517
+ fill: `url(#${i})`,
2518
+ stroke: "none"
2519
+ },
2520
+ d: "M216.513 242c-10.049 0-17.553-8.152-17.553-18.206V95.206c0-10.054 7.504-18.206 17.553-18.206 10.048 0 17.553 8.152 17.553 18.206v128.588c0 10.054-7.505 18.206-17.553 18.206"
2521
+ }
2522
+ )
2523
+ }
2524
+ )
2525
+ ] }),
2526
+ /* @__PURE__ */ jsx(
2527
+ "path",
2528
+ {
2529
+ style: {
2530
+ fill: `url(#${j})`,
2531
+ stroke: "none"
2532
+ },
2533
+ d: "M369.225 224.447c0-9.694 7.859-17.553 17.553-17.553 9.695 0 17.553 7.859 17.553 17.553s-7.858 17.552-17.553 17.552c-9.694 0-17.553-7.858-17.553-17.552",
2534
+ transform: "matrix(1.33333 0 0 -1.33333 0 425.333)"
2535
+ }
2536
+ ),
2537
+ /* @__PURE__ */ jsx(
2538
+ "path",
2539
+ {
2540
+ style: {
2541
+ fill: `url(#${k})`,
2542
+ stroke: "none"
2543
+ },
2544
+ d: "M553.532 94.554c0-9.695 7.859-17.554 17.553-17.554 9.695 0 17.554 7.859 17.554 17.554 0 9.694-7.859 17.552-17.554 17.552-9.694 0-17.553-7.858-17.553-17.552",
2545
+ transform: "matrix(1.33333 0 0 -1.33333 0 425.333)"
2546
+ }
2547
+ ),
2548
+ /* @__PURE__ */ jsx(
2549
+ "path",
2550
+ {
2551
+ style: {
2552
+ fill: `url(#${l})`,
2553
+ stroke: "none"
2554
+ },
2555
+ d: "M69.067 223.794V95.206C69.067 85.152 76.571 77 86.62 77c10.048 0 17.553 8.152 17.553 18.206v128.588c0 10.055-7.505 18.205-17.553 18.205-10.049 0-17.553-8.15-17.553-18.205",
2556
+ transform: "matrix(1.33333 0 0 -1.33333 0 425.333)"
2557
+ }
2558
+ ),
2559
+ /* @__PURE__ */ jsx(
2560
+ "path",
2561
+ {
2562
+ style: {
2563
+ fill: `url(#${m})`,
2564
+ stroke: "none"
2565
+ },
2566
+ d: "M198.96 94.554c0-9.695 7.859-17.554 17.553-17.554 9.695 0 17.554 7.859 17.554 17.554 0 9.694-7.859 17.553-17.554 17.553-9.694 0-17.553-7.859-17.553-17.553",
2567
+ transform: "matrix(1.33333 0 0 -1.33333 0 425.333)"
2568
+ }
2569
+ ),
2570
+ /* @__PURE__ */ jsx("g", { clipPath: `url(#${n})`, transform: "matrix(1.33333 0 0 -1.33333 0 425.333)", children: /* @__PURE__ */ jsx(
2571
+ "g",
2572
+ {
2573
+ style: {
2574
+ opacity: 0.69999701
2575
+ },
2576
+ clipPath: `url(#${o})`,
2577
+ children: /* @__PURE__ */ jsx(
2578
+ "path",
2579
+ {
2580
+ style: {
2581
+ fill: `url(#${p})`,
2582
+ stroke: "none"
2583
+ },
2584
+ d: "M139.155 147.088c6.855-6.855 17.969-6.855 24.824 0s6.855 17.969 0 24.824l-64.947 64.946c-6.855 6.855-17.969 6.855-24.824 0s-6.855-17.969 0-24.823z"
2585
+ }
2586
+ )
2587
+ }
2588
+ ) }),
2589
+ /* @__PURE__ */ jsx(
2590
+ "path",
2591
+ {
2592
+ style: {
2593
+ fill: `url(#${q})`,
2594
+ stroke: "none"
2595
+ },
2596
+ d: "m204.101 236.858-64.947-64.946c-6.854-6.855-6.854-17.969 0-24.824 6.856-6.855 17.97-6.855 24.824 0l64.947 64.947c6.855 6.855 6.855 17.968 0 24.823A17.495 17.495 0 0 1 216.513 242a17.498 17.498 0 0 1-12.412-5.142",
2597
+ transform: "matrix(1.33333 0 0 -1.33333 0 425.333)"
2598
+ }
2599
+ ),
2600
+ /* @__PURE__ */ jsx(
2601
+ "path",
2602
+ {
2603
+ style: {
2604
+ fill: `url(#${r})`,
2605
+ stroke: "none"
2606
+ },
2607
+ d: "M253.374 223.794v-71.315c0-41.685 33.793-75.479 75.479-75.479 9.695 0 17.553 7.859 17.553 17.554 0 9.694-7.858 17.553-17.553 17.553-22.297 0-40.372 18.075-40.372 40.372v71.315c0 10.055-7.505 18.205-17.554 18.205s-17.553-8.15-17.553-18.205",
2608
+ transform: "matrix(1.33333 0 0 -1.33333 0 425.333)"
2609
+ }
2610
+ )
2611
+ ]
2612
+ }
2613
+ );
2614
+ }
2615
+ const Logo = styled.span`
2616
+ display: inline-block;
2617
+ height: 0.8em;
2618
+ margin-right: 1em;
2619
+ transform: translate(0.3em, -0.2em);
2620
+ `, Header = () => /* @__PURE__ */ jsxs(Fragment, { children: [
2621
+ /* @__PURE__ */ jsx(Logo, { children: /* @__PURE__ */ jsx(MuxLogo, { height: 13 }) }),
2622
+ "API Credentials"
2623
+ ] }), fieldNames = ["token", "secretKey", "enableSignedUrls"];
2624
+ function ConfigureApi({ secrets, setDialogState }) {
2625
+ var _a, _b;
2626
+ const client = useClient(), [state, dispatch] = useSecretsFormState(secrets), hasSecretsInitially = useMemo(() => secrets.token && secrets.secretKey, [secrets]), handleClose = useCallback(() => setDialogState(!1), [setDialogState]), dirty = useMemo(
2627
+ () => secrets.token !== state.token || secrets.secretKey !== state.secretKey || secrets.enableSignedUrls !== state.enableSignedUrls,
2628
+ [secrets, state]
2629
+ ), id = `ConfigureApi${useId()}`, [tokenId, secretKeyId, enableSignedUrlsId] = useMemo(
2630
+ () => fieldNames.map((field) => `${id}-${field}`),
2631
+ [id]
2632
+ ), firstField = useRef(null), handleSaveSecrets = useSaveSecrets(client, secrets), saving = useRef(!1), handleSubmit = useCallback(
2633
+ (event) => {
2634
+ if (event.preventDefault(), !saving.current && event.currentTarget.reportValidity()) {
2635
+ saving.current = !0, dispatch({ type: "submit" });
2636
+ const { token, secretKey, enableSignedUrls } = state;
2637
+ handleSaveSecrets({ token, secretKey, enableSignedUrls }).then((savedSecrets) => {
2638
+ const { projectId, dataset } = client.config();
2639
+ clear([cacheNs, _id, projectId, dataset]), preload(() => Promise.resolve(savedSecrets), [cacheNs, _id, projectId, dataset]), setDialogState(!1);
2640
+ }).catch((err) => dispatch({ type: "error", payload: err.message })).finally(() => {
2641
+ saving.current = !1;
2642
+ });
2643
+ }
2644
+ },
2645
+ [client, dispatch, handleSaveSecrets, setDialogState, state]
2646
+ ), handleChangeToken = useCallback(
2647
+ (event) => {
2648
+ dispatch({
2649
+ type: "change",
2650
+ payload: { name: "token", value: event.currentTarget.value }
2651
+ });
2652
+ },
2653
+ [dispatch]
2654
+ ), handleChangeSecretKey = useCallback(
2655
+ (event) => {
2656
+ dispatch({
2657
+ type: "change",
2658
+ payload: { name: "secretKey", value: event.currentTarget.value }
2659
+ });
2660
+ },
2661
+ [dispatch]
2662
+ ), handleChangeEnableSignedUrls = useCallback(
2663
+ (event) => {
2664
+ dispatch({
2665
+ type: "change",
2666
+ payload: { name: "enableSignedUrls", value: event.currentTarget.checked }
2667
+ });
2668
+ },
2669
+ [dispatch]
2670
+ );
2671
+ return useEffect(() => {
2672
+ firstField.current && firstField.current.focus();
2673
+ }, [firstField]), /* @__PURE__ */ jsx(
2674
+ Dialog,
2675
+ {
2676
+ id,
2677
+ onClose: handleClose,
2678
+ header: /* @__PURE__ */ jsx(Header, {}),
2679
+ width: 1,
2680
+ style: {
2681
+ maxWidth: "550px"
2682
+ },
2683
+ children: /* @__PURE__ */ jsx(Box, { padding: 4, style: { position: "relative" }, children: /* @__PURE__ */ jsx("form", { onSubmit: handleSubmit, noValidate: !0, children: /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
2684
+ !hasSecretsInitially && /* @__PURE__ */ jsx(Card, { padding: [3, 3, 3], radius: 2, shadow: 1, tone: "primary", children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
2685
+ /* @__PURE__ */ jsxs(Text, { size: 1, children: [
2686
+ "To set up a new access token, go to your",
2687
+ " ",
2688
+ /* @__PURE__ */ jsx(
2689
+ "a",
2690
+ {
2691
+ href: "https://dashboard.mux.com/settings/access-tokens",
2692
+ target: "_blank",
2693
+ rel: "noreferrer noopener",
2694
+ children: "account on mux.com"
2695
+ }
2696
+ ),
2697
+ "."
2698
+ ] }),
2699
+ /* @__PURE__ */ jsxs(Text, { size: 1, children: [
2700
+ "The access token needs permissions: ",
2701
+ /* @__PURE__ */ jsx("strong", { children: "Mux Video " }),
2702
+ "(Full Access) and ",
2703
+ /* @__PURE__ */ jsx("strong", { children: "Mux Data" }),
2704
+ " (Read)",
2705
+ /* @__PURE__ */ jsx("br", {}),
2706
+ "The credentials will be stored safely in a hidden document only available to editors."
2707
+ ] })
2708
+ ] }) }),
2709
+ /* @__PURE__ */ jsx(FormField$1, { title: "Access Token", inputId: tokenId, children: /* @__PURE__ */ jsx(
2710
+ TextInput,
2711
+ {
2712
+ id: tokenId,
2713
+ ref: firstField,
2714
+ onChange: handleChangeToken,
2715
+ type: "text",
2716
+ value: (_a = state.token) != null ? _a : "",
2717
+ required: !!state.secretKey || state.enableSignedUrls
2718
+ }
2719
+ ) }),
2720
+ /* @__PURE__ */ jsx(FormField$1, { title: "Secret Key", inputId: secretKeyId, children: /* @__PURE__ */ jsx(
2721
+ TextInput,
2722
+ {
2723
+ id: secretKeyId,
2724
+ onChange: handleChangeSecretKey,
2725
+ type: "text",
2726
+ value: (_b = state.secretKey) != null ? _b : "",
2727
+ required: !!state.token || state.enableSignedUrls
2728
+ }
2729
+ ) }),
2730
+ /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
2731
+ /* @__PURE__ */ jsxs(Flex, { align: "center", children: [
2732
+ /* @__PURE__ */ jsx(
2733
+ Checkbox,
2734
+ {
2735
+ id: enableSignedUrlsId,
2736
+ onChange: handleChangeEnableSignedUrls,
2737
+ checked: state.enableSignedUrls,
2738
+ style: { display: "block" }
2739
+ }
2740
+ ),
2741
+ /* @__PURE__ */ jsx(Box, { flex: 1, paddingLeft: 3, children: /* @__PURE__ */ jsx(Text, { children: /* @__PURE__ */ jsx("label", { htmlFor: enableSignedUrlsId, children: "Enable Signed Urls" }) }) })
2742
+ ] }),
2743
+ secrets.signingKeyId && state.enableSignedUrls ? /* @__PURE__ */ jsx(Card, { padding: [3, 3, 3], radius: 2, shadow: 1, tone: "caution", children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
2744
+ /* @__PURE__ */ jsx(Text, { size: 1, children: "The signing key ID that Sanity will use is:" }),
2745
+ /* @__PURE__ */ jsx(Code, { size: 1, children: secrets.signingKeyId }),
2746
+ /* @__PURE__ */ jsxs(Text, { size: 1, children: [
2747
+ "This key is only used for previewing content in the Sanity UI.",
2748
+ /* @__PURE__ */ jsx("br", {}),
2749
+ "You should generate a different key to use in your application server."
2750
+ ] })
2751
+ ] }) }) : null
2752
+ ] }),
2753
+ /* @__PURE__ */ jsxs(Inline, { space: 2, children: [
2754
+ /* @__PURE__ */ jsx(
2755
+ Button,
2756
+ {
2757
+ text: "Save",
2758
+ disabled: !dirty,
2759
+ loading: state.submitting,
2760
+ tone: "primary",
2761
+ mode: "default",
2762
+ type: "submit"
2763
+ }
2764
+ ),
2765
+ /* @__PURE__ */ jsx(
2766
+ Button,
2767
+ {
2768
+ disabled: state.submitting,
2769
+ text: "Cancel",
2770
+ mode: "bleed",
2771
+ onClick: handleClose
2772
+ }
2773
+ )
2774
+ ] }),
2775
+ state.error && /* @__PURE__ */ jsx(Card, { padding: [3, 3, 3], radius: 2, shadow: 1, tone: "critical", children: /* @__PURE__ */ jsx(Text, { children: state.error }) })
2776
+ ] }) }) })
2777
+ }
2778
+ );
2779
+ }
2780
+ var ConfigureApi$1 = memo(ConfigureApi);
2781
+ function ErrorBoundaryCard(props) {
2782
+ const { children, schemaType } = props, { push: pushToast } = useToast(), errorRef = useRef(null), { ErrorBoundary, didCatch, error, reset } = useErrorBoundary({
2783
+ onDidCatch: (err, errorInfo) => {
2784
+ console.group(err.toString()), console.groupCollapsed("console.error"), console.error(err), console.groupEnd(), err.stack && (console.groupCollapsed("error.stack"), console.log(err.stack), console.groupEnd()), errorInfo != null && errorInfo.componentStack && (console.groupCollapsed("errorInfo.componentStack"), console.log(errorInfo.componentStack), console.groupEnd()), console.groupEnd(), pushToast({
2785
+ status: "error",
2786
+ title: "Plugin crashed",
2787
+ description: /* @__PURE__ */ jsx(Flex, { align: "center", children: /* @__PURE__ */ jsxs(Inline, { space: 1, children: [
2788
+ "An error happened while rendering",
2789
+ /* @__PURE__ */ jsx(
2790
+ Button,
2791
+ {
2792
+ padding: 1,
2793
+ fontSize: 1,
2794
+ style: { transform: "translateY(1px)" },
2795
+ mode: "ghost",
2796
+ text: schemaType.title,
2797
+ onClick: () => {
2798
+ errorRef.current && scrollIntoView(errorRef.current, {
2799
+ behavior: "smooth",
2800
+ scrollMode: "if-needed",
2801
+ block: "center"
2802
+ });
2803
+ }
2804
+ }
2805
+ )
2806
+ ] }) })
2807
+ });
2808
+ }
2809
+ }), handleRetry = useCallback(() => {
2810
+ clear([name$1]), reset();
2811
+ }, [reset]);
2812
+ return didCatch ? /* @__PURE__ */ jsx(Card, { ref: errorRef, paddingX: [2, 3, 4, 4], height: "fill", shadow: 1, overflow: "auto", children: /* @__PURE__ */ jsx(Flex, { justify: "flex-start", align: "center", height: "fill", children: /* @__PURE__ */ jsxs(Grid, { columns: 1, gap: [2, 3, 4, 4], children: [
2813
+ /* @__PURE__ */ jsxs(Heading, { as: "h1", children: [
2814
+ "The ",
2815
+ /* @__PURE__ */ jsx("code", { children: name$1 }),
2816
+ " plugin crashed"
2817
+ ] }),
2818
+ (error == null ? void 0 : error.message) && /* @__PURE__ */ jsx(Card, { padding: 3, tone: "critical", shadow: 1, radius: 2, children: /* @__PURE__ */ jsx(Text, { children: error.message }) }),
2819
+ /* @__PURE__ */ jsx(Inline, { children: /* @__PURE__ */ jsx(Button, { onClick: handleRetry, text: "Retry" }) })
2820
+ ] }) }) }) : /* @__PURE__ */ jsx(ErrorBoundary, { children });
2821
+ }
2822
+ var ErrorBoundaryCard$1 = memo(ErrorBoundaryCard);
2823
+ const InputFallback = () => /* @__PURE__ */ jsx("div", { style: { padding: 1 }, children: /* @__PURE__ */ jsx(
2824
+ Card,
2825
+ {
2826
+ shadow: 1,
2827
+ sizing: "border",
2828
+ style: { aspectRatio: "16/9", width: "100%", borderRadius: "1px" },
2829
+ children: /* @__PURE__ */ jsxs(Flex, { align: "center", direction: "column", height: "fill", justify: "center", children: [
2830
+ /* @__PURE__ */ jsx(Spinner, { muted: !0 }),
2831
+ /* @__PURE__ */ jsx(Box, { marginTop: 3, children: /* @__PURE__ */ jsx(Text, { align: "center", muted: !0, size: 1, children: "Loading\u2026" }) })
2832
+ ] })
2833
+ }
2834
+ ) });
2835
+ function Onboard(props) {
2836
+ const { setDialogState } = props, handleOpen = useCallback(() => setDialogState("secrets"), [setDialogState]);
2837
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx("div", { style: { padding: 2 }, children: /* @__PURE__ */ jsx(
2838
+ Card,
2839
+ {
2840
+ display: "flex",
2841
+ sizing: "border",
2842
+ style: {
2843
+ aspectRatio: "16/9",
2844
+ width: "100%",
2845
+ boxShadow: "var(--card-bg-color) 0 0 0 2px"
2846
+ },
2847
+ paddingX: [2, 3, 4, 4],
2848
+ radius: 1,
2849
+ tone: "transparent",
2850
+ children: /* @__PURE__ */ jsx(Flex, { justify: "flex-start", align: "center", children: /* @__PURE__ */ jsxs(Grid, { columns: 1, gap: [2, 3, 4, 4], children: [
2851
+ /* @__PURE__ */ jsx(Inline, { paddingY: 1, children: /* @__PURE__ */ jsx("div", { style: { height: "32px" }, children: /* @__PURE__ */ jsx(MuxLogo, {}) }) }),
2852
+ /* @__PURE__ */ jsx(Inline, { paddingY: 1, children: /* @__PURE__ */ jsx(Heading, { size: [0, 1, 2, 2], children: "Upload and preview videos directly from your studio." }) }),
2853
+ /* @__PURE__ */ jsx(Inline, { paddingY: 1, children: /* @__PURE__ */ jsx(Button, { mode: "ghost", icon: PlugIcon, text: "Configure API", onClick: handleOpen }) })
2854
+ ] }) })
2855
+ }
2856
+ ) }) });
2857
+ }
2858
+ function createUpChunkObservable(uuid2, uploadUrl2, source2) {
2859
+ return new Observable((subscriber) => {
2860
+ const upchunk = UpChunk.createUpload({
2861
+ endpoint: uploadUrl2,
2862
+ file: source2,
2863
+ dynamicChunkSize: !0
2864
+ // changes the chunk size based on network speeds
2865
+ }), successHandler = () => {
2866
+ subscriber.next({
2867
+ type: "success",
2868
+ id: uuid2
2869
+ }), subscriber.complete();
2870
+ }, errorHandler = (data) => subscriber.error(new Error(data.detail.message)), progressHandler = (data) => subscriber.next({ type: "progress", percent: data.detail }), offlineHandler = () => {
2871
+ upchunk.pause(), subscriber.next({
2872
+ type: "pause",
2873
+ id: uuid2
2874
+ });
2875
+ }, onlineHandler = () => {
2876
+ upchunk.resume(), subscriber.next({
2877
+ type: "resume",
2878
+ id: uuid2
2879
+ });
2880
+ };
2881
+ return upchunk.on("success", successHandler), upchunk.on("error", errorHandler), upchunk.on("progress", progressHandler), upchunk.on("offline", offlineHandler), upchunk.on("online", onlineHandler), () => upchunk.abort();
2882
+ });
2883
+ }
2884
+ function cancelUpload(client, uuid2) {
2885
+ return client.observable.request({
2886
+ url: `/addons/mux/uploads/${client.config().dataset}/${uuid2}`,
2887
+ withCredentials: !0,
2888
+ method: "DELETE"
2889
+ });
2890
+ }
2891
+ function uploadUrl({
2892
+ url,
2893
+ settings,
2894
+ client
2895
+ }) {
2896
+ return testUrl(url).pipe(
2897
+ switchMap((validUrl) => concat(
2898
+ of({ type: "url", url: validUrl }),
2899
+ testSecretsObservable(client).pipe(
2900
+ switchMap((json) => {
2901
+ if (!json || !json.status)
2902
+ return throwError(new Error("Invalid credentials"));
2903
+ const uuid$1 = uuid(), muxBody = settings;
2904
+ muxBody.input || (muxBody.input = [{ type: "video" }]), muxBody.input[0].url = validUrl;
2905
+ const query = {
2906
+ muxBody: JSON.stringify(muxBody),
2907
+ filename: validUrl.split("/").slice(-1)[0]
2908
+ }, dataset = client.config().dataset;
2909
+ return defer(
2910
+ () => client.observable.request({
2911
+ url: `/addons/mux/assets/${dataset}`,
2912
+ withCredentials: !0,
2913
+ method: "POST",
2914
+ headers: {
2915
+ "MUX-Proxy-UUID": uuid$1,
2916
+ "Content-Type": "application/json"
2917
+ },
2918
+ query
2919
+ })
2920
+ ).pipe(
2921
+ mergeMap((result) => {
2922
+ const asset = result && result.results && result.results[0] && result.results[0].document || null;
2923
+ return asset ? of({ type: "success", id: uuid$1, asset }) : throwError(new Error("No asset document returned"));
2924
+ })
2925
+ );
2926
+ })
2927
+ )
2928
+ ))
2929
+ );
2930
+ }
2931
+ function uploadFile({
2932
+ settings,
2933
+ client,
2934
+ file
2935
+ }) {
2936
+ return testFile(file).pipe(
2937
+ switchMap((fileOptions) => concat(
2938
+ of({ type: "file", file: fileOptions }),
2939
+ testSecretsObservable(client).pipe(
2940
+ switchMap((json) => {
2941
+ if (!json || !json.status)
2942
+ return throwError(() => new Error("Invalid credentials"));
2943
+ const uuid$1 = uuid(), body = settings;
2944
+ return concat(
2945
+ of({ type: "uuid", uuid: uuid$1 }),
2946
+ defer(
2947
+ () => client.observable.request({
2948
+ url: `/addons/mux/uploads/${client.config().dataset}`,
2949
+ withCredentials: !0,
2950
+ method: "POST",
2951
+ headers: {
2952
+ "MUX-Proxy-UUID": uuid$1,
2953
+ "Content-Type": "application/json"
2954
+ },
2955
+ body
2956
+ })
2957
+ ).pipe(
2958
+ mergeMap((result) => createUpChunkObservable(uuid$1, result.upload.url, file).pipe(
2959
+ // eslint-disable-next-line no-warning-comments
2960
+ // @TODO type the observable events
2961
+ // eslint-disable-next-line max-nested-callbacks
2962
+ mergeMap((event) => event.type !== "success" ? of(event) : from(updateAssetDocumentFromUpload(client, uuid$1)).pipe(
2963
+ // eslint-disable-next-line max-nested-callbacks
2964
+ mergeMap((doc) => of({ ...event, asset: doc }))
2965
+ )),
2966
+ // eslint-disable-next-line max-nested-callbacks
2967
+ catchError((err) => cancelUpload(client, uuid$1).pipe(mergeMapTo(throwError(err))))
2968
+ ))
2969
+ )
2970
+ );
2971
+ })
2972
+ )
2973
+ ))
2974
+ );
2975
+ }
2976
+ function getUpload(client, assetId) {
2977
+ const { dataset } = client.config();
2978
+ return client.request({
2979
+ url: `/addons/mux/uploads/${dataset}/${assetId}`,
2980
+ withCredentials: !0,
2981
+ method: "GET"
2982
+ });
2983
+ }
2984
+ function pollUpload(client, uuid2) {
2985
+ let pollInterval, tries = 0, assetId, upload;
2986
+ return new Promise((resolve, reject) => {
2987
+ pollInterval = setInterval(async () => {
2988
+ try {
2989
+ upload = await getUpload(client, uuid2);
2990
+ } catch (err) {
2991
+ reject(err);
2992
+ return;
2993
+ }
2994
+ assetId = upload && upload.data && upload.data.asset_id, assetId && (clearInterval(pollInterval), resolve(upload)), tries > 10 && (clearInterval(pollInterval), reject(new Error("Upload did not finish"))), tries++;
2995
+ }, 2e3);
2996
+ });
2997
+ }
2998
+ async function updateAssetDocumentFromUpload(client, uuid2) {
2999
+ let upload, asset;
3000
+ try {
3001
+ upload = await pollUpload(client, uuid2);
3002
+ } catch (err) {
3003
+ return Promise.reject(err);
3004
+ }
3005
+ try {
3006
+ asset = await getAsset(client, upload.data.asset_id);
3007
+ } catch (err) {
3008
+ return Promise.reject(err);
3009
+ }
3010
+ const doc = {
3011
+ _id: uuid2,
3012
+ _type: "mux.videoAsset",
3013
+ status: asset.data.status,
3014
+ data: asset.data,
3015
+ assetId: asset.data.id,
3016
+ playbackId: asset.data.playback_ids[0].id,
3017
+ uploadId: upload.data.id
3018
+ };
3019
+ return client.createOrReplace(doc).then(() => doc);
3020
+ }
3021
+ function testFile(file) {
3022
+ if (typeof window < "u" && file instanceof window.File) {
3023
+ const fileOptions = optionsFromFile({}, file);
3024
+ return of(fileOptions);
3025
+ }
3026
+ return throwError(new Error("Invalid file"));
3027
+ }
3028
+ function testUrl(url) {
3029
+ const error = new Error("Invalid URL");
3030
+ if (typeof url != "string")
3031
+ return throwError(error);
3032
+ let parsed;
3033
+ try {
3034
+ parsed = new URL(url);
3035
+ } catch {
3036
+ return throwError(error);
3037
+ }
3038
+ return parsed && !parsed.protocol.match(/http:|https:/) ? throwError(error) : of(url);
3039
+ }
3040
+ function optionsFromFile(opts, file) {
3041
+ if (!(typeof window > "u" || !(file instanceof window.File)))
3042
+ return {
3043
+ name: opts.preserveFilename === !1 ? void 0 : file.name,
3044
+ type: file.type
3045
+ };
3046
+ }
3047
+ function isValidUrl(url) {
3048
+ try {
3049
+ const parsed = new URL(url);
3050
+ return parsed && !!parsed.protocol.match(/http:|https:/);
3051
+ } catch {
3052
+ return !1;
3053
+ }
3054
+ }
3055
+ function extractDroppedFiles(dataTransfer) {
3056
+ const files2 = Array.from(dataTransfer.files || []), items = Array.from(dataTransfer.items || []);
3057
+ return files2 && files2.length > 0 ? Promise.resolve(files2) : normalizeItems(items).then((arr) => arr.flat());
3058
+ }
3059
+ function normalizeItems(items) {
3060
+ return Promise.all(
3061
+ items.map((item) => {
3062
+ if (item.kind === "file" && item.webkitGetAsEntry) {
3063
+ let entry;
3064
+ try {
3065
+ entry = item.webkitGetAsEntry();
3066
+ } catch {
3067
+ return [item.getAsFile()];
3068
+ }
3069
+ return entry ? entry.isDirectory ? walk(entry) : [item.getAsFile()] : [];
3070
+ }
3071
+ if (item.kind === "file") {
3072
+ const file = item.getAsFile();
3073
+ return Promise.resolve(file ? [file] : []);
3074
+ }
3075
+ return new Promise((resolve) => item.getAsString(resolve)).then(
3076
+ (str) => str ? [new File([str], "unknown.txt", { type: item.type })] : []
3077
+ );
3078
+ })
3079
+ );
3080
+ }
3081
+ function isFile(entry) {
3082
+ return entry.isFile;
3083
+ }
3084
+ function isDirectory(entry) {
3085
+ return entry.isDirectory;
3086
+ }
3087
+ function walk(entry) {
3088
+ if (isFile(entry))
3089
+ return new Promise((resolve) => entry.file(resolve)).then((file) => [file]);
3090
+ if (isDirectory(entry)) {
3091
+ const dir = entry.createReader();
3092
+ return new Promise((resolve) => dir.readEntries(resolve)).then((entries) => entries.filter((entr) => !entr.name.startsWith("."))).then((entries) => Promise.all(entries.map(walk)).then((arr) => arr.flat()));
3093
+ }
3094
+ return Promise.resolve([]);
3095
+ }
3096
+ function SelectAssets({ asset: selectedAsset, onChange, setDialogState }) {
3097
+ const handleSelect = useCallback(
3098
+ (chosenAsset) => {
3099
+ chosenAsset != null && chosenAsset._id || onChange(PatchEvent.from([unset(["asset"])])), chosenAsset._id !== (selectedAsset == null ? void 0 : selectedAsset._id) && onChange(
3100
+ PatchEvent.from([
3101
+ setIfMissing({ asset: {}, _type: "mux.video" }),
3102
+ set({ _type: "reference", _weak: !0, _ref: chosenAsset._id }, ["asset"])
3103
+ ])
3104
+ ), setDialogState(!1);
3105
+ },
3106
+ [onChange, setDialogState, selectedAsset]
3107
+ );
3108
+ return /* @__PURE__ */ jsx(VideosBrowser, { onSelect: handleSelect });
3109
+ }
3110
+ const StyledDialog = styled(Dialog)`
3111
+ > div[data-ui='DialogCard'] > div[data-ui='Card'] {
3112
+ height: 100%;
3113
+ }
3114
+ `;
3115
+ function InputBrowser({
3116
+ setDialogState,
3117
+ asset,
3118
+ onChange
3119
+ }) {
3120
+ const id = `InputBrowser${useId()}`, handleClose = useCallback(() => setDialogState(!1), [setDialogState]);
3121
+ return /* @__PURE__ */ jsx(
3122
+ StyledDialog,
3123
+ {
3124
+ __unstable_autoFocus: !0,
3125
+ header: "Select video",
3126
+ id,
3127
+ onClose: handleClose,
3128
+ width: 2,
3129
+ children: /* @__PURE__ */ jsx(SelectAssets, { asset, onChange, setDialogState })
3130
+ }
3131
+ );
3132
+ }
3133
+ const useCancelUpload = (asset, onChange) => {
3134
+ const client = useClient();
3135
+ return useCallback(() => {
3136
+ asset && (onChange(PatchEvent.from(unset())), asset.assetId && deleteAssetOnMux(client, asset.assetId), asset._id && client.delete(asset._id));
3137
+ }, [asset, client, onChange]);
3138
+ };
3139
+ styled.div`
3140
+ && {
3141
+ --media-background-color: transparent;
3142
+ --media-button-icon-width: 100%;
3143
+ --media-button-icon-height: auto;
3144
+ pointer-events: none;
3145
+ width: 100%;
3146
+ display: flex;
3147
+ flex-flow: row;
3148
+ align-items: center;
3149
+ justify-content: center;
3150
+ media-play-button {
3151
+ --media-control-background: transparent;
3152
+ --media-control-hover-background: transparent;
3153
+ padding: 0;
3154
+ width: max(27px, min(9%, 90px));
3155
+ }
3156
+ }
3157
+ `;
3158
+ const TopControls = styled.div`
3159
+ position: absolute;
3160
+ top: 0;
3161
+ right: 0;
3162
+ justify-content: flex-end;
3163
+ button {
3164
+ height: auto;
3165
+ }
3166
+ `, CardWrapper = styled(Card)`
3167
+ min-height: 82px;
3168
+ box-sizing: border-box;
3169
+ `, FlexWrapper = styled(Flex)`
3170
+ text-overflow: ellipsis;
3171
+ overflow: hidden;
3172
+ `, LeftSection = styled(Stack)`
3173
+ position: relative;
3174
+ width: 60%;
3175
+ `, CodeWrapper = styled(Code)`
3176
+ position: relative;
3177
+ width: 100%;
3178
+
3179
+ code {
3180
+ overflow: hidden;
3181
+ text-overflow: ellipsis;
3182
+ position: relative;
3183
+ max-width: 200px;
3184
+ }
3185
+ `, UploadProgress = ({
3186
+ progress = 100,
3187
+ onCancel,
3188
+ filename,
3189
+ text = "Uploading"
3190
+ }) => /* @__PURE__ */ jsx(CardWrapper, { tone: "primary", padding: 4, border: !0, height: "fill", children: /* @__PURE__ */ jsxs(FlexWrapper, { align: "center", justify: "space-between", height: "fill", direction: "row", gap: 2, children: [
3191
+ /* @__PURE__ */ jsxs(LeftSection, { children: [
3192
+ /* @__PURE__ */ jsx(Flex, { justify: "center", gap: [3, 3, 2, 2], direction: ["column", "column", "row"], children: /* @__PURE__ */ jsx(Text, { size: 1, children: /* @__PURE__ */ jsxs(Inline, { space: 2, children: [
3193
+ text,
3194
+ /* @__PURE__ */ jsx(CodeWrapper, { size: 1, children: filename || "..." })
3195
+ ] }) }) }),
3196
+ /* @__PURE__ */ jsx(Card, { marginTop: 3, radius: 5, shadow: 1, children: /* @__PURE__ */ jsx(LinearProgress, { value: progress }) })
3197
+ ] }),
3198
+ onCancel ? /* @__PURE__ */ jsx(
3199
+ Button,
3200
+ {
3201
+ fontSize: 2,
3202
+ text: "Cancel upload",
3203
+ mode: "ghost",
3204
+ tone: "critical",
3205
+ onClick: onCancel
3206
+ }
3207
+ ) : null
3208
+ ] }) }), Player = ({ asset, buttons, readOnly, onChange }) => {
3209
+ var _a, _b, _c, _d;
3210
+ const isLoading = useMemo(() => (asset == null ? void 0 : asset.status) === "preparing" ? "Preparing the video" : (asset == null ? void 0 : asset.status) === "waiting_for_upload" ? "Waiting for upload to start" : (asset == null ? void 0 : asset.status) === "waiting" ? "Processing upload" : !((asset == null ? void 0 : asset.status) === "ready" || typeof (asset == null ? void 0 : asset.status) > "u"), [asset]), isPreparingStaticRenditions = useMemo(() => {
3211
+ var _a2, _b2;
3212
+ return ((_b2 = (_a2 = asset == null ? void 0 : asset.data) == null ? void 0 : _a2.static_renditions) == null ? void 0 : _b2.status) === "preparing";
3213
+ }, [(_b = (_a = asset == null ? void 0 : asset.data) == null ? void 0 : _a.static_renditions) == null ? void 0 : _b.status]), playRef = useRef(null), muteRef = useRef(null), handleCancelUpload = useCancelUpload(asset, onChange);
3214
+ return useEffect(() => {
3215
+ var _a2, _b2;
3216
+ const style = document.createElement("style");
3217
+ style.innerHTML = "button svg { vertical-align: middle; }", (_a2 = playRef.current) != null && _a2.shadowRoot && playRef.current.shadowRoot.appendChild(style), (_b2 = muteRef == null ? void 0 : muteRef.current) != null && _b2.shadowRoot && muteRef.current.shadowRoot.appendChild(style.cloneNode(!0));
3218
+ }, []), useEffect(() => {
3219
+ var _a2, _b2, _c2;
3220
+ if ((asset == null ? void 0 : asset.status) === "errored")
3221
+ throw handleCancelUpload(), new Error((_c2 = (_b2 = (_a2 = asset.data) == null ? void 0 : _a2.errors) == null ? void 0 : _b2.messages) == null ? void 0 : _c2.join(" "));
3222
+ }, [(_d = (_c = asset.data) == null ? void 0 : _c.errors) == null ? void 0 : _d.messages, asset == null ? void 0 : asset.status, handleCancelUpload]), !asset || !asset.status ? null : isLoading ? /* @__PURE__ */ jsx(
3223
+ UploadProgress,
3224
+ {
3225
+ progress: 100,
3226
+ filename: asset == null ? void 0 : asset.filename,
3227
+ text: isLoading !== !0 && isLoading || "Waiting for Mux to complete the upload",
3228
+ onCancel: readOnly ? void 0 : () => handleCancelUpload()
3229
+ }
3230
+ ) : /* @__PURE__ */ jsxs(VideoPlayer, { asset, children: [
3231
+ buttons && /* @__PURE__ */ jsx(TopControls, { slot: "top-chrome", children: buttons }),
3232
+ isPreparingStaticRenditions && /* @__PURE__ */ jsx(
3233
+ Card,
3234
+ {
3235
+ padding: 2,
3236
+ radius: 1,
3237
+ style: {
3238
+ background: "var(--card-fg-color)",
3239
+ position: "absolute",
3240
+ top: "0.5em",
3241
+ left: "0.5em"
3242
+ },
3243
+ children: /* @__PURE__ */ jsx(Text, { size: 1, style: { color: "var(--card-bg-color)" }, children: "MUX is preparing static renditions, please stand by" })
3244
+ }
3245
+ )
3246
+ ] });
3247
+ };
3248
+ function focusRingBorderStyle(border) {
3249
+ return `inset 0 0 0 ${border.width}px ${border.color}`;
3250
+ }
3251
+ function focusRingStyle(opts) {
3252
+ const { base, border, focusRing } = opts, focusRingOutsetWidth = focusRing.offset + focusRing.width, focusRingInsetWidth = 0 - focusRing.offset, bgColor = base ? base.bg : "var(--card-bg-color)";
3253
+ return [
3254
+ focusRingInsetWidth > 0 && `inset 0 0 0 ${focusRingInsetWidth}px var(--card-focus-ring-color)`,
3255
+ border && focusRingBorderStyle(border),
3256
+ focusRingInsetWidth < 0 && `0 0 0 ${0 - focusRingInsetWidth}px ${bgColor}`,
3257
+ focusRingOutsetWidth > 0 && `0 0 0 ${focusRingOutsetWidth}px var(--card-focus-ring-color)`
3258
+ ].filter(Boolean).join(",");
3259
+ }
3260
+ const FileButton = styled(MenuItem)(({ theme }) => {
3261
+ const { focusRing } = theme.sanity, base = theme.sanity.color.base;
3262
+ return css`
3263
+ position: relative;
3264
+
3265
+ &:not([data-disabled='true']) {
3266
+ &:focus-within {
3267
+ box-shadow: ${focusRingStyle({ base, border: { width: 1, color: "var(--card-border-color)" }, focusRing })};
3268
+ }
3269
+ }
3270
+
3271
+ & input {
3272
+ overflow: hidden;
3273
+ top: 0;
3274
+ left: 0;
3275
+ width: 100%;
3276
+ height: 100%;
3277
+ position: absolute;
3278
+ min-width: 0;
3279
+ display: block;
3280
+ appearance: none;
3281
+ padding: 0;
3282
+ margin: 0;
3283
+ border: 0;
3284
+ opacity: 0;
3285
+ }
3286
+ `;
3287
+ }), FileInputMenuItem = React.forwardRef(function(props, forwardedRef) {
3288
+ const {
3289
+ icon,
3290
+ id: idProp,
3291
+ accept,
3292
+ capture,
3293
+ fontSize,
3294
+ multiple,
3295
+ onSelect,
3296
+ space = 3,
3297
+ textAlign,
3298
+ text,
3299
+ disabled,
3300
+ ...rest
3301
+ } = props, idHook = useId(), id = idProp || idHook, handleChange = React.useCallback(
3302
+ (event) => {
3303
+ onSelect && event.target.files && onSelect(Array.from(event.target.files));
3304
+ },
3305
+ [onSelect]
3306
+ ), content = /* @__PURE__ */ jsxs(Flex, { align: "center", justify: "flex-start", children: [
3307
+ icon && /* @__PURE__ */ jsx(Box, { marginRight: text ? space : void 0, children: /* @__PURE__ */ jsxs(Text, { size: fontSize, children: [
3308
+ isValidElement(icon) && icon,
3309
+ isValidElementType(icon) && createElement(icon)
3310
+ ] }) }),
3311
+ text && /* @__PURE__ */ jsx(Text, { align: textAlign, size: fontSize, textOverflow: "ellipsis", children: text })
3312
+ ] });
3313
+ return /* @__PURE__ */ jsxs(FileButton, { ...rest, htmlFor: id, disabled, ref: forwardedRef, children: [
3314
+ content,
3315
+ /* @__PURE__ */ jsx(
3316
+ "input",
3317
+ {
3318
+ "data-testid": "file-button-input",
3319
+ accept,
3320
+ capture,
3321
+ id,
3322
+ multiple,
3323
+ onChange: handleChange,
3324
+ type: "file",
3325
+ value: "",
3326
+ disabled
3327
+ }
3328
+ )
3329
+ ] });
3330
+ }), LockCard = styled(Card)`
3331
+ position: absolute;
3332
+ top: 0;
3333
+ left: 0;
3334
+ opacity: 0.6;
3335
+ mix-blend-mode: screen;
3336
+ background: transparent;
3337
+ `, LockButton = styled(Button)`
3338
+ background: transparent;
3339
+ color: white;
3340
+ `;
3341
+ function PlayerActionsMenu(props) {
3342
+ const { asset, readOnly, dialogState, setDialogState, onChange, onSelect } = props, [open, setOpen] = useState(!1), [menuElement, setMenuRef] = useState(null), isSigned = useMemo(() => getPlaybackPolicy(asset) === "signed", [asset]), onReset = useCallback(() => onChange(PatchEvent.from(unset([]))), [onChange]);
3343
+ return useEffect(() => {
3344
+ open && dialogState && setOpen(!1);
3345
+ }, [dialogState, open]), useClickOutside(
3346
+ useCallback(() => setOpen(!1), []),
3347
+ [menuElement]
3348
+ ), /* @__PURE__ */ jsxs(Inline, { space: 1, padding: 2, children: [
3349
+ isSigned && /* @__PURE__ */ jsx(
3350
+ Tooltip,
3351
+ {
3352
+ content: /* @__PURE__ */ jsx(Box, { padding: 2, children: /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: "Signed playback policy" }) }),
3353
+ placement: "right",
3354
+ portal: !0,
3355
+ children: /* @__PURE__ */ jsx(LockCard, { radius: 2, margin: 2, scheme: "dark", tone: "positive", children: /* @__PURE__ */ jsx(LockButton, { icon: LockIcon, mode: "bleed", tone: "positive" }) })
3356
+ }
3357
+ ),
3358
+ /* @__PURE__ */ jsx(
3359
+ Popover,
3360
+ {
3361
+ content: /* @__PURE__ */ jsxs(Menu, { ref: setMenuRef, children: [
3362
+ /* @__PURE__ */ jsx(Box, { padding: 2, children: /* @__PURE__ */ jsx(Label$1, { muted: !0, size: 1, children: "Replace" }) }),
3363
+ /* @__PURE__ */ jsx(
3364
+ FileInputMenuItem,
3365
+ {
3366
+ accept: "video/*",
3367
+ icon: UploadIcon,
3368
+ onSelect,
3369
+ text: "Upload",
3370
+ disabled: readOnly,
3371
+ fontSize: 1
3372
+ }
3373
+ ),
3374
+ /* @__PURE__ */ jsx(
3375
+ MenuItem,
3376
+ {
3377
+ icon: SearchIcon,
3378
+ text: "Browse",
3379
+ onClick: () => setDialogState("select-video")
3380
+ }
3381
+ ),
3382
+ /* @__PURE__ */ jsx(MenuDivider, {}),
3383
+ /* @__PURE__ */ jsx(
3384
+ MenuItem,
3385
+ {
3386
+ icon: PlugIcon,
3387
+ text: "Configure API",
3388
+ onClick: () => setDialogState("secrets")
3389
+ }
3390
+ ),
3391
+ /* @__PURE__ */ jsx(MenuDivider, {}),
3392
+ /* @__PURE__ */ jsx(
3393
+ MenuItem,
3394
+ {
3395
+ tone: "critical",
3396
+ icon: ResetIcon,
3397
+ text: "Clear field",
3398
+ onClick: onReset,
3399
+ disabled: readOnly
3400
+ }
3401
+ )
3402
+ ] }),
3403
+ portal: !0,
3404
+ open,
3405
+ children: /* @__PURE__ */ jsx(
3406
+ Button,
3407
+ {
3408
+ icon: EllipsisHorizontalIcon,
3409
+ mode: "ghost",
3410
+ fontSize: 1,
3411
+ onClick: () => {
3412
+ setDialogState(!1), setOpen(!0);
3413
+ }
3414
+ }
3415
+ )
3416
+ }
3417
+ )
3418
+ ] });
3419
+ }
3420
+ var PlayerActionsMenu$1 = memo(PlayerActionsMenu);
3421
+ function formatBytes(bytes, si = !1, dp = 1) {
3422
+ const thresh = si ? 1e3 : 1024;
3423
+ if (Math.abs(bytes) < thresh)
3424
+ return bytes + " B";
3425
+ const units = si ? ["kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"] : ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
3426
+ let u = -1;
3427
+ const r = 10 ** dp;
3428
+ do
3429
+ bytes /= thresh, ++u;
3430
+ while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1);
3431
+ return bytes.toFixed(dp) + " " + units[u];
3432
+ }
3433
+ const SUPPORTED_MUX_LANGUAGES = [
3434
+ { label: "English", code: "en", state: "Stable" },
3435
+ { label: "Spanish", code: "es", state: "Stable" },
3436
+ { label: "Italian", code: "it", state: "Stable" },
3437
+ { label: "Portuguese", code: "pt", state: "Stable" },
3438
+ { label: "German", code: "de", state: "Stable" },
3439
+ { label: "French", code: "fr", state: "Stable" },
3440
+ { label: "Polish", code: "pl", state: "Beta" },
3441
+ { label: "Russian", code: "ru", state: "Beta" },
3442
+ { label: "Dutch", code: "nl", state: "Beta" },
3443
+ { label: "Catalan", code: "ca", state: "Beta" },
3444
+ { label: "Turkish", code: "tr", state: "Beta" },
3445
+ { label: "Swedish", code: "sv", state: "Beta" },
3446
+ { label: "Ukrainian", code: "uk", state: "Beta" },
3447
+ { label: "Norwegian", code: "no", state: "Beta" },
3448
+ { label: "Finnish", code: "fi", state: "Beta" },
3449
+ { label: "Slovak", code: "sk", state: "Beta" },
3450
+ { label: "Greek", code: "el", state: "Beta" },
3451
+ { label: "Czech", code: "cs", state: "Beta" },
3452
+ { label: "Croatian", code: "hr", state: "Beta" },
3453
+ { label: "Danish", code: "da", state: "Beta" },
3454
+ { label: "Romanian", code: "ro", state: "Beta" },
3455
+ { label: "Bulgarian", code: "bg", state: "Beta" }
3456
+ ];
3457
+ function isCustomTextTrack(track) {
3458
+ return track.type !== "autogenerated";
3459
+ }
3460
+ function isAutogeneratedTrack(track) {
3461
+ return track.type === "autogenerated";
3462
+ }
3463
+ const ALL_LANGUAGE_CODES = LanguagesList.getAllCodes().map((code) => ({
3464
+ value: code,
3465
+ label: LanguagesList.getNativeName(code)
3466
+ })), SUBTITLE_LANGUAGES = {
3467
+ autogenerated: SUPPORTED_MUX_LANGUAGES.map((lang) => ({
3468
+ value: lang.code,
3469
+ label: lang.label
3470
+ })),
3471
+ subtitles: ALL_LANGUAGE_CODES,
3472
+ captions: ALL_LANGUAGE_CODES
3473
+ }, TRACK_TYPES = [
3474
+ { value: "autogenerated", label: "Auto-generated Subtitles" }
3475
+ // {value: 'subtitles', label: 'Subtitles'},
3476
+ // {value: 'captions', label: 'Closed Captions'},
3477
+ ];
3478
+ function TrackEditor({
3479
+ canAutoGenerate,
3480
+ track,
3481
+ dispatch
3482
+ }) {
3483
+ const { _id: id, type: type2 } = track, dispatchTrackAction = (args) => dispatch({ action: "track", id, ...args }), trackTypes = TRACK_TYPES.filter(
3484
+ ({ value }) => !(value === "autogenerated" && !canAutoGenerate)
3485
+ );
3486
+ return trackTypes.length === 0 ? null : /* @__PURE__ */ jsx(Card, { border: !0, padding: 3, radius: 2, style: { position: "relative" }, children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
3487
+ trackTypes.length > 1 && /* @__PURE__ */ jsx(FormField$2, { title: "Auto-generated subtitles", children: /* @__PURE__ */ jsx(Flex, { gap: 3, children: trackTypes.map(({ value, label }) => {
3488
+ const inputId = `${id}--type-${value}`;
3489
+ return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
3490
+ /* @__PURE__ */ jsx(
3491
+ Radio,
3492
+ {
3493
+ checked: type2 === value,
3494
+ name: "track-type",
3495
+ onChange: (e) => dispatchTrackAction({
3496
+ subAction: "update",
3497
+ value: {
3498
+ type: e.currentTarget.value
3499
+ }
3500
+ }),
3501
+ value,
3502
+ id: inputId
3503
+ }
3504
+ ),
3505
+ /* @__PURE__ */ jsx(Text, { as: "label", htmlFor: inputId, children: label })
3506
+ ] }, value);
3507
+ }) }) }),
3508
+ /* @__PURE__ */ jsx(
3509
+ Autocomplete,
3510
+ {
3511
+ id: `${id}--language`,
3512
+ value: track.language_code,
3513
+ onChange: (newValue) => dispatchTrackAction({
3514
+ subAction: "update",
3515
+ value: {
3516
+ language_code: newValue,
3517
+ name: LanguagesList.getNativeName(newValue)
3518
+ }
3519
+ }),
3520
+ options: SUBTITLE_LANGUAGES[track.type],
3521
+ icon: TranslateIcon,
3522
+ placeholder: "Select language",
3523
+ filterOption: (query, option) => option.label.toLowerCase().indexOf(query.toLowerCase()) > -1 || option.value.toLowerCase().indexOf(query.toLowerCase()) > -1,
3524
+ openButton: !0,
3525
+ renderValue: (value) => {
3526
+ var _a;
3527
+ return ((_a = SUBTITLE_LANGUAGES[track.type].find((l) => l.value === value)) == null ? void 0 : _a.label) || value;
3528
+ },
3529
+ renderOption: (option) => /* @__PURE__ */ jsx(Card, { "data-as": "button", padding: 3, radius: 2, tone: "inherit", children: /* @__PURE__ */ jsxs(Text, { size: 2, textOverflow: "ellipsis", children: [
3530
+ option.label,
3531
+ " (",
3532
+ option.value,
3533
+ ")"
3534
+ ] }) })
3535
+ }
3536
+ ),
3537
+ /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
3538
+ Button,
3539
+ {
3540
+ icon: TrashIcon,
3541
+ tone: "critical",
3542
+ mode: "ghost",
3543
+ onClick: () => dispatchTrackAction({ subAction: "delete" }),
3544
+ text: "Delete"
3545
+ }
3546
+ ) })
3547
+ ] }) });
3548
+ }
3549
+ function TextTracksEditor({
3550
+ canAutoGenerate,
3551
+ tracks,
3552
+ dispatch
3553
+ }) {
3554
+ return TRACK_TYPES.filter(
3555
+ ({ value }) => !(value === "autogenerated" && !canAutoGenerate)
3556
+ ).length === 0 ? null : /* @__PURE__ */ jsx(
3557
+ FormField$2,
3558
+ {
3559
+ title: "Captions & Subtitles",
3560
+ description: "Provide text tracks for video accessibility.",
3561
+ children: /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
3562
+ tracks.map((track) => /* @__PURE__ */ jsx(
3563
+ TrackEditor,
3564
+ {
3565
+ canAutoGenerate,
3566
+ track,
3567
+ dispatch
3568
+ },
3569
+ track._id
3570
+ )),
3571
+ /* @__PURE__ */ jsx(
3572
+ Button,
3573
+ {
3574
+ icon: AddIcon,
3575
+ onClick: () => dispatch({ action: "track", id: uuid(), subAction: "add" }),
3576
+ text: "New caption/subtitle",
3577
+ mode: "ghost"
3578
+ }
3579
+ )
3580
+ ] })
3581
+ }
3582
+ );
3583
+ }
3584
+ const ENCODING_OPTIONS = [
3585
+ { value: "smart", label: "Smart" },
3586
+ { value: "baseline", label: "Baseline" }
3587
+ ], RESOLUTION_TIERS = [
3588
+ { value: "1080p", label: "1080p" },
3589
+ { value: "1440p", label: "1440p (2k)" },
3590
+ { value: "2160p", label: "2160p (4k)" }
3591
+ ];
3592
+ function UploadConfiguration({
3593
+ stagedUpload,
3594
+ secrets,
3595
+ pluginConfig,
3596
+ startUpload,
3597
+ onClose
3598
+ }) {
3599
+ var _a;
3600
+ const id = useId(), autoTextTracks = useRef(
3601
+ pluginConfig.encoding_tier === "smart" && ((_a = pluginConfig.defaultAutogeneratedSubtitleLangs) == null ? void 0 : _a.map(
3602
+ (language_code) => ({
3603
+ _id: uuid(),
3604
+ type: "autogenerated",
3605
+ language_code,
3606
+ name: LanguagesList.getNativeName(language_code)
3607
+ })
3608
+ )) || []
3609
+ ).current, [config, dispatch] = useReducer(
3610
+ (prev, action) => {
3611
+ var _a2;
3612
+ switch (action.action) {
3613
+ case "encoding_tier":
3614
+ return action.value === "baseline" ? Object.assign({}, prev, {
3615
+ encoding_tier: action.value,
3616
+ mp4_support: "none",
3617
+ max_resolution_tier: "1080p",
3618
+ text_tracks: (_a2 = prev.text_tracks) == null ? void 0 : _a2.filter(({ type: type2 }) => type2 !== "autogenerated")
3619
+ }) : Object.assign({}, prev, {
3620
+ encoding_tier: action.value,
3621
+ mp4_support: pluginConfig.mp4_support,
3622
+ max_resolution_tier: pluginConfig.max_resolution_tier,
3623
+ text_tracks: [...autoTextTracks, ...prev.text_tracks || []]
3624
+ });
3625
+ case "mp4_support":
3626
+ case "max_resolution_tier":
3627
+ case "normalize_audio":
3628
+ case "signed":
3629
+ return Object.assign({}, prev, { [action.action]: action.value });
3630
+ case "track": {
3631
+ const text_tracks = [...prev.text_tracks], target_track_i = text_tracks.findIndex(({ _id: _id2 }) => _id2 === action.id);
3632
+ switch (action.subAction) {
3633
+ case "add":
3634
+ if (target_track_i !== -1)
3635
+ break;
3636
+ text_tracks.push(
3637
+ prev.encoding_tier === "smart" ? { _id: action.id, type: "autogenerated" } : { _id: action.id, type: "subtitles" }
3638
+ );
3639
+ break;
3640
+ case "update":
3641
+ if (target_track_i === -1)
3642
+ break;
3643
+ text_tracks[target_track_i] = {
3644
+ ...text_tracks[target_track_i],
3645
+ ...action.value
3646
+ };
3647
+ break;
3648
+ case "delete":
3649
+ if (target_track_i === -1)
3650
+ break;
3651
+ text_tracks.splice(target_track_i, 1);
3652
+ break;
3653
+ }
3654
+ return Object.assign({}, prev, { text_tracks });
3655
+ }
3656
+ default:
3657
+ return prev;
3658
+ }
3659
+ },
3660
+ {
3661
+ encoding_tier: pluginConfig.encoding_tier,
3662
+ max_resolution_tier: pluginConfig.max_resolution_tier,
3663
+ mp4_support: pluginConfig.mp4_support,
3664
+ signed: secrets.enableSignedUrls && pluginConfig.defaultSigned,
3665
+ normalize_audio: pluginConfig.normalize_audio,
3666
+ text_tracks: autoTextTracks
3667
+ }
3668
+ ), { disableTextTrackConfig, disableUploadConfig } = pluginConfig, skipConfig = disableTextTrackConfig && disableUploadConfig;
3669
+ if (useEffect(() => {
3670
+ skipConfig && startUpload(formatUploadConfig(config));
3671
+ }, []), skipConfig)
3672
+ return null;
3673
+ const maxSupportedResolution = RESOLUTION_TIERS.findIndex(
3674
+ (rt) => rt.value === pluginConfig.max_resolution_tier
3675
+ );
3676
+ return /* @__PURE__ */ jsx(
3677
+ Dialog,
3678
+ {
3679
+ open: !0,
3680
+ id: "upload-configuration",
3681
+ zOffset: 1e3,
3682
+ width: 1,
3683
+ header: "Configure Mux Upload",
3684
+ onClose,
3685
+ children: /* @__PURE__ */ jsxs(Stack, { padding: 4, space: 2, children: [
3686
+ /* @__PURE__ */ jsx(Label$1, { size: 3, children: "FILE TO UPLOAD" }),
3687
+ /* @__PURE__ */ jsx(
3688
+ Card,
3689
+ {
3690
+ tone: "transparent",
3691
+ border: !0,
3692
+ padding: 3,
3693
+ paddingY: 4,
3694
+ style: { borderRadius: "0.1865rem" },
3695
+ children: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3696
+ /* @__PURE__ */ jsx(DocumentVideoIcon, { fontSize: "2em" }),
3697
+ /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
3698
+ /* @__PURE__ */ jsx(Text, { textOverflow: "ellipsis", as: "h2", size: 3, children: stagedUpload.type === "file" ? stagedUpload.files[0].name : stagedUpload.url }),
3699
+ /* @__PURE__ */ jsx(Text, { as: "p", size: 1, muted: !0, children: stagedUpload.type === "file" ? `Direct File Upload (${formatBytes(stagedUpload.files[0].size)})` : "File From URL (Unknown size)" })
3700
+ ] })
3701
+ ] })
3702
+ }
3703
+ ),
3704
+ !disableUploadConfig && /* @__PURE__ */ jsxs(Stack, { space: 3, paddingBottom: 2, children: [
3705
+ /* @__PURE__ */ jsx(
3706
+ FormField$2,
3707
+ {
3708
+ title: "Encoding Tier",
3709
+ description: /* @__PURE__ */ jsxs(Fragment, { children: [
3710
+ "The encoding tier informs the cost, quality, and available platform features for the asset.",
3711
+ " ",
3712
+ /* @__PURE__ */ jsx(
3713
+ "a",
3714
+ {
3715
+ href: "https://docs.mux.com/guides/use-encoding-tiers",
3716
+ target: "_blank",
3717
+ rel: "noopener noreferrer",
3718
+ children: "See the Mux guide for more details."
3719
+ }
3720
+ )
3721
+ ] }),
3722
+ children: /* @__PURE__ */ jsx(Flex, { gap: 3, children: ENCODING_OPTIONS.map(({ value, label }) => {
3723
+ const inputId = `${id}--encodingtier-${value}`;
3724
+ return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
3725
+ /* @__PURE__ */ jsx(
3726
+ Radio,
3727
+ {
3728
+ checked: config.encoding_tier === value,
3729
+ name: "asset-encodingtier",
3730
+ onChange: (e) => dispatch({
3731
+ action: "encoding_tier",
3732
+ value: e.currentTarget.value
3733
+ }),
3734
+ value,
3735
+ id: inputId
3736
+ }
3737
+ ),
3738
+ /* @__PURE__ */ jsx(Text, { as: "label", htmlFor: inputId, children: label })
3739
+ ] }, value);
3740
+ }) })
3741
+ }
3742
+ ),
3743
+ config.encoding_tier === "smart" && maxSupportedResolution > 0 && /* @__PURE__ */ jsx(
3744
+ FormField$2,
3745
+ {
3746
+ title: "Resolution Tier",
3747
+ description: /* @__PURE__ */ jsxs(Fragment, { children: [
3748
+ "The maximum",
3749
+ " ",
3750
+ /* @__PURE__ */ jsx(
3751
+ "a",
3752
+ {
3753
+ href: "https://docs.mux.com/api-reference#video/operation/create-direct-upload",
3754
+ target: "_blank",
3755
+ rel: "noopener noreferrer",
3756
+ children: "resolution_tier"
3757
+ }
3758
+ ),
3759
+ " ",
3760
+ "your asset is encoded, stored, and streamed at."
3761
+ ] }),
3762
+ children: /* @__PURE__ */ jsx(Flex, { gap: 3, wrap: "wrap", children: RESOLUTION_TIERS.map(({ value, label }, index) => {
3763
+ const inputId = `${id}--type-${value}`;
3764
+ return index > maxSupportedResolution ? null : /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
3765
+ /* @__PURE__ */ jsx(
3766
+ Radio,
3767
+ {
3768
+ checked: config.max_resolution_tier === value,
3769
+ name: "asset-resolutiontier",
3770
+ onChange: (e) => dispatch({
3771
+ action: "max_resolution_tier",
3772
+ value: e.currentTarget.value
3773
+ }),
3774
+ value,
3775
+ id: inputId
3776
+ }
3777
+ ),
3778
+ /* @__PURE__ */ jsx(Text, { as: "label", htmlFor: inputId, children: label })
3779
+ ] }, value);
3780
+ }) })
3781
+ }
3782
+ ),
3783
+ (secrets.enableSignedUrls || config.encoding_tier === "smart") && /* @__PURE__ */ jsx(FormField$2, { title: "Additional Configuration", children: /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
3784
+ secrets.enableSignedUrls && /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
3785
+ /* @__PURE__ */ jsx(
3786
+ Checkbox,
3787
+ {
3788
+ id: `${id}--signed`,
3789
+ style: { display: "block" },
3790
+ name: "signed",
3791
+ required: !0,
3792
+ checked: config.signed,
3793
+ onChange: (e) => dispatch({
3794
+ action: "signed",
3795
+ value: e.currentTarget.checked
3796
+ })
3797
+ }
3798
+ ),
3799
+ /* @__PURE__ */ jsx(Text, { children: /* @__PURE__ */ jsx("label", { htmlFor: `${id}--signed`, children: "Signed playback URL" }) })
3800
+ ] }),
3801
+ config.encoding_tier === "smart" && /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
3802
+ /* @__PURE__ */ jsx(
3803
+ Checkbox,
3804
+ {
3805
+ id: `${id}--mp4_support`,
3806
+ style: { display: "block" },
3807
+ name: "mp4_support",
3808
+ required: !0,
3809
+ checked: config.mp4_support === "standard",
3810
+ onChange: (e) => dispatch({
3811
+ action: "mp4_support",
3812
+ value: e.currentTarget.checked ? "standard" : "none"
3813
+ })
3814
+ }
3815
+ ),
3816
+ /* @__PURE__ */ jsx(Text, { children: /* @__PURE__ */ jsx("label", { htmlFor: `${id}--mp4_support`, children: "MP4 support (allow downloading)" }) })
3817
+ ] })
3818
+ ] }) })
3819
+ ] }),
3820
+ !disableTextTrackConfig && /* @__PURE__ */ jsx(
3821
+ TextTracksEditor,
3822
+ {
3823
+ canAutoGenerate: config.encoding_tier === "smart",
3824
+ tracks: config.text_tracks,
3825
+ dispatch
3826
+ }
3827
+ ),
3828
+ /* @__PURE__ */ jsx(
3829
+ Button,
3830
+ {
3831
+ icon: UploadIcon,
3832
+ text: "Upload",
3833
+ tone: "positive",
3834
+ onClick: () => startUpload(formatUploadConfig(config))
3835
+ }
3836
+ )
3837
+ ] })
3838
+ }
3839
+ );
3840
+ }
3841
+ function formatUploadConfig(config) {
3842
+ const generated_subtitles = config.text_tracks.filter(isAutogeneratedTrack).map((track) => ({
3843
+ name: track.name,
3844
+ language_code: track.language_code
3845
+ }));
3846
+ return {
3847
+ input: [
3848
+ {
3849
+ type: "video",
3850
+ generated_subtitles: generated_subtitles.length > 0 ? generated_subtitles : void 0
3851
+ },
3852
+ ...config.text_tracks.filter(isCustomTextTrack).reduce(
3853
+ (acc, track) => (track.language_code && track.file && track.name && acc.push({
3854
+ url: track.file.contents,
3855
+ type: "text",
3856
+ text_type: track.type === "subtitles" ? "subtitles" : void 0,
3857
+ language_code: track.language_code,
3858
+ name: track.name,
3859
+ closed_captions: track.type === "captions"
3860
+ }), acc),
3861
+ []
3862
+ )
3863
+ ],
3864
+ mp4_support: config.mp4_support,
3865
+ playback_policy: config.signed ? ["public", "signed"] : ["public"],
3866
+ max_resolution_tier: config.max_resolution_tier,
3867
+ encoding_tier: config.encoding_tier,
3868
+ normalize_audio: config.normalize_audio
3869
+ };
3870
+ }
3871
+ function withFocusRing(component) {
3872
+ return styled(component)((props) => {
3873
+ const border = {
3874
+ width: props.$border ? 1 : 0,
3875
+ color: "var(--card-border-color)"
3876
+ };
3877
+ return css`
3878
+ --card-focus-box-shadow: ${focusRingBorderStyle(border)};
3879
+
3880
+ border-radius: ${rem(props.theme.sanity.radius[1])};
3881
+ outline: none;
3882
+ box-shadow: var(--card-focus-box-shadow);
3883
+
3884
+ &:focus {
3885
+ --card-focus-box-shadow: ${focusRingStyle({
3886
+ base: props.theme.sanity.color.base,
3887
+ border,
3888
+ focusRing: props.theme.sanity.focusRing
3889
+ })};
3890
+ }
3891
+ `;
3892
+ });
3893
+ }
3894
+ const ctrlKey = 17, cmdKey = 91, UploadCardWithFocusRing = withFocusRing(Card), UploadCard = forwardRef(
3895
+ ({ children, tone, onPaste, onDrop, onDragEnter, onDragLeave, onDragOver }, forwardedRef) => {
3896
+ const ctrlDown = useRef(!1), inputRef = useRef(null), handleKeyDown = useCallback((event) => {
3897
+ (event.keyCode == ctrlKey || event.keyCode == cmdKey) && (ctrlDown.current = !0), ctrlDown.current && event.keyCode == 86 && inputRef.current.focus();
3898
+ }, []), handleKeyUp = useCallback((event) => {
3899
+ (event.keyCode == ctrlKey || event.keyCode == cmdKey) && (ctrlDown.current = !1);
3900
+ }, []);
3901
+ return /* @__PURE__ */ jsxs(
3902
+ UploadCardWithFocusRing,
3903
+ {
3904
+ tone,
3905
+ ref: forwardedRef,
3906
+ padding: 0,
3907
+ radius: 2,
3908
+ shadow: 0,
3909
+ tabIndex: 0,
3910
+ onKeyDown: handleKeyDown,
3911
+ onKeyUp: handleKeyUp,
3912
+ onPaste,
3913
+ onDrop,
3914
+ onDragEnter,
3915
+ onDragLeave,
3916
+ onDragOver,
3917
+ children: [
3918
+ /* @__PURE__ */ jsx(HiddenInput$1, { ref: inputRef, onPaste }),
3919
+ children
3920
+ ]
3921
+ }
3922
+ );
3923
+ }
3924
+ ), HiddenInput$1 = styled.input.attrs({ type: "text" })`
3925
+ position: absolute;
3926
+ border: 0;
3927
+ color: white;
3928
+ opacity: 0;
3929
+
3930
+ &:focus {
3931
+ outline: none;
3932
+ }
3933
+ `, HiddenInput = styled.input`
3934
+ overflow: hidden;
3935
+ width: 0.1px;
3936
+ height: 0.1px;
3937
+ opacity: 0;
3938
+ position: absolute;
3939
+ z-index: -1;
3940
+ `, Label = styled.label`
3941
+ position: relative;
3942
+ `, FileInputButton = ({ onSelect, accept, ...props }) => {
3943
+ const inputId = `FileSelect${useId()}`, inputRef = useRef(null), handleSelect = useCallback(
3944
+ (event) => {
3945
+ onSelect && onSelect(event.target.files);
3946
+ },
3947
+ [onSelect]
3948
+ ), handleButtonClick = useCallback(() => {
3949
+ var _a;
3950
+ return (_a = inputRef.current) == null ? void 0 : _a.click();
3951
+ }, []);
3952
+ return /* @__PURE__ */ jsxs(Label, { htmlFor: inputId, children: [
3953
+ /* @__PURE__ */ jsx(
3954
+ HiddenInput,
3955
+ {
3956
+ accept: accept || "video/*",
3957
+ ref: inputRef,
3958
+ tabIndex: 0,
3959
+ type: "file",
3960
+ id: inputId,
3961
+ onChange: handleSelect,
3962
+ value: ""
3963
+ }
3964
+ ),
3965
+ /* @__PURE__ */ jsx(
3966
+ Button,
3967
+ {
3968
+ onClick: handleButtonClick,
3969
+ mode: "default",
3970
+ tone: "primary",
3971
+ style: { width: "100%" },
3972
+ ...props
3973
+ }
3974
+ )
3975
+ ] });
3976
+ };
3977
+ function UploadPlaceholder(props) {
3978
+ const { setDialogState, readOnly, onSelect, hovering, needsSetup } = props, handleBrowse = useCallback(() => setDialogState("select-video"), [setDialogState]), handleConfigureApi = useCallback(() => setDialogState("secrets"), [setDialogState]);
3979
+ return /* @__PURE__ */ jsx(
3980
+ Card,
3981
+ {
3982
+ sizing: "border",
3983
+ tone: readOnly ? "transparent" : "inherit",
3984
+ border: !0,
3985
+ radius: 2,
3986
+ paddingX: 3,
3987
+ paddingY: 1,
3988
+ style: hovering ? { borderColor: "transparent" } : void 0,
3989
+ children: /* @__PURE__ */ jsxs(
3990
+ Flex,
3991
+ {
3992
+ align: "center",
3993
+ justify: "space-between",
3994
+ gap: 4,
3995
+ direction: ["column", "column", "row"],
3996
+ paddingY: 2,
3997
+ sizing: "border",
3998
+ children: [
3999
+ /* @__PURE__ */ jsxs(Flex, { align: "center", justify: "flex-start", gap: 2, flex: 1, children: [
4000
+ /* @__PURE__ */ jsx(Flex, { justify: "center", children: /* @__PURE__ */ jsx(Text, { muted: !0, children: /* @__PURE__ */ jsx(DocumentVideoIcon, {}) }) }),
4001
+ /* @__PURE__ */ jsx(Flex, { justify: "center", children: /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "Drag video or paste URL here" }) })
4002
+ ] }),
4003
+ /* @__PURE__ */ jsxs(Inline, { space: 2, children: [
4004
+ /* @__PURE__ */ jsx(
4005
+ FileInputButton,
4006
+ {
4007
+ mode: "bleed",
4008
+ tone: "default",
4009
+ icon: UploadIcon,
4010
+ text: "Upload",
4011
+ onSelect
4012
+ }
4013
+ ),
4014
+ /* @__PURE__ */ jsx(Button, { mode: "bleed", icon: SearchIcon, text: "Select", onClick: handleBrowse }),
4015
+ /* @__PURE__ */ jsx(
4016
+ Button,
4017
+ {
4018
+ padding: 3,
4019
+ radius: 3,
4020
+ tone: needsSetup ? "critical" : void 0,
4021
+ onClick: handleConfigureApi,
4022
+ icon: PlugIcon,
4023
+ mode: "bleed",
4024
+ title: "Configure plugin credentials"
4025
+ }
4026
+ )
4027
+ ] })
4028
+ ]
4029
+ }
4030
+ )
4031
+ }
4032
+ );
4033
+ }
4034
+ const INITIAL_STATE = {
4035
+ stagedUpload: null,
4036
+ uploadStatus: null,
4037
+ error: null
4038
+ };
4039
+ function Uploader(props) {
4040
+ var _a;
4041
+ const toast = useToast(), containerRef = useRef(null), dragEnteredEls = useRef([]), [dragState, setDragState] = useState(null), cancelUploadButton = useRef(
4042
+ (() => {
4043
+ const events$ = new Subject();
4044
+ return {
4045
+ observable: events$.asObservable(),
4046
+ handleClick: (event) => events$.next(event)
4047
+ };
4048
+ })()
4049
+ ).current, uploadRef = useRef(null), [state, dispatch] = useReducer(
4050
+ (prev, action) => {
4051
+ var _a2, _b;
4052
+ switch (action.action) {
4053
+ case "stageUpload":
4054
+ return Object.assign({}, INITIAL_STATE, { stagedUpload: action.input });
4055
+ case "commitUpload":
4056
+ return Object.assign({}, prev, { uploadStatus: { progress: 0 } });
4057
+ case "progressInfo": {
4058
+ const { type: type2, action: _, ...payload } = action;
4059
+ return Object.assign({}, prev, {
4060
+ uploadStatus: {
4061
+ ...prev.uploadStatus,
4062
+ progress: prev.uploadStatus.progress,
4063
+ ...payload
4064
+ }
4065
+ });
4066
+ }
4067
+ case "progress":
4068
+ return Object.assign({}, prev, {
4069
+ uploadStatus: {
4070
+ ...prev.uploadStatus,
4071
+ progress: action.percent
4072
+ }
4073
+ });
4074
+ case "reset":
4075
+ case "complete":
4076
+ return (_a2 = uploadRef.current) == null || _a2.unsubscribe(), uploadRef.current = null, INITIAL_STATE;
4077
+ case "error":
4078
+ return (_b = uploadRef.current) == null || _b.unsubscribe(), uploadRef.current = null, Object.assign({}, INITIAL_STATE, { error: action.error });
4079
+ default:
4080
+ return prev;
4081
+ }
4082
+ },
4083
+ {
4084
+ stagedUpload: null,
4085
+ uploadStatus: null,
4086
+ error: null
4087
+ }
4088
+ );
4089
+ useEffect(() => () => {
4090
+ uploadRef.current && !uploadRef.current.closed && uploadRef.current.unsubscribe();
4091
+ }, []);
4092
+ const startUpload = (settings) => {
4093
+ const { stagedUpload } = state;
4094
+ if (!stagedUpload || uploadRef.current)
4095
+ return;
4096
+ dispatch({ action: "commitUpload" });
4097
+ let uploadObservable;
4098
+ switch (stagedUpload.type) {
4099
+ case "url":
4100
+ uploadObservable = uploadUrl({
4101
+ client: props.client,
4102
+ url: stagedUpload.url,
4103
+ settings
4104
+ });
4105
+ break;
4106
+ case "file":
4107
+ uploadObservable = uploadFile({
4108
+ client: props.client,
4109
+ file: stagedUpload.files[0],
4110
+ settings
4111
+ }).pipe(
4112
+ takeUntil(
4113
+ cancelUploadButton.observable.pipe(
4114
+ tap(() => {
4115
+ var _a2;
4116
+ (_a2 = state.uploadStatus) != null && _a2.uuid && props.client.delete(state.uploadStatus.uuid);
4117
+ })
4118
+ )
4119
+ )
4120
+ );
4121
+ break;
4122
+ }
4123
+ uploadRef.current = uploadObservable.subscribe({
4124
+ next: (event) => {
4125
+ switch (event.type) {
4126
+ case "uuid":
4127
+ case "file":
4128
+ case "url":
4129
+ dispatch({ action: "progressInfo", ...event });
4130
+ break;
4131
+ case "progress":
4132
+ dispatch({ action: "progress", percent: event.percent });
4133
+ break;
4134
+ case "success":
4135
+ dispatch({ action: "progress", percent: 100 }), props.onChange(
4136
+ PatchEvent.from([
4137
+ setIfMissing({ asset: {} }),
4138
+ set({ _type: "reference", _weak: !0, _ref: event.asset._id }, ["asset"])
4139
+ ])
4140
+ );
4141
+ break;
4142
+ }
4143
+ },
4144
+ complete: () => dispatch({ action: "complete" }),
4145
+ error: (error) => dispatch({ action: "error", error })
4146
+ });
4147
+ }, handleUpload = (files2) => {
4148
+ dispatch({
4149
+ action: "stageUpload",
4150
+ input: { type: "file", files: files2 }
4151
+ });
4152
+ }, handlePaste = (event) => {
4153
+ event.preventDefault(), event.stopPropagation();
4154
+ const url = (event.clipboardData || window.clipboardData).getData("text");
4155
+ if (!isValidUrl(url)) {
4156
+ toast.push({ status: "error", title: "Invalid URL for Mux video input." });
4157
+ return;
4158
+ }
4159
+ dispatch({ action: "stageUpload", input: { type: "url", url } });
4160
+ }, handleDrop = (event) => {
4161
+ setDragState(null), event.preventDefault(), event.stopPropagation(), extractDroppedFiles(event.nativeEvent.dataTransfer).then((files2) => {
4162
+ dispatch({
4163
+ action: "stageUpload",
4164
+ input: { type: "file", files: files2 }
4165
+ });
4166
+ });
4167
+ }, handleDragOver = (event) => {
4168
+ event.preventDefault(), event.stopPropagation();
4169
+ }, handleDragEnter = (event) => {
4170
+ var _a2, _b;
4171
+ event.stopPropagation(), dragEnteredEls.current.push(event.target);
4172
+ const type2 = (_b = (_a2 = event.dataTransfer.items) == null ? void 0 : _a2[0]) == null ? void 0 : _b.type;
4173
+ setDragState(type2 != null && type2.startsWith("video/") ? "valid" : "invalid");
4174
+ }, handleDragLeave = (event) => {
4175
+ event.stopPropagation();
4176
+ const idx = dragEnteredEls.current.indexOf(event.target);
4177
+ idx > -1 && dragEnteredEls.current.splice(idx, 1), dragEnteredEls.current.length === 0 && setDragState(null);
4178
+ };
4179
+ if (state.error !== null) {
4180
+ const error = { state };
4181
+ return /* @__PURE__ */ jsxs(Flex, { gap: 3, direction: "column", justify: "center", align: "center", children: [
4182
+ /* @__PURE__ */ jsx(Text, { size: 5, muted: !0, children: /* @__PURE__ */ jsx(ErrorOutlineIcon, {}) }),
4183
+ /* @__PURE__ */ jsx(Text, { children: "Something went wrong" }),
4184
+ error instanceof Error && error.message && /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: error.message }),
4185
+ /* @__PURE__ */ jsx(Button, { text: "Upload another file", onClick: () => dispatch({ action: "reset" }) })
4186
+ ] });
4187
+ }
4188
+ if (state.uploadStatus !== null) {
4189
+ const { uploadStatus } = state;
4190
+ return /* @__PURE__ */ jsx(
4191
+ UploadProgress,
4192
+ {
4193
+ onCancel: cancelUploadButton.handleClick,
4194
+ progress: uploadStatus.progress,
4195
+ filename: ((_a = uploadStatus.file) == null ? void 0 : _a.name) || uploadStatus.url
4196
+ }
4197
+ );
4198
+ }
4199
+ if (state.stagedUpload !== null)
4200
+ return /* @__PURE__ */ jsx(
4201
+ UploadConfiguration,
4202
+ {
4203
+ stagedUpload: state.stagedUpload,
4204
+ pluginConfig: props.config,
4205
+ secrets: props.secrets,
4206
+ startUpload,
4207
+ onClose: () => dispatch({ action: "reset" })
4208
+ }
4209
+ );
4210
+ let tone;
4211
+ return dragState && (tone = dragState === "valid" ? "positive" : "critical"), /* @__PURE__ */ jsxs(Fragment, { children: [
4212
+ /* @__PURE__ */ jsx(
4213
+ UploadCard,
4214
+ {
4215
+ tone,
4216
+ onDrop: handleDrop,
4217
+ onDragOver: handleDragOver,
4218
+ onDragLeave: handleDragLeave,
4219
+ onDragEnter: handleDragEnter,
4220
+ onPaste: handlePaste,
4221
+ ref: containerRef,
4222
+ children: props.asset ? /* @__PURE__ */ jsx(
4223
+ Player,
4224
+ {
4225
+ readOnly: props.readOnly,
4226
+ asset: props.asset,
4227
+ onChange: props.onChange,
4228
+ buttons: /* @__PURE__ */ jsx(
4229
+ PlayerActionsMenu$1,
4230
+ {
4231
+ asset: props.asset,
4232
+ dialogState: props.dialogState,
4233
+ setDialogState: props.setDialogState,
4234
+ onChange: props.onChange,
4235
+ onSelect: handleUpload,
4236
+ readOnly: props.readOnly
4237
+ }
4238
+ )
4239
+ }
4240
+ ) : /* @__PURE__ */ jsx(
4241
+ UploadPlaceholder,
4242
+ {
4243
+ hovering: dragState !== null,
4244
+ onSelect: handleUpload,
4245
+ readOnly: !!props.readOnly,
4246
+ setDialogState: props.setDialogState,
4247
+ needsSetup: props.needsSetup
4248
+ }
4249
+ )
4250
+ }
4251
+ ),
4252
+ props.dialogState === "select-video" && /* @__PURE__ */ jsx(
4253
+ InputBrowser,
4254
+ {
4255
+ asset: props.asset,
4256
+ onChange: props.onChange,
4257
+ setDialogState: props.setDialogState
4258
+ }
4259
+ )
4260
+ ] });
4261
+ }
4262
+ const Input = (props) => {
4263
+ var _a;
4264
+ const client = useClient(), secretDocumentValues = useSecretsDocumentValues(), assetDocumentValues = useAssetDocumentValues((_a = props.value) == null ? void 0 : _a.asset), poll = useMuxPolling(props.readOnly ? void 0 : (assetDocumentValues == null ? void 0 : assetDocumentValues.value) || void 0), [dialogState, setDialogState] = useDialogState(), error = secretDocumentValues.error || assetDocumentValues.error || poll.error;
4265
+ if (error)
4266
+ throw error;
4267
+ const isLoading = secretDocumentValues.isLoading || assetDocumentValues.isLoading;
4268
+ return /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(ErrorBoundaryCard$1, { schemaType: props.schemaType, children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(InputFallback, {}), children: isLoading ? /* @__PURE__ */ jsx(InputFallback, {}) : /* @__PURE__ */ jsxs(Fragment, { children: [
4269
+ secretDocumentValues.value.needsSetup && !assetDocumentValues.value ? /* @__PURE__ */ jsx(Onboard, { setDialogState }) : /* @__PURE__ */ jsx(
4270
+ Uploader,
4271
+ {
4272
+ ...props,
4273
+ config: props.config,
4274
+ onChange: props.onChange,
4275
+ client,
4276
+ secrets: secretDocumentValues.value.secrets,
4277
+ asset: assetDocumentValues.value,
4278
+ dialogState,
4279
+ setDialogState,
4280
+ needsSetup: secretDocumentValues.value.needsSetup
4281
+ }
4282
+ ),
4283
+ dialogState === "secrets" && /* @__PURE__ */ jsx(
4284
+ ConfigureApi$1,
4285
+ {
4286
+ setDialogState,
4287
+ secrets: secretDocumentValues.value.secrets
4288
+ }
4289
+ )
4290
+ ] }) }) }) });
4291
+ };
4292
+ var Input$1 = memo(Input);
4293
+ function muxVideoCustomRendering(config) {
4294
+ return {
4295
+ components: {
4296
+ input: (props) => /* @__PURE__ */ jsx(Input$1, { config: { ...config, ...props.schemaType.options }, ...props })
4297
+ },
4298
+ preview: {
4299
+ select: {
4300
+ filename: "asset.filename",
4301
+ playbackId: "asset.playbackId",
4302
+ status: "asset.status",
4303
+ assetId: "asset.assetId",
4304
+ thumbTime: "asset.thumbTime",
4305
+ data: "asset.data"
4306
+ },
4307
+ prepare: (asset) => {
4308
+ const { filename, playbackId, status } = asset;
4309
+ return {
4310
+ title: filename || playbackId || "",
4311
+ subtitle: status ? `status: ${status}` : null,
4312
+ media: asset.playbackId ? /* @__PURE__ */ jsx(VideoThumbnail, { asset, width: 64 }) : null
4313
+ };
4314
+ }
4315
+ }
4316
+ };
4317
+ }
4318
+ const muxVideo = {
4319
+ name: "mux.video",
4320
+ type: "object",
4321
+ title: "Video asset reference",
4322
+ fields: [
4323
+ {
4324
+ title: "Video",
4325
+ name: "asset",
4326
+ type: "reference",
4327
+ weak: !0,
4328
+ to: [{ type: "mux.videoAsset" }]
4329
+ }
4330
+ ]
4331
+ }, muxVideoAsset = {
4332
+ name: "mux.videoAsset",
4333
+ type: "object",
4334
+ title: "Video asset",
4335
+ fields: [
4336
+ {
4337
+ type: "string",
4338
+ name: "status"
4339
+ },
4340
+ {
4341
+ type: "string",
4342
+ name: "assetId"
4343
+ },
4344
+ {
4345
+ type: "string",
4346
+ name: "playbackId"
4347
+ },
4348
+ {
4349
+ type: "string",
4350
+ name: "filename"
4351
+ },
4352
+ {
4353
+ type: "number",
4354
+ name: "thumbTime"
4355
+ }
4356
+ ]
4357
+ }, defaultConfig = {
4358
+ mp4_support: "none",
4359
+ encoding_tier: "smart",
4360
+ max_resolution_tier: "1080p",
4361
+ normalize_audio: !1,
4362
+ defaultSigned: !1,
4363
+ tool: DEFAULT_TOOL_CONFIG
4364
+ }, muxInput = definePlugin((userConfig) => {
4365
+ const config = { ...defaultConfig, ...userConfig || {} };
4366
+ return {
4367
+ name: "mux-input",
4368
+ schema: {
4369
+ types: [
4370
+ muxVideoAsset,
4371
+ {
4372
+ ...muxVideo,
4373
+ ...muxVideoCustomRendering(config)
4374
+ }
4375
+ ]
4376
+ },
4377
+ tools: config.tool === !1 ? void 0 : [createStudioTool(config)]
4378
+ };
4379
+ });
4380
+ export {
4381
+ defaultConfig,
4382
+ muxInput
4383
+ };
4384
+ //# sourceMappingURL=index.esm.js.map