sanity-plugin-media 4.1.1 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +107 -3
  3. package/dist/index.d.mts +227 -56
  4. package/dist/index.d.ts +227 -56
  5. package/dist/index.js +473 -184
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +476 -187
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +9 -2
  10. package/src/__tests__/fixtures/createEpicTestStore.ts +27 -0
  11. package/src/__tests__/fixtures/listenMock.ts +9 -0
  12. package/src/__tests__/fixtures/mockSanityClient.ts +84 -0
  13. package/src/__tests__/fixtures/renderWithProviders.tsx +54 -0
  14. package/src/__tests__/fixtures/rootState.ts +27 -0
  15. package/src/__tests__/fixtures/withinDialog.ts +28 -0
  16. package/src/components/AutoTagInputWrapper/index.tsx +82 -0
  17. package/src/components/Browser/Browser.test.tsx +44 -0
  18. package/src/components/Browser/index.tsx +12 -69
  19. package/src/components/Browser/useBrowserInit.ts +126 -0
  20. package/src/components/CardAsset/CardAsset.test.tsx +322 -0
  21. package/src/components/DialogAssetEdit/Details.tsx +123 -44
  22. package/src/components/DialogAssetEdit/DialogAssetEdit.test.tsx +215 -0
  23. package/src/components/DialogAssetEdit/index.tsx +138 -30
  24. package/src/components/DialogTagCreate/DialogTagCreate.test.tsx +120 -0
  25. package/src/components/DialogTagEdit/DialogTagEdit.test.tsx +164 -0
  26. package/src/components/FormBuilderTool/FormBuilderTool.test.tsx +62 -0
  27. package/src/components/FormBuilderTool/index.tsx +1 -1
  28. package/src/components/UploadDropzone/UploadDropzone.test.tsx +39 -0
  29. package/src/contexts/ToolOptionsContext.tsx +9 -3
  30. package/src/formSchema/index.test.ts +55 -0
  31. package/src/formSchema/index.ts +28 -12
  32. package/src/hooks/useVersionedClient.ts +1 -1
  33. package/src/index.ts +4 -1
  34. package/src/modules/assets/deleteAndUpdateEpics.test.ts +86 -0
  35. package/src/modules/assets/fetchEpic.test.ts +72 -0
  36. package/src/modules/assets/reducer.test.ts +90 -0
  37. package/src/modules/assets/tagsAndListenerEpics.test.ts +205 -0
  38. package/src/modules/dialog/epics.test.ts +167 -0
  39. package/src/modules/dialog/reducer.test.ts +184 -0
  40. package/src/modules/notifications/epics.test.ts +373 -0
  41. package/src/modules/notifications/index.ts +24 -4
  42. package/src/modules/notifications/reducer.test.ts +53 -0
  43. package/src/modules/search/index.test.ts +35 -0
  44. package/src/modules/selectors.test.ts +20 -0
  45. package/src/modules/tags/epics.test.ts +95 -0
  46. package/src/modules/tags/index.test.ts +41 -0
  47. package/src/modules/uploads/epics.test.ts +108 -0
  48. package/src/modules/uploads/index.test.ts +58 -0
  49. package/src/operators/checkTagName.test.ts +28 -0
  50. package/src/types/index.ts +25 -7
  51. package/src/utils/applyMediaTags.ts +86 -0
  52. package/src/utils/blocksToText.test.ts +42 -0
  53. package/src/utils/constructFilter.test.ts +119 -0
  54. package/src/utils/generatePreviewBlobUrl.test.ts +69 -0
  55. package/src/utils/getAssetResolution.test.ts +12 -0
  56. package/src/utils/getDocumentAssetIds.test.ts +49 -0
  57. package/src/utils/getSchemeColor.test.ts +11 -0
  58. package/src/utils/getTagSelectOptions.test.ts +43 -0
  59. package/src/utils/getUniqueDocuments.test.ts +25 -0
  60. package/src/utils/imageDprUrl.test.ts +45 -0
  61. package/src/utils/isSupportedAssetType.test.ts +15 -0
  62. package/src/utils/mediaField.ts +72 -0
  63. package/src/utils/sanitizeFormData.test.ts +58 -0
  64. package/src/utils/typeGuards.test.ts +17 -0
  65. package/src/utils/uploadSanityAsset.test.ts +28 -0
  66. package/src/utils/withMaxConcurrency.test.ts +42 -0
package/dist/index.d.ts CHANGED
@@ -1,8 +1,12 @@
1
1
  import {AssetSourceComponentProps} from 'sanity'
2
2
  import type {ComponentType} from 'react'
3
3
  import {Control} from 'react-hook-form'
4
+ import type {FieldDefinitionBase} from 'sanity'
4
5
  import {FieldErrors} from 'react-hook-form'
6
+ import type {FileDefinition} from 'sanity'
5
7
  import {ForwardRefExoticComponent} from 'react'
8
+ import type {ImageDefinition} from 'sanity'
9
+ import {InputProps} from 'sanity'
6
10
  import {JSX as JSX_2} from 'react'
7
11
  import {Plugin as Plugin_2} from 'sanity'
8
12
  import {RefAttributes} from 'react'
@@ -10,17 +14,122 @@ import type {SanityAssetDocument} from '@sanity/client'
10
14
  import type {SanityImageAssetDocument} from '@sanity/client'
11
15
  import {SVGProps} from 'react'
12
16
  import {UseFormRegister} from 'react-hook-form'
17
+ import type {WidenInitialValue} from 'sanity'
18
+ import type {WidenValidation} from 'sanity'
13
19
  import * as z from 'zod'
14
20
 
15
21
  declare type Asset = FileAsset | ImageAsset
16
22
 
17
- declare type AssetFormData = z.infer<typeof assetFormSchema>
23
+ declare type AssetFormData = z.infer<ReturnType<typeof getAssetFormSchema>>
18
24
 
19
- declare const assetFormSchema: z.ZodObject<
25
+ /**
26
+ * Input component that automatically applies media tags when an asset is selected or uploaded.
27
+ *
28
+ * Apply explicitly to image/file fields that should be auto-tagged:
29
+ * ```ts
30
+ * import {AutoTagInput} from 'sanity-plugin-media'
31
+ *
32
+ * defineField({
33
+ * type: 'image',
34
+ * options: { mediaTags: ['product'] }, // also pre-filters the media browser
35
+ * components: { input: AutoTagInput },
36
+ * })
37
+ * ```
38
+ *
39
+ * Pass `mediaTags` as a prop to override or use without `options`:
40
+ * ```ts
41
+ * components: { input: (props) => <AutoTagInput {...props} mediaTags={['product']} /> }
42
+ * ```
43
+ */
44
+ export declare function AutoTagInput(props: AutoTagInputProps): JSX_2
45
+
46
+ export declare type AutoTagInputProps = InputProps & {
47
+ mediaTags?: string[]
48
+ }
49
+
50
+ declare type CustomFields = {
51
+ altText?: LocalizedString
52
+ description?: LocalizedString
53
+ opt?: {
54
+ media?: {
55
+ tags?: SanityReference[]
56
+ }
57
+ }
58
+ title?: LocalizedString
59
+ }
60
+
61
+ declare type DetailsProps = {
62
+ formUpdating: boolean
63
+ handleCreateTag: (title: string) => void
64
+ control: Control<AssetFormData>
65
+ errors: FieldErrors<AssetFormData>
66
+ register: UseFormRegister<AssetFormData>
67
+ allTagOptions: TagSelectOption[]
68
+ assetTagOptions: TagSelectOption[] | null
69
+ currentAsset: Asset
70
+ creditLine?: {
71
+ enabled: boolean
72
+ excludeSources?: string | string[] | undefined
73
+ }
74
+ locales?: Locale_2[]
75
+ }
76
+
77
+ declare type FileAsset = SanityAssetDocument &
78
+ CustomFields & {
79
+ _type: 'sanity.fileAsset'
80
+ }
81
+
82
+ declare type FileMediaFieldConfig = Omit<FileDefinition, 'options'> &
83
+ FieldDefinitionBase & {
84
+ name: string
85
+ mediaTags: string[]
86
+ options?: FileDefinition['options']
87
+ }
88
+
89
+ declare type FileMediaFieldResult = Omit<FileDefinition, 'options'> &
90
+ FieldDefinitionBase & {
91
+ options?: FileDefinition['options'] & {
92
+ mediaTags: string[]
93
+ }
94
+ components: {
95
+ input: typeof AutoTagInput
96
+ }
97
+ } & WidenValidation &
98
+ WidenInitialValue
99
+
100
+ declare function getAssetFormSchema(
101
+ locales?: {
102
+ id: string
103
+ }[]
104
+ ): z.ZodObject<
20
105
  {
21
- altText: z.ZodOptional<z.ZodString>
22
- creditLine: z.ZodOptional<z.ZodString>
23
- description: z.ZodOptional<z.ZodString>
106
+ altText:
107
+ | z.ZodOptional<z.ZodString>
108
+ | z.ZodObject<
109
+ Record<string, z.ZodTypeAny>,
110
+ 'passthrough',
111
+ z.ZodTypeAny,
112
+ z.objectOutputType<Record<string, z.ZodTypeAny>, z.ZodTypeAny, 'passthrough'>,
113
+ z.objectInputType<Record<string, z.ZodTypeAny>, z.ZodTypeAny, 'passthrough'>
114
+ >
115
+ creditLine:
116
+ | z.ZodOptional<z.ZodString>
117
+ | z.ZodObject<
118
+ Record<string, z.ZodTypeAny>,
119
+ 'passthrough',
120
+ z.ZodTypeAny,
121
+ z.objectOutputType<Record<string, z.ZodTypeAny>, z.ZodTypeAny, 'passthrough'>,
122
+ z.objectInputType<Record<string, z.ZodTypeAny>, z.ZodTypeAny, 'passthrough'>
123
+ >
124
+ description:
125
+ | z.ZodOptional<z.ZodString>
126
+ | z.ZodObject<
127
+ Record<string, z.ZodTypeAny>,
128
+ 'passthrough',
129
+ z.ZodTypeAny,
130
+ z.objectOutputType<Record<string, z.ZodTypeAny>, z.ZodTypeAny, 'passthrough'>,
131
+ z.objectInputType<Record<string, z.ZodTypeAny>, z.ZodTypeAny, 'passthrough'>
132
+ >
24
133
  opt: z.ZodObject<
25
134
  {
26
135
  media: z.ZodObject<
@@ -35,12 +144,12 @@ declare const assetFormSchema: z.ZodObject<
35
144
  'strip',
36
145
  z.ZodTypeAny,
37
146
  {
38
- label: string
39
147
  value: string
148
+ label: string
40
149
  },
41
150
  {
42
- label: string
43
151
  value: string
152
+ label: string
44
153
  }
45
154
  >,
46
155
  'many'
@@ -52,16 +161,16 @@ declare const assetFormSchema: z.ZodObject<
52
161
  {
53
162
  tags:
54
163
  | {
55
- label: string
56
164
  value: string
165
+ label: string
57
166
  }[]
58
167
  | null
59
168
  },
60
169
  {
61
170
  tags:
62
171
  | {
63
- label: string
64
172
  value: string
173
+ label: string
65
174
  }[]
66
175
  | null
67
176
  }
@@ -73,8 +182,8 @@ declare const assetFormSchema: z.ZodObject<
73
182
  media: {
74
183
  tags:
75
184
  | {
76
- label: string
77
185
  value: string
186
+ label: string
78
187
  }[]
79
188
  | null
80
189
  }
@@ -83,15 +192,23 @@ declare const assetFormSchema: z.ZodObject<
83
192
  media: {
84
193
  tags:
85
194
  | {
86
- label: string
87
195
  value: string
196
+ label: string
88
197
  }[]
89
198
  | null
90
199
  }
91
200
  }
92
201
  >
93
202
  originalFilename: z.ZodString
94
- title: z.ZodOptional<z.ZodString>
203
+ title:
204
+ | z.ZodOptional<z.ZodString>
205
+ | z.ZodObject<
206
+ Record<string, z.ZodTypeAny>,
207
+ 'passthrough',
208
+ z.ZodTypeAny,
209
+ z.objectOutputType<Record<string, z.ZodTypeAny>, z.ZodTypeAny, 'passthrough'>,
210
+ z.objectInputType<Record<string, z.ZodTypeAny>, z.ZodTypeAny, 'passthrough'>
211
+ >
95
212
  },
96
213
  'strip',
97
214
  z.ZodTypeAny,
@@ -100,73 +217,92 @@ declare const assetFormSchema: z.ZodObject<
100
217
  media: {
101
218
  tags:
102
219
  | {
103
- label: string
104
220
  value: string
221
+ label: string
105
222
  }[]
106
223
  | null
107
224
  }
108
225
  }
109
226
  originalFilename: string
110
- altText?: string | undefined
111
- creditLine?: string | undefined
112
- description?: string | undefined
113
- title?: string | undefined
227
+ altText?:
228
+ | string
229
+ | z.objectOutputType<Record<string, z.ZodTypeAny>, z.ZodTypeAny, 'passthrough'>
230
+ | undefined
231
+ creditLine?:
232
+ | string
233
+ | z.objectOutputType<Record<string, z.ZodTypeAny>, z.ZodTypeAny, 'passthrough'>
234
+ | undefined
235
+ description?:
236
+ | string
237
+ | z.objectOutputType<Record<string, z.ZodTypeAny>, z.ZodTypeAny, 'passthrough'>
238
+ | undefined
239
+ title?:
240
+ | string
241
+ | z.objectOutputType<Record<string, z.ZodTypeAny>, z.ZodTypeAny, 'passthrough'>
242
+ | undefined
114
243
  },
115
244
  {
116
245
  opt: {
117
246
  media: {
118
247
  tags:
119
248
  | {
120
- label: string
121
249
  value: string
250
+ label: string
122
251
  }[]
123
252
  | null
124
253
  }
125
254
  }
126
255
  originalFilename: string
127
- altText?: string | undefined
128
- creditLine?: string | undefined
129
- description?: string | undefined
130
- title?: string | undefined
256
+ altText?:
257
+ | string
258
+ | z.objectInputType<Record<string, z.ZodTypeAny>, z.ZodTypeAny, 'passthrough'>
259
+ | undefined
260
+ creditLine?:
261
+ | string
262
+ | z.objectInputType<Record<string, z.ZodTypeAny>, z.ZodTypeAny, 'passthrough'>
263
+ | undefined
264
+ description?:
265
+ | string
266
+ | z.objectInputType<Record<string, z.ZodTypeAny>, z.ZodTypeAny, 'passthrough'>
267
+ | undefined
268
+ title?:
269
+ | string
270
+ | z.objectInputType<Record<string, z.ZodTypeAny>, z.ZodTypeAny, 'passthrough'>
271
+ | undefined
131
272
  }
132
273
  >
133
274
 
134
- declare type CustomFields = {
135
- altText?: string
136
- description?: string
137
- opt?: {
138
- media?: {
139
- tags?: SanityReference[]
140
- }
275
+ declare type ImageAsset = SanityImageAssetDocument &
276
+ CustomFields & {
277
+ _type: 'sanity.imageAsset'
278
+ creditLine?: LocalizedString
141
279
  }
142
- title?: string
143
- }
144
280
 
145
- declare type DetailsProps = {
146
- formUpdating: boolean
147
- handleCreateTag: (title: string) => void
148
- control: Control<AssetFormData>
149
- errors: FieldErrors<AssetFormData>
150
- register: UseFormRegister<AssetFormData>
151
- allTagOptions: TagSelectOption[]
152
- assetTagOptions: TagSelectOption[] | null
153
- currentAsset: Asset
154
- creditLine?: {
155
- enabled: boolean
156
- excludeSources?: string | string[] | undefined
281
+ declare type ImageMediaFieldConfig = Omit<ImageDefinition, 'options'> &
282
+ FieldDefinitionBase & {
283
+ name: string
284
+ mediaTags: string[]
285
+ options?: ImageDefinition['options']
157
286
  }
158
- }
159
287
 
160
- declare type FileAsset = SanityAssetDocument &
161
- CustomFields & {
162
- _type: 'sanity.fileAsset'
163
- }
288
+ declare type ImageMediaFieldResult = Omit<ImageDefinition, 'options'> &
289
+ FieldDefinitionBase & {
290
+ options?: ImageDefinition['options'] & {
291
+ mediaTags: string[]
292
+ }
293
+ components: {
294
+ input: typeof AutoTagInput
295
+ }
296
+ } & WidenValidation &
297
+ WidenInitialValue
164
298
 
165
- declare type ImageAsset = SanityImageAssetDocument &
166
- CustomFields & {
167
- _type: 'sanity.imageAsset'
168
- creditLine?: string
169
- }
299
+ declare type Locale_2 = {
300
+ title: string
301
+ id: string
302
+ [key: string]: unknown
303
+ }
304
+
305
+ declare type LocalizedString = string | Record<string, string>
170
306
 
171
307
  export declare const media: Plugin_2<void | MediaToolOptions>
172
308
 
@@ -179,8 +315,38 @@ export declare const mediaAssetSource: {
179
315
  title: string
180
316
  }
181
317
 
318
+ /**
319
+ * Defines an image or file field with automatic media tag application when an asset is selected.
320
+ *
321
+ * Pass `mediaTags` at the top level — they are moved into `options.mediaTags` (for media browser
322
+ * pre-filtering) and wire up {@link AutoTagInput} as the field component automatically:
323
+ * ```ts
324
+ * import {mediaField} from 'sanity-plugin-media'
325
+ *
326
+ * mediaField({
327
+ * name: 'coverImage',
328
+ * type: 'image',
329
+ * mediaTags: ['product-cover'],
330
+ * options: { hotspot: true },
331
+ * })
332
+ * ```
333
+ *
334
+ * For file fields, set `type: 'file'`:
335
+ * ```ts
336
+ * mediaField({ name: 'drawing', type: 'file', mediaTags: ['model-drawing'] })
337
+ * ```
338
+ */
339
+ export declare function mediaField(config: ImageMediaFieldConfig): ImageMediaFieldResult
340
+
341
+ export declare function mediaField(config: FileMediaFieldConfig): FileMediaFieldResult
342
+
343
+ export declare type MediaTagsOptions = {
344
+ mediaTags?: string[]
345
+ }
346
+
182
347
  export declare type MediaToolOptions = {
183
348
  maximumUploadSize?: number
349
+ createTagsOnUpload?: boolean
184
350
  components?: {
185
351
  details?: ComponentType<
186
352
  DetailsProps & {
@@ -188,11 +354,16 @@ export declare type MediaToolOptions = {
188
354
  }
189
355
  >
190
356
  }
191
- creditLine: {
357
+ creditLine?: {
192
358
  enabled: boolean
193
359
  excludeSources?: string | string[]
194
360
  }
195
361
  directUploads?: boolean
362
+ /**
363
+ * Optional locales following Sanity recommended scheme: [{ id, title }]
364
+ * https://www.sanity.io/docs/studio/localization#k4da239411955
365
+ */
366
+ locales?: Locale_2[]
196
367
  }
197
368
 
198
369
  declare type SanityReference = {
@@ -209,12 +380,12 @@ declare const tagOptionSchema: z.ZodObject<
209
380
  'strip',
210
381
  z.ZodTypeAny,
211
382
  {
212
- label: string
213
383
  value: string
384
+ label: string
214
385
  },
215
386
  {
216
- label: string
217
387
  value: string
388
+ label: string
218
389
  }
219
390
  >
220
391