sanity-plugin-media 4.0.0 → 4.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sanity-plugin-media",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "description": "This version of `sanity-plugin-media` is for Sanity Studio V3.",
5
5
  "keywords": [
6
6
  "sanity",
@@ -1,7 +1,7 @@
1
1
  import {DownloadIcon} from '@sanity/icons'
2
2
  import {Box, Button, Flex, Inline, Stack, Text} from '@sanity/ui'
3
3
  import type {Asset, AssetItem} from '../../types'
4
- import format from 'date-fns/format'
4
+ import { format } from 'date-fns'
5
5
  import filesize from 'filesize'
6
6
  import {type ReactNode} from 'react'
7
7
  import getAssetResolution from '../../utils/getAssetResolution'
@@ -0,0 +1,101 @@
1
+ import {Stack} from '@sanity/ui'
2
+ import type {Asset, AssetFormData, TagSelectOption} from '../../types'
3
+ import {type Control, type FieldErrors, type UseFormRegister} from 'react-hook-form'
4
+
5
+ import FormFieldInputTags from '../FormFieldInputTags'
6
+ import FormFieldInputText from '../FormFieldInputText'
7
+ import FormFieldInputTextarea from '../FormFieldInputTextarea'
8
+
9
+ export type DetailsProps = {
10
+ formUpdating: boolean
11
+ handleCreateTag: (title: string) => void
12
+ control: Control<AssetFormData>
13
+ errors: FieldErrors<AssetFormData>
14
+ register: UseFormRegister<AssetFormData>
15
+ allTagOptions: TagSelectOption[]
16
+ assetTagOptions: TagSelectOption[] | null
17
+ currentAsset: Asset
18
+ creditLine?: {
19
+ enabled: boolean
20
+ excludeSources?: string | string[] | undefined
21
+ }
22
+ }
23
+
24
+ export default function Details({
25
+ formUpdating,
26
+ handleCreateTag,
27
+ control,
28
+ errors,
29
+ register,
30
+ allTagOptions,
31
+ assetTagOptions,
32
+ currentAsset,
33
+ creditLine
34
+ }: DetailsProps) {
35
+ return (
36
+ <Stack space={3}>
37
+ {/* Tags */}
38
+ <FormFieldInputTags
39
+ control={control}
40
+ disabled={formUpdating}
41
+ error={errors?.opt?.media?.tags?.message}
42
+ label="Tags"
43
+ name="opt.media.tags"
44
+ onCreateTag={handleCreateTag}
45
+ options={allTagOptions}
46
+ placeholder="Select or create..."
47
+ value={assetTagOptions}
48
+ />
49
+ {/* Filename */}
50
+ <FormFieldInputText
51
+ {...register('originalFilename')}
52
+ disabled={formUpdating}
53
+ error={errors?.originalFilename?.message}
54
+ label="Filename"
55
+ name="originalFilename"
56
+ value={currentAsset?.originalFilename}
57
+ />
58
+ {/* Title */}
59
+ <FormFieldInputText
60
+ {...register('title')}
61
+ disabled={formUpdating}
62
+ error={errors?.title?.message}
63
+ label="Title"
64
+ name="title"
65
+ value={currentAsset?.title}
66
+ />
67
+ {/* Alt text */}
68
+ <FormFieldInputText
69
+ {...register('altText')}
70
+ disabled={formUpdating}
71
+ error={errors?.altText?.message}
72
+ label="Alt Text"
73
+ name="altText"
74
+ value={currentAsset?.altText}
75
+ />
76
+ {/* Description */}
77
+ <FormFieldInputTextarea
78
+ {...register('description')}
79
+ disabled={formUpdating}
80
+ error={errors?.description?.message}
81
+ label="Description"
82
+ name="description"
83
+ rows={5}
84
+ value={currentAsset?.description}
85
+ />
86
+ {/* CreditLine */}
87
+ {creditLine?.enabled && (
88
+ <FormFieldInputText
89
+ {...register('creditLine')}
90
+ error={errors?.creditLine?.message}
91
+ label="Credit"
92
+ name="creditLine"
93
+ value={currentAsset?.creditLine}
94
+ disabled={
95
+ formUpdating || creditLine?.excludeSources?.includes(currentAsset?.source?.name)
96
+ }
97
+ />
98
+ )}
99
+ </Stack>
100
+ )
101
+ }
@@ -1,6 +1,6 @@
1
1
  import {zodResolver} from '@hookform/resolvers/zod'
2
2
  import type {MutationEvent} from '@sanity/client'
3
- import {Box, Button, Card, Flex, Stack, Tab, TabList, TabPanel, Text} from '@sanity/ui'
3
+ import {Box, Button, Card, Flex, Tab, TabList, TabPanel, Text} from '@sanity/ui'
4
4
  import type {Asset, AssetFormData, DialogAssetEditProps, TagSelectOption} from '../../types'
5
5
  import groq from 'groq'
6
6
  import {type ReactNode, useCallback, useEffect, useRef, useState} from 'react'
@@ -22,12 +22,14 @@ import AssetMetadata from '../AssetMetadata'
22
22
  import Dialog from '../Dialog'
23
23
  import DocumentList from '../DocumentList'
24
24
  import FileAssetPreview from '../FileAssetPreview'
25
- import FormFieldInputTags from '../FormFieldInputTags'
26
- import FormFieldInputText from '../FormFieldInputText'
27
- import FormFieldInputTextarea from '../FormFieldInputTextarea'
28
25
  import FormSubmitButton from '../FormSubmitButton'
29
26
  import Image from '../Image'
30
27
  import {useToolOptions} from '../../contexts/ToolOptionsContext'
28
+ import Details, {type DetailsProps} from './Details'
29
+
30
+ function renderDefaultDetails(props: DetailsProps) {
31
+ return <Details {...props} />
32
+ }
31
33
 
32
34
  type Props = {
33
35
  children: ReactNode
@@ -61,7 +63,7 @@ const DialogAssetEdit = (props: Props) => {
61
63
  const assetTagOptions = useTypedSelector(selectTagSelectOptions(currentAsset))
62
64
 
63
65
  // Check if credit line options are configured
64
- const {creditLine} = useToolOptions()
66
+ const {creditLine, components: {details: CustomDetails} = {}} = useToolOptions()
65
67
 
66
68
  const generateDefaultValues = useCallback(
67
69
  (asset?: Asset): AssetFormData => {
@@ -239,6 +241,19 @@ const DialogAssetEdit = (props: Props) => {
239
241
  return null
240
242
  }
241
243
 
244
+ const detailsProps = {
245
+ control,
246
+ errors,
247
+ formUpdating,
248
+ register,
249
+ setValue,
250
+ assetTagOptions,
251
+ allTagOptions,
252
+ handleCreateTag,
253
+ currentAsset,
254
+ creditLine
255
+ }
256
+
242
257
  return (
243
258
  <Dialog
244
259
  animate
@@ -304,71 +319,14 @@ const DialogAssetEdit = (props: Props) => {
304
319
  hidden={tabSection !== 'details'}
305
320
  id="details-panel"
306
321
  >
307
- <Stack space={3}>
308
- {/* Tags */}
309
- <FormFieldInputTags
310
- control={control}
311
- disabled={formUpdating}
312
- error={errors?.opt?.media?.tags?.message}
313
- label="Tags"
314
- name="opt.media.tags"
315
- onCreateTag={handleCreateTag}
316
- options={allTagOptions}
317
- placeholder="Select or create..."
318
- value={assetTagOptions}
322
+ {CustomDetails ? (
323
+ <CustomDetails
324
+ {...detailsProps}
325
+ renderDefaultDetails={renderDefaultDetails}
319
326
  />
320
- {/* Filename */}
321
- <FormFieldInputText
322
- {...register('originalFilename')}
323
- disabled={formUpdating}
324
- error={errors?.originalFilename?.message}
325
- label="Filename"
326
- name="originalFilename"
327
- value={currentAsset?.originalFilename}
328
- />
329
- {/* Title */}
330
- <FormFieldInputText
331
- {...register('title')}
332
- disabled={formUpdating}
333
- error={errors?.title?.message}
334
- label="Title"
335
- name="title"
336
- value={currentAsset?.title}
337
- />
338
- {/* Alt text */}
339
- <FormFieldInputText
340
- {...register('altText')}
341
- disabled={formUpdating}
342
- error={errors?.altText?.message}
343
- label="Alt Text"
344
- name="altText"
345
- value={currentAsset?.altText}
346
- />
347
- {/* Description */}
348
- <FormFieldInputTextarea
349
- {...register('description')}
350
- disabled={formUpdating}
351
- error={errors?.description?.message}
352
- label="Description"
353
- name="description"
354
- rows={5}
355
- value={currentAsset?.description}
356
- />
357
- {/* CreditLine */}
358
- {creditLine?.enabled && (
359
- <FormFieldInputText
360
- {...register('creditLine')}
361
- error={errors?.creditLine?.message}
362
- label="Credit"
363
- name="creditLine"
364
- value={currentAsset?.creditLine}
365
- disabled={
366
- formUpdating ||
367
- creditLine?.excludeSources?.includes(currentAsset?.source?.name)
368
- }
369
- />
370
- )}
371
- </Stack>
327
+ ) : (
328
+ <Details {...detailsProps} />
329
+ )}
372
330
  </TabPanel>
373
331
 
374
332
  {/* Panel: References */}
@@ -1,5 +1,5 @@
1
1
  import {Box, Button, Text, Tooltip} from '@sanity/ui'
2
- import format from 'date-fns/format'
2
+ import { format } from 'date-fns'
3
3
  import {type ReactNode} from 'react'
4
4
 
5
5
  type Props = {
@@ -5,6 +5,7 @@ import pluralize from 'pluralize'
5
5
  import {useAssetSourceActions} from '../../contexts/AssetSourceDispatchContext'
6
6
  import {useDropzoneActions} from '../../contexts/DropzoneDispatchContext'
7
7
  import useTypedSelector from '../../hooks/useTypedSelector'
8
+ import {useToolOptions} from '../../contexts/ToolOptionsContext'
8
9
 
9
10
  type Props = {
10
11
  onClose?: () => void
@@ -20,6 +21,8 @@ const Header = (props: Props) => {
20
21
  const assetTypes = useTypedSelector(state => state.assets.assetTypes)
21
22
  const selectedDocument = useTypedSelector(state => state.selected.document)
22
23
 
24
+ const {directUploads} = useToolOptions()
25
+
23
26
  // Row: Current document / close button
24
27
  return (
25
28
  <Box paddingY={2}>
@@ -46,14 +49,15 @@ const Header = (props: Props) => {
46
49
 
47
50
  <Flex marginX={2}>
48
51
  {/* Upload */}
49
- <Button
50
- fontSize={1}
51
- icon={UploadIcon}
52
- mode="bleed"
53
- onClick={open}
54
- text={`Upload ${assetTypes.length === 1 ? pluralize(assetTypes[0]) : 'assets'}`}
55
- tone="primary"
56
- />
52
+ {directUploads && (
53
+ <Button
54
+ fontSize={1}
55
+ icon={UploadIcon}
56
+ mode="bleed"
57
+ onClick={open}
58
+ text={`Upload ${assetTypes.length === 1 ? pluralize(assetTypes[0]) : 'assets'}`}
59
+ />
60
+ )}
57
61
 
58
62
  {/* Close */}
59
63
  {onClose && (
@@ -11,7 +11,7 @@ import {
11
11
  Tooltip,
12
12
  useMediaIndex
13
13
  } from '@sanity/ui'
14
- import formatRelative from 'date-fns/formatRelative'
14
+ import { formatRelative } from 'date-fns'
15
15
  import filesize from 'filesize'
16
16
  import {
17
17
  memo,
@@ -64,7 +64,8 @@ const UploadDropzone = (props: Props) => {
64
64
  const {children} = props
65
65
 
66
66
  const {
67
- dropzone: {maxSize}
67
+ dropzone: {maxSize},
68
+ directUploads
68
69
  } = useToolOptions()
69
70
 
70
71
  const {onSelect} = useAssetSourceActions()
@@ -143,7 +144,8 @@ const UploadDropzone = (props: Props) => {
143
144
  noDrag: !!onSelect,
144
145
  onDrop: handleDrop,
145
146
  maxSize,
146
- onDropRejected: handleDropRejected
147
+ onDropRejected: handleDropRejected,
148
+ disabled: !directUploads
147
149
  })
148
150
 
149
151
  return (
@@ -4,7 +4,9 @@ import type {DropzoneOptions} from 'react-dropzone'
4
4
 
5
5
  type ContextProps = {
6
6
  dropzone: Pick<DropzoneOptions, 'maxSize'>
7
+ components: MediaToolOptions['components']
7
8
  creditLine: MediaToolOptions['creditLine']
9
+ directUploads: MediaToolOptions['directUploads']
8
10
  }
9
11
 
10
12
  const ToolOptionsContext = createContext<ContextProps | null>(null)
@@ -25,15 +27,21 @@ export const ToolOptionsProvider = ({options, children}: PropsWithChildren<Props
25
27
 
26
28
  return {
27
29
  dropzone: {maxSize: options?.maximumUploadSize},
30
+ components: {
31
+ details: options?.components?.details
32
+ },
28
33
  creditLine: {
29
34
  enabled: options?.creditLine?.enabled || false,
30
35
  excludeSources: creditLineExcludeSources
31
- }
36
+ },
37
+ directUploads: options?.directUploads ?? true
32
38
  }
33
39
  }, [
34
40
  options?.creditLine?.enabled,
41
+ options?.components,
35
42
  options?.creditLine?.excludeSources,
36
- options?.maximumUploadSize
43
+ options?.maximumUploadSize,
44
+ options?.directUploads
37
45
  ])
38
46
 
39
47
  return <ToolOptionsContext.Provider value={value}>{children}</ToolOptionsContext.Provider>
@@ -254,7 +254,9 @@ const assetsSlice = createSlice({
254
254
  originalFilename,
255
255
  size,
256
256
  source {
257
- name
257
+ name,
258
+ id,
259
+ url,
258
260
  },
259
261
  title,
260
262
  url
@@ -5,17 +5,25 @@ import type {
5
5
  SanityDocument,
6
6
  SanityImageAssetDocument
7
7
  } from '@sanity/client'
8
+ import type {ComponentType, JSX} from 'react'
8
9
  import type {Epic} from 'redux-observable'
9
10
  import * as z from 'zod'
10
11
  import {assetFormSchema, tagFormSchema, tagOptionSchema} from '../formSchema'
11
12
  import type {RootReducerState} from '../modules/types'
13
+ import type {DetailsProps} from '../components/DialogAssetEdit/Details'
12
14
 
13
15
  export type MediaToolOptions = {
14
16
  maximumUploadSize?: number
17
+ components?: {
18
+ details?: ComponentType<
19
+ DetailsProps & {renderDefaultDetails: (props: DetailsProps) => JSX.Element}
20
+ >
21
+ }
15
22
  creditLine: {
16
23
  enabled: boolean
17
24
  excludeSources?: string | string[]
18
25
  }
26
+ directUploads?: boolean
19
27
  }
20
28
 
21
29
  type CustomFields = {