sanity-plugin-mux-input 2.2.4 → 2.3.1

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