sanity-plugin-mux-input 2.11.1 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -198,21 +198,65 @@ sanity documents delete secrets.mux
198
198
 
199
199
  More information on signed URLs is available on Mux's [docs](https://docs.mux.com/docs/headless-cms-sanity#advanced-signed-urls)
200
200
 
201
- ### MP4 support (downloadable videos or offline viewing)
201
+ ### Static Renditions (downloadable videos or offline viewing)
202
202
 
203
- To enable [static MP4 renditions](https://docs.mux.com/guides/video/enable-static-mp4-renditions), add `mp4_support: 'standard'` to the `options` of your `mux.video` schema type.
203
+ To enable [static MP4 renditions](https://docs.mux.com/guides/video/enable-static-mp4-renditions), add `static_renditions` to your plugin configuration. This allows users to download videos for offline viewing.
204
+
205
+ #### Standard Mode (Recommended)
204
206
 
205
207
  ```js
206
208
  import {muxInput} from 'sanity-plugin-mux-input'
207
209
 
208
210
  export default defineConfig({
209
- plugins: [muxInput({mp4_support: 'standard'})],
211
+ plugins: [
212
+ muxInput({
213
+ static_renditions: ['highest'], // Enables MP4 downloads at the highest quality (up to 4K)
214
+ // or
215
+ static_renditions: ['highest', 'audio-only'], // Also includes audio-only (M4A) downloads
216
+ }),
217
+ ],
210
218
  })
211
219
  ```
212
220
 
213
- If MP4 support is enabled in the plugin's configuration, editors can still choose to enable MP4 renditions on a per-video basis when uploading new assets.
221
+ **Standard mode options:**
222
+ - `'highest'`: Produces an MP4 file with video resolution up to 4K (2160p)
223
+ - `'audio-only'`: Produces an M4A (audio-only MP4) file
224
+
225
+ #### Advanced Mode (Specific Resolutions)
226
+
227
+ For more control, you can specify exact resolutions:
228
+
229
+ ```js
230
+ import {muxInput} from 'sanity-plugin-mux-input'
231
+
232
+ export default defineConfig({
233
+ plugins: [
234
+ muxInput({
235
+ static_renditions: ['1080p', '720p', 'audio-only'],
236
+ }),
237
+ ],
238
+ })
239
+ ```
240
+
241
+ **Advanced mode options:**
242
+ - Specific resolutions: `'270p'`, `'360p'`, `'480p'`, `'540p'`, `'720p'`, `'1080p'`, `'1440p'`, `'2160p'`
243
+ - `'audio-only'`: M4A file
244
+
245
+ **Important notes:**
246
+ - You cannot mix `'highest'` with specific resolutions (e.g., `['highest', '1080p']` is invalid)
247
+ - Mux will not upscale videos - renditions requiring upscaling are automatically skipped
248
+ - When uploading new assets, editors can choose different rendition settings on a per-video basis
249
+
250
+ #### Backward Compatibility
251
+
252
+ The deprecated `mp4_support` field is still supported for backward compatibility:
253
+
254
+ ```js
255
+ // ⚠️ Deprecated - use static_renditions instead
256
+ muxInput({mp4_support: 'standard'}) // Equivalent to static_renditions: ['highest']
257
+ ```
214
258
 
215
- MP4 allows users to download videos for later or offline viewing. More information can be found on Mux's [documentation](https://docs.mux.com/guides/enable-static-mp4-renditions).
259
+ More information can be found on Mux's [documentation](https://docs.mux.com/guides/enable-static-mp4-renditions).
216
260
 
217
261
  ### Video resolution (max_resolution_tier)
218
262
 
package/dist/index.d.mts CHANGED
@@ -30,12 +30,18 @@ declare interface MuxAsset {
30
30
  static_renditions?: {
31
31
  status: 'ready' | 'preparing' | 'disabled' | 'errored'
32
32
  files: {
33
- name: 'low.mp4' | 'medium.mp4' | 'high.mp4' | 'audio.m4a'
33
+ name: string
34
34
  ext: 'mp4' | 'm4a'
35
35
  height: number
36
36
  width: number
37
37
  bitrate: number
38
- filesize: number
38
+ filesize: string
39
+ type: 'standard' | 'advanced'
40
+ status: 'ready' | 'preparing' | 'skipped' | 'errored'
41
+ resolution_tier?: string
42
+ resolution?: string
43
+ id: string
44
+ passthrough?: string
39
45
  }[]
40
46
  }
41
47
  recording_times?: {
@@ -78,6 +84,19 @@ export declare const muxInput: Plugin_2<void | Partial<PluginConfig>>
78
84
 
79
85
  declare interface MuxInputConfig {
80
86
  /**
87
+ * Enable static renditions by default. Can be overwritten on a per-asset basis.
88
+ * Supports:
89
+ * - Standard mode: 'highest' (up to 4K MP4) and/or 'audio-only' (M4A)
90
+ * - Advanced mode: Specific resolutions ('270p', '360p', '480p', '540p', '720p', '1080p', '1440p', '2160p') and/or 'audio-only'
91
+ *
92
+ * **Important**: 'highest' cannot be mixed with specific resolutions. If both are provided, only 'highest' will be used.
93
+ *
94
+ * @see {@link https://docs.mux.com/guides/video/enable-static-mp4-renditions}
95
+ * @defaultValue []
96
+ */
97
+ static_renditions: StaticRenditionResolution[]
98
+ /**
99
+ * @deprecated Use `static_renditions` instead. This field is kept for backward compatibility.
81
100
  * Enable static renditions by setting this to 'standard'. Can be overwritten on a per-asset basis.
82
101
  * Requires `"video_quality": "plus"`
83
102
  * @see {@link https://docs.mux.com/guides/video/enable-static-mp4-renditions#why-enable-mp4-support}
@@ -195,6 +214,21 @@ declare interface PluginConfig extends MuxInputConfig {
195
214
  allowedRolesForConfiguration: string[]
196
215
  }
197
216
 
217
+ /**
218
+ * All static rendition resolution options supported by Mux
219
+ */
220
+ declare type StaticRenditionResolution =
221
+ | 'highest'
222
+ | 'audio-only'
223
+ | '270p'
224
+ | '360p'
225
+ | '480p'
226
+ | '540p'
227
+ | '720p'
228
+ | '1080p'
229
+ | '1440p'
230
+ | '2160p'
231
+
198
232
  declare const SUPPORTED_MUX_LANGUAGES_VALUES: (
199
233
  | 'en'
200
234
  | 'es'
package/dist/index.d.ts CHANGED
@@ -30,12 +30,18 @@ declare interface MuxAsset {
30
30
  static_renditions?: {
31
31
  status: 'ready' | 'preparing' | 'disabled' | 'errored'
32
32
  files: {
33
- name: 'low.mp4' | 'medium.mp4' | 'high.mp4' | 'audio.m4a'
33
+ name: string
34
34
  ext: 'mp4' | 'm4a'
35
35
  height: number
36
36
  width: number
37
37
  bitrate: number
38
- filesize: number
38
+ filesize: string
39
+ type: 'standard' | 'advanced'
40
+ status: 'ready' | 'preparing' | 'skipped' | 'errored'
41
+ resolution_tier?: string
42
+ resolution?: string
43
+ id: string
44
+ passthrough?: string
39
45
  }[]
40
46
  }
41
47
  recording_times?: {
@@ -78,6 +84,19 @@ export declare const muxInput: Plugin_2<void | Partial<PluginConfig>>
78
84
 
79
85
  declare interface MuxInputConfig {
80
86
  /**
87
+ * Enable static renditions by default. Can be overwritten on a per-asset basis.
88
+ * Supports:
89
+ * - Standard mode: 'highest' (up to 4K MP4) and/or 'audio-only' (M4A)
90
+ * - Advanced mode: Specific resolutions ('270p', '360p', '480p', '540p', '720p', '1080p', '1440p', '2160p') and/or 'audio-only'
91
+ *
92
+ * **Important**: 'highest' cannot be mixed with specific resolutions. If both are provided, only 'highest' will be used.
93
+ *
94
+ * @see {@link https://docs.mux.com/guides/video/enable-static-mp4-renditions}
95
+ * @defaultValue []
96
+ */
97
+ static_renditions: StaticRenditionResolution[]
98
+ /**
99
+ * @deprecated Use `static_renditions` instead. This field is kept for backward compatibility.
81
100
  * Enable static renditions by setting this to 'standard'. Can be overwritten on a per-asset basis.
82
101
  * Requires `"video_quality": "plus"`
83
102
  * @see {@link https://docs.mux.com/guides/video/enable-static-mp4-renditions#why-enable-mp4-support}
@@ -195,6 +214,21 @@ declare interface PluginConfig extends MuxInputConfig {
195
214
  allowedRolesForConfiguration: string[]
196
215
  }
197
216
 
217
+ /**
218
+ * All static rendition resolution options supported by Mux
219
+ */
220
+ declare type StaticRenditionResolution =
221
+ | 'highest'
222
+ | 'audio-only'
223
+ | '270p'
224
+ | '360p'
225
+ | '480p'
226
+ | '540p'
227
+ | '720p'
228
+ | '1080p'
229
+ | '1440p'
230
+ | '2160p'
231
+
198
232
  declare const SUPPORTED_MUX_LANGUAGES_VALUES: (
199
233
  | 'en'
200
234
  | 'es'
package/dist/index.js CHANGED
@@ -1527,7 +1527,7 @@ function VideoPlayer({
1527
1527
  crossOrigin: "anonymous",
1528
1528
  metadata: {
1529
1529
  player_name: "Sanity Admin Dashboard",
1530
- player_version: "2.11.1",
1530
+ player_version: "2.12.0",
1531
1531
  page_type: "Preview Player"
1532
1532
  },
1533
1533
  audio: isAudio,
@@ -1618,21 +1618,21 @@ function PublishedStatus(props) {
1618
1618
  }
1619
1619
  function PaneItemPreview(props) {
1620
1620
  const { icon, layout, presence, schemaType, value } = props, title = sanity.isRecord(value.title) && React.isValidElement(value.title) || isString__default.default(value.title) || isNumber__default.default(value.title) ? value.title : null, observable = React.useMemo(
1621
- () => sanity.getPreviewStateObservable(props.documentPreviewStore, schemaType, value._id, title),
1622
- [props.documentPreviewStore, schemaType, title, value._id]
1623
- ), { draft, published, isLoading } = reactRx.useObservable(observable, {
1624
- draft: null,
1625
- published: null,
1626
- isLoading: !0
1621
+ () => sanity.getPreviewStateObservable(props.documentPreviewStore, schemaType, value._id),
1622
+ [props.documentPreviewStore, schemaType, value._id]
1623
+ ), { snapshot, original, isLoading } = reactRx.useObservable(observable, {
1624
+ isLoading: !0,
1625
+ snapshot: null,
1626
+ original: null
1627
1627
  }), status = isLoading ? null : /* @__PURE__ */ jsxRuntime.jsxs(ui.Inline, { space: 4, children: [
1628
1628
  presence && presence.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(sanity.DocumentPreviewPresence, { presence }),
1629
- /* @__PURE__ */ jsxRuntime.jsx(PublishedStatus, { document: published }),
1630
- /* @__PURE__ */ jsxRuntime.jsx(DraftStatus, { document: draft })
1629
+ /* @__PURE__ */ jsxRuntime.jsx(PublishedStatus, { document: original }),
1630
+ /* @__PURE__ */ jsxRuntime.jsx(DraftStatus, { document: snapshot })
1631
1631
  ] });
1632
1632
  return /* @__PURE__ */ jsxRuntime.jsx(
1633
1633
  sanity.SanityDefaultPreview,
1634
1634
  {
1635
- ...sanity.getPreviewValueWithFallback({ value, draft, published }),
1635
+ ...sanity.getPreviewValueWithFallback({ snapshot, original, fallback: { title } }),
1636
1636
  isPlaceholder: isLoading,
1637
1637
  icon,
1638
1638
  layout,
@@ -2437,9 +2437,14 @@ const useAccessControl = (config) => {
2437
2437
  sanity.isReference(asset) ? asset._ref : "",
2438
2438
  path
2439
2439
  ), useMuxPolling = (asset) => {
2440
- const client = useClient(), projectId = sanity.useProjectId(), dataset = sanity.useDataset(), shouldFetch = React.useMemo(
2441
- () => !!asset?.assetId && (asset?.status === "preparing" || asset?.data?.static_renditions?.status === "preparing"),
2442
- [asset?.assetId, asset?.data?.static_renditions?.status, asset?.status]
2440
+ const client = useClient(), projectId = sanity.useProjectId(), dataset = sanity.useDataset(), isPreparingStaticRenditions = React.useMemo(() => {
2441
+ if (asset?.data?.static_renditions?.status && asset?.data?.static_renditions?.status !== "disabled")
2442
+ return !1;
2443
+ const files = asset?.data?.static_renditions?.files;
2444
+ return !files || files.length === 0 ? !1 : files.some((file) => file.status === "preparing");
2445
+ }, [asset?.data?.static_renditions?.status, asset?.data?.static_renditions?.files]), shouldFetch = React.useMemo(
2446
+ () => !!asset?.assetId && (asset?.status === "preparing" || isPreparingStaticRenditions),
2447
+ [asset?.assetId, asset?.status, isPreparingStaticRenditions]
2443
2448
  );
2444
2449
  return useSWR__default.default(
2445
2450
  shouldFetch ? `/${projectId}/addons/mux/assets/${dataset}/data/${asset?.assetId}` : null,
@@ -2454,7 +2459,7 @@ const useAccessControl = (config) => {
2454
2459
  { refreshInterval: 2e3, refreshWhenHidden: !0, dedupingInterval: 1e3 }
2455
2460
  );
2456
2461
  };
2457
- var c = function(r) {
2462
+ var c = (function(r) {
2458
2463
  var t, e;
2459
2464
  function n(t2) {
2460
2465
  var e2;
@@ -2470,7 +2475,7 @@ var c = function(r) {
2470
2475
  var r2 = this.state, t2 = this.props, e2 = t2.render, n2 = t2.children, o2 = t2.renderError;
2471
2476
  return r2.hasError ? o2 ? o2({ error: r2.error }) : null : e2 ? e2() : n2 || null;
2472
2477
  }, n;
2473
- }(React.PureComponent), u = function(r, t) {
2478
+ })(React.PureComponent), u = function(r, t) {
2474
2479
  switch (t.type) {
2475
2480
  case "catch":
2476
2481
  return { didCatch: !0, error: t.error };
@@ -2746,13 +2751,14 @@ function testUrl(url) {
2746
2751
  const error = new Error("Invalid URL");
2747
2752
  if (typeof url != "string")
2748
2753
  return rxjs.throwError(error);
2754
+ const trimmedUrl = url.trim();
2749
2755
  let parsed;
2750
2756
  try {
2751
- parsed = new URL(url);
2757
+ parsed = new URL(trimmedUrl);
2752
2758
  } catch {
2753
2759
  return rxjs.throwError(error);
2754
2760
  }
2755
- return parsed && !parsed.protocol.match(/http:|https:/) ? rxjs.throwError(error) : rxjs.of(url);
2761
+ return parsed && !parsed.protocol.match(/http:|https:/) ? rxjs.throwError(error) : rxjs.of(trimmedUrl);
2756
2762
  }
2757
2763
  function optionsFromFile(opts, file) {
2758
2764
  if (!(typeof window > "u" || !(file instanceof window.File)))
@@ -2927,7 +2933,12 @@ const TopControls = styledComponents.styled.div`
2927
2933
  ) : null
2928
2934
  ] }) });
2929
2935
  }, Player = ({ asset, buttons, readOnly, onChange }) => {
2930
- const isLoading = React.useMemo(() => asset?.status === "preparing" ? "Preparing the video" : asset?.status === "waiting_for_upload" ? "Waiting for upload to start" : asset?.status === "waiting" ? "Processing upload" : !(asset?.status === "ready" || typeof asset?.status > "u"), [asset]), isPreparingStaticRenditions = React.useMemo(() => asset?.data?.static_renditions?.status === "preparing", [asset?.data?.static_renditions?.status]), playRef = React.useRef(null), muteRef = React.useRef(null), handleCancelUpload = useCancelUpload(asset, onChange);
2936
+ const isLoading = React.useMemo(() => asset?.status === "preparing" ? "Preparing the video" : asset?.status === "waiting_for_upload" ? "Waiting for upload to start" : asset?.status === "waiting" ? "Processing upload" : !(asset?.status === "ready" || typeof asset?.status > "u"), [asset]), isPreparingStaticRenditions = React.useMemo(() => {
2937
+ if (asset?.data?.static_renditions?.status && asset?.data?.static_renditions?.status !== "disabled")
2938
+ return !1;
2939
+ const files = asset?.data?.static_renditions?.files;
2940
+ return !files || files.length === 0 ? !1 : files.some((file) => file.status === "preparing");
2941
+ }, [asset?.data?.static_renditions?.status, asset?.data?.static_renditions?.files]), playRef = React.useRef(null), muteRef = React.useRef(null), handleCancelUpload = useCancelUpload(asset, onChange);
2931
2942
  return React.useEffect(() => {
2932
2943
  const style = document.createElement("style");
2933
2944
  style.innerHTML = "button svg { vertical-align: middle; }", playRef.current?.shadowRoot && playRef.current.shadowRoot.appendChild(style), muteRef?.current?.shadowRoot && muteRef.current.shadowRoot.appendChild(style.cloneNode(!0));
@@ -3348,7 +3359,20 @@ const VIDEO_QUALITY_LEVELS = [
3348
3359
  { value: "1080p", label: "1080p" },
3349
3360
  { value: "1440p", label: "1440p (2k)" },
3350
3361
  { value: "2160p", label: "2160p (4k)" }
3362
+ ], ADVANCED_RESOLUTIONS = [
3363
+ { value: "270p", label: "270p" },
3364
+ { value: "360p", label: "360p" },
3365
+ { value: "480p", label: "480p" },
3366
+ { value: "540p", label: "540p" },
3367
+ { value: "720p", label: "720p" },
3368
+ { value: "1080p", label: "1080p" },
3369
+ { value: "1440p", label: "1440p" },
3370
+ { value: "2160p", label: "2160p" }
3351
3371
  ];
3372
+ function sanitizeStaticRenditions(renditions) {
3373
+ const hasHighest = renditions.includes("highest"), hasSpecificResolutions = renditions.some((r) => r !== "highest" && r !== "audio-only");
3374
+ return hasHighest && hasSpecificResolutions ? renditions.filter((r) => r === "highest" || r === "audio-only") : renditions;
3375
+ }
3352
3376
  function UploadConfiguration({
3353
3377
  stagedUpload,
3354
3378
  secrets,
@@ -3371,18 +3395,18 @@ function UploadConfiguration({
3371
3395
  case "video_quality":
3372
3396
  return action.value === "basic" ? Object.assign({}, prev, {
3373
3397
  video_quality: action.value,
3374
- mp4_support: "none",
3398
+ static_renditions: [],
3375
3399
  max_resolution_tier: "1080p",
3376
3400
  text_tracks: prev.text_tracks?.filter(({ type }) => type !== "autogenerated"),
3377
3401
  public_policy: !0,
3378
3402
  signed_policy: !1
3379
3403
  }) : Object.assign({}, prev, {
3380
3404
  video_quality: action.value,
3381
- mp4_support: pluginConfig.mp4_support,
3405
+ static_renditions: sanitizeStaticRenditions(pluginConfig.static_renditions || []),
3382
3406
  max_resolution_tier: pluginConfig.max_resolution_tier,
3383
3407
  text_tracks: [...autoTextTracks, ...prev.text_tracks || []]
3384
3408
  });
3385
- case "mp4_support":
3409
+ case "static_renditions":
3386
3410
  case "max_resolution_tier":
3387
3411
  case "normalize_audio":
3388
3412
  case "signed_policy":
@@ -3421,13 +3445,34 @@ function UploadConfiguration({
3421
3445
  {
3422
3446
  video_quality: pluginConfig.video_quality,
3423
3447
  max_resolution_tier: pluginConfig.max_resolution_tier,
3424
- mp4_support: pluginConfig.mp4_support,
3448
+ static_renditions: sanitizeStaticRenditions(pluginConfig.static_renditions || []),
3425
3449
  signed_policy: secrets.enableSignedUrls && pluginConfig.defaultSigned,
3426
3450
  public_policy: pluginConfig.defaultPublic,
3427
3451
  normalize_audio: pluginConfig.normalize_audio,
3428
3452
  text_tracks: autoTextTracks
3429
3453
  }
3430
- ), { disableTextTrackConfig, disableUploadConfig } = pluginConfig, skipConfig = disableTextTrackConfig && disableUploadConfig;
3454
+ ), isAdvancedMode = React.useMemo(() => config.static_renditions.filter(
3455
+ (r) => r !== "highest" && r !== "audio-only"
3456
+ ).length > 0, [config.static_renditions]), [renditionMode, setRenditionMode] = React.useState(
3457
+ isAdvancedMode ? "advanced" : "standard"
3458
+ ), toggleRendition = (rendition) => {
3459
+ const current = config.static_renditions, hasRendition = current.includes(rendition);
3460
+ dispatch(hasRendition ? {
3461
+ action: "static_renditions",
3462
+ value: current.filter((r) => r !== rendition)
3463
+ } : {
3464
+ action: "static_renditions",
3465
+ value: [...current, rendition]
3466
+ });
3467
+ }, handleModeChange = (mode) => {
3468
+ setRenditionMode(mode), dispatch(mode === "standard" ? {
3469
+ action: "static_renditions",
3470
+ value: config.static_renditions.filter((r) => r === "highest" || r === "audio-only")
3471
+ } : {
3472
+ action: "static_renditions",
3473
+ value: config.static_renditions.filter((r) => r !== "highest")
3474
+ });
3475
+ }, { disableTextTrackConfig, disableUploadConfig } = pluginConfig, skipConfig = disableTextTrackConfig && disableUploadConfig;
3431
3476
  if (React.useEffect(() => {
3432
3477
  skipConfig && startUpload(formatUploadConfig(config));
3433
3478
  }, []), skipConfig) return null;
@@ -3542,25 +3587,101 @@ function UploadConfiguration({
3542
3587
  }) })
3543
3588
  }
3544
3589
  ),
3545
- !basicConfig && /* @__PURE__ */ jsxRuntime.jsx(sanity.FormField, { title: "Additional Configuration", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [
3590
+ !basicConfig && /* @__PURE__ */ jsxRuntime.jsx(sanity.FormField, { title: "Additional Configuration", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
3546
3591
  /* @__PURE__ */ jsxRuntime.jsx(PlaybackPolicy, { id, config, secrets, dispatch }),
3547
- !basicConfig && /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", gap: 2, padding: [0, 2], children: [
3548
- /* @__PURE__ */ jsxRuntime.jsx(
3549
- ui.Checkbox,
3550
- {
3551
- id: `${id}--mp4_support`,
3552
- style: { display: "block" },
3553
- name: "mp4_support",
3554
- required: !0,
3555
- checked: config.mp4_support === "standard",
3556
- onChange: (e) => dispatch({
3557
- action: "mp4_support",
3558
- value: e.currentTarget.checked ? "standard" : "none"
3559
- })
3560
- }
3561
- ),
3562
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${id}--mp4_support`, children: "MP4 support (allow downloading)" }) })
3563
- ] })
3592
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, { space: 3, children: /* @__PURE__ */ jsxRuntime.jsx(
3593
+ sanity.FormField,
3594
+ {
3595
+ title: "Static Renditions",
3596
+ description: "Generate downloadable MP4 or M4A files. Note: Mux will not upscale to produce MP4 renditions - renditions that would cause upscaling are skipped.",
3597
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
3598
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 3, children: [
3599
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", gap: 2, children: [
3600
+ /* @__PURE__ */ jsxRuntime.jsx(
3601
+ ui.Radio,
3602
+ {
3603
+ checked: renditionMode === "standard",
3604
+ name: "rendition-mode",
3605
+ onChange: () => handleModeChange("standard"),
3606
+ value: "standard",
3607
+ id: `${id}--mode-standard`
3608
+ }
3609
+ ),
3610
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { as: "label", htmlFor: `${id}--mode-standard`, children: "Standard" })
3611
+ ] }),
3612
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", gap: 2, children: [
3613
+ /* @__PURE__ */ jsxRuntime.jsx(
3614
+ ui.Radio,
3615
+ {
3616
+ checked: renditionMode === "advanced",
3617
+ name: "rendition-mode",
3618
+ onChange: () => handleModeChange("advanced"),
3619
+ value: "advanced",
3620
+ id: `${id}--mode-advanced`
3621
+ }
3622
+ ),
3623
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { as: "label", htmlFor: `${id}--mode-advanced`, children: "Advanced" })
3624
+ ] })
3625
+ ] }),
3626
+ renditionMode === "standard" && /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [
3627
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", gap: 2, padding: [0, 2], children: [
3628
+ /* @__PURE__ */ jsxRuntime.jsx(
3629
+ ui.Checkbox,
3630
+ {
3631
+ id: `${id}--highest`,
3632
+ style: { display: "block" },
3633
+ checked: config.static_renditions.includes("highest"),
3634
+ onChange: () => toggleRendition("highest")
3635
+ }
3636
+ ),
3637
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { as: "label", htmlFor: `${id}--highest`, children: "Highest Resolution (up to 4K)" })
3638
+ ] }),
3639
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", gap: 2, padding: [0, 2], children: [
3640
+ /* @__PURE__ */ jsxRuntime.jsx(
3641
+ ui.Checkbox,
3642
+ {
3643
+ id: `${id}--audio-only-standard`,
3644
+ style: { display: "block" },
3645
+ checked: config.static_renditions.includes("audio-only"),
3646
+ onChange: () => toggleRendition("audio-only")
3647
+ }
3648
+ ),
3649
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { as: "label", htmlFor: `${id}--audio-only-standard`, children: "Audio Only (M4A)" })
3650
+ ] })
3651
+ ] }),
3652
+ renditionMode === "advanced" && /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [
3653
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: 1, muted: !0, children: "Select specific resolutions:" }),
3654
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { gap: 2, wrap: "wrap", children: ADVANCED_RESOLUTIONS.map(({ value, label }) => {
3655
+ const inputId = `${id}--resolution-${value}`;
3656
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", gap: 2, children: [
3657
+ /* @__PURE__ */ jsxRuntime.jsx(
3658
+ ui.Checkbox,
3659
+ {
3660
+ id: inputId,
3661
+ style: { display: "block" },
3662
+ checked: config.static_renditions.includes(value),
3663
+ onChange: () => toggleRendition(value)
3664
+ }
3665
+ ),
3666
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { as: "label", htmlFor: inputId, size: 1, children: label })
3667
+ ] }, value);
3668
+ }) }),
3669
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", gap: 2, padding: [2, 2, 0, 2], children: [
3670
+ /* @__PURE__ */ jsxRuntime.jsx(
3671
+ ui.Checkbox,
3672
+ {
3673
+ id: `${id}--audio-only-advanced`,
3674
+ style: { display: "block" },
3675
+ checked: config.static_renditions.includes("audio-only"),
3676
+ onChange: () => toggleRendition("audio-only")
3677
+ }
3678
+ ),
3679
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { as: "label", htmlFor: `${id}--audio-only-advanced`, children: "Audio Only (M4A)" })
3680
+ ] })
3681
+ ] })
3682
+ ] })
3683
+ }
3684
+ ) })
3564
3685
  ] }) })
3565
3686
  ] }),
3566
3687
  !disableTextTrackConfig && !basicConfig && /* @__PURE__ */ jsxRuntime.jsx(
@@ -3612,7 +3733,7 @@ function formatUploadConfig(config) {
3612
3733
  []
3613
3734
  )
3614
3735
  ],
3615
- mp4_support: config.mp4_support,
3736
+ static_renditions: config.static_renditions.length > 0 ? config.static_renditions.map((resolution) => ({ resolution })) : void 0,
3616
3737
  playback_policy: setPlaybackPolicy(config),
3617
3738
  max_resolution_tier: config.max_resolution_tier,
3618
3739
  video_quality: config.video_quality,
@@ -3790,7 +3911,7 @@ function Uploader(props) {
3790
3911
  const events$ = new rxjs.Subject();
3791
3912
  return {
3792
3913
  observable: events$.asObservable(),
3793
- handleClick: (event) => events$.next(event)
3914
+ handleClick: ((event) => events$.next(event))
3794
3915
  };
3795
3916
  })()
3796
3917
  ).current, uploadRef = React.useRef(null), uploadingDocumentId = React.useRef(null), [state, dispatch] = React.useReducer(
@@ -3801,7 +3922,7 @@ function Uploader(props) {
3801
3922
  case "commitUpload":
3802
3923
  return Object.assign({}, prev, { uploadStatus: { progress: 0 } });
3803
3924
  case "progressInfo": {
3804
- const { ...payload } = action;
3925
+ const { type, action: _, ...payload } = action;
3805
3926
  return Object.assign({}, prev, {
3806
3927
  uploadStatus: {
3807
3928
  ...prev.uploadStatus,
@@ -3909,7 +4030,7 @@ function Uploader(props) {
3909
4030
  });
3910
4031
  }, handlePaste = (event) => {
3911
4032
  event.preventDefault(), event.stopPropagation();
3912
- const url = (event.clipboardData || window.clipboardData).getData("text");
4033
+ const url = (event.clipboardData || window.clipboardData).getData("text")?.trim();
3913
4034
  if (!isValidUrl(url)) {
3914
4035
  toast.push({ status: "error", title: "Invalid URL for Mux video input." });
3915
4036
  return;
@@ -4115,12 +4236,18 @@ const muxVideoSchema = {
4115
4236
  name: "mux.staticRenditionFile",
4116
4237
  type: "object",
4117
4238
  fields: [
4118
- { type: "string", name: "ext" },
4119
4239
  { type: "string", name: "name" },
4240
+ { type: "string", name: "ext" },
4241
+ { type: "number", name: "height" },
4120
4242
  { type: "number", name: "width" },
4121
4243
  { type: "number", name: "bitrate" },
4122
- { type: "number", name: "filesize" },
4123
- { type: "number", name: "height" }
4244
+ { type: "string", name: "filesize" },
4245
+ { type: "string", name: "type" },
4246
+ { type: "string", name: "status" },
4247
+ { type: "string", name: "resolution_tier" },
4248
+ { type: "string", name: "resolution" },
4249
+ { type: "string", name: "id" },
4250
+ { type: "string", name: "passthrough" }
4124
4251
  ]
4125
4252
  }, muxStaticRenditions = {
4126
4253
  name: "mux.staticRenditions",
@@ -4251,6 +4378,7 @@ const muxVideoSchema = {
4251
4378
  muxAssetData,
4252
4379
  muxVideoAsset
4253
4380
  ], defaultConfig = {
4381
+ static_renditions: [],
4254
4382
  mp4_support: "none",
4255
4383
  video_quality: "plus",
4256
4384
  max_resolution_tier: "1080p",
@@ -4259,12 +4387,20 @@ const muxVideoSchema = {
4259
4387
  defaultSigned: !1,
4260
4388
  tool: DEFAULT_TOOL_CONFIG,
4261
4389
  allowedRolesForConfiguration: []
4262
- }, muxInput = sanity.definePlugin((userConfig) => {
4390
+ };
4391
+ function convertLegacyConfig(config) {
4392
+ return config.static_renditions && config.static_renditions.length > 0 ? { static_renditions: config.static_renditions } : config.mp4_support === "standard" ? { static_renditions: ["highest"] } : { static_renditions: [] };
4393
+ }
4394
+ const muxInput = sanity.definePlugin((userConfig) => {
4263
4395
  if (typeof userConfig == "object" && "encoding_tier" in userConfig) {
4264
4396
  const deprecated_encoding_tier = userConfig.encoding_tier;
4265
4397
  userConfig.video_quality || (deprecated_encoding_tier === "baseline" && (userConfig.video_quality = "basic"), deprecated_encoding_tier === "smart" && (userConfig.video_quality = "plus"));
4266
4398
  }
4267
- const config = { ...defaultConfig, ...userConfig || {} };
4399
+ const config = {
4400
+ ...defaultConfig,
4401
+ ...userConfig || {},
4402
+ ...convertLegacyConfig(userConfig || {})
4403
+ };
4268
4404
  return {
4269
4405
  name: "mux-input",
4270
4406
  schema: {