sanity-plugin-media 4.3.5 → 5.0.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 (166) hide show
  1. package/dist/index.d.ts +190 -413
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +2532 -3564
  4. package/dist/index.js.map +1 -1
  5. package/package.json +29 -35
  6. package/dist/index.cjs +0 -5753
  7. package/dist/index.cjs.map +0 -1
  8. package/dist/index.d.cts +0 -462
  9. package/sanity.json +0 -8
  10. package/src/__tests__/fixtures/createEpicTestStore.ts +0 -28
  11. package/src/__tests__/fixtures/listenMock.ts +0 -9
  12. package/src/__tests__/fixtures/mockSanityClient.ts +0 -84
  13. package/src/__tests__/fixtures/renderWithProviders.tsx +0 -55
  14. package/src/__tests__/fixtures/rootState.ts +0 -27
  15. package/src/__tests__/fixtures/withinDialog.ts +0 -28
  16. package/src/components/AssetGridVirtualized/index.tsx +0 -94
  17. package/src/components/AssetMetadata/index.tsx +0 -122
  18. package/src/components/AssetTableVirtualized/index.tsx +0 -73
  19. package/src/components/AutoTagInputWrapper/index.tsx +0 -87
  20. package/src/components/Browser/Browser.test.tsx +0 -45
  21. package/src/components/Browser/index.tsx +0 -90
  22. package/src/components/Browser/useBrowserInit.ts +0 -126
  23. package/src/components/ButtonAssetCopy/index.tsx +0 -65
  24. package/src/components/ButtonViewGroup/index.tsx +0 -39
  25. package/src/components/CardAsset/CardAsset.test.tsx +0 -323
  26. package/src/components/CardAsset/index.tsx +0 -290
  27. package/src/components/CardUpload/index.tsx +0 -161
  28. package/src/components/Controls/index.tsx +0 -136
  29. package/src/components/DebugControls/index.tsx +0 -80
  30. package/src/components/Dialog/index.tsx +0 -11
  31. package/src/components/DialogAssetEdit/Details.tsx +0 -181
  32. package/src/components/DialogAssetEdit/DialogAssetEdit.test.tsx +0 -216
  33. package/src/components/DialogAssetEdit/index.tsx +0 -492
  34. package/src/components/DialogConfirm/index.tsx +0 -88
  35. package/src/components/DialogSearchFacets/index.tsx +0 -42
  36. package/src/components/DialogTagCreate/DialogTagCreate.test.tsx +0 -121
  37. package/src/components/DialogTagCreate/index.tsx +0 -103
  38. package/src/components/DialogTagEdit/DialogTagEdit.test.tsx +0 -165
  39. package/src/components/DialogTagEdit/index.tsx +0 -190
  40. package/src/components/DialogTags/index.tsx +0 -45
  41. package/src/components/Dialogs/index.tsx +0 -76
  42. package/src/components/DocumentList/index.tsx +0 -62
  43. package/src/components/FileAssetPreview/index.tsx +0 -37
  44. package/src/components/FileIcon/index.tsx +0 -43
  45. package/src/components/FormBuilderTool/FormBuilderTool.test.tsx +0 -63
  46. package/src/components/FormBuilderTool/index.tsx +0 -69
  47. package/src/components/FormFieldInputLabel/index.tsx +0 -66
  48. package/src/components/FormFieldInputTags/index.tsx +0 -98
  49. package/src/components/FormFieldInputText/index.tsx +0 -41
  50. package/src/components/FormFieldInputTextarea/index.tsx +0 -43
  51. package/src/components/FormSubmitButton/index.tsx +0 -59
  52. package/src/components/Header/index.tsx +0 -80
  53. package/src/components/Image/index.tsx +0 -41
  54. package/src/components/Items/index.tsx +0 -68
  55. package/src/components/Notifications/index.tsx +0 -24
  56. package/src/components/OrderSelect/index.tsx +0 -66
  57. package/src/components/PickedBar/index.tsx +0 -77
  58. package/src/components/Progress/index.tsx +0 -38
  59. package/src/components/ReduxProvider/index.tsx +0 -96
  60. package/src/components/SearchFacet/index.tsx +0 -66
  61. package/src/components/SearchFacetNumber/index.tsx +0 -133
  62. package/src/components/SearchFacetSelect/index.tsx +0 -110
  63. package/src/components/SearchFacetString/index.tsx +0 -88
  64. package/src/components/SearchFacetTags/index.tsx +0 -121
  65. package/src/components/SearchFacets/index.tsx +0 -72
  66. package/src/components/SearchFacetsControl/index.tsx +0 -140
  67. package/src/components/TableHeader/index.tsx +0 -110
  68. package/src/components/TableHeaderItem/index.tsx +0 -61
  69. package/src/components/TableRowAsset/index.tsx +0 -420
  70. package/src/components/TableRowUpload/index.tsx +0 -164
  71. package/src/components/Tag/index.tsx +0 -200
  72. package/src/components/TagIcon/index.tsx +0 -22
  73. package/src/components/TagView/index.tsx +0 -39
  74. package/src/components/TagViewHeader/index.tsx +0 -70
  75. package/src/components/TagsPanel/index.tsx +0 -40
  76. package/src/components/TagsVirtualized/index.tsx +0 -160
  77. package/src/components/TextInputNumber/index.tsx +0 -32
  78. package/src/components/TextInputSearch/index.tsx +0 -60
  79. package/src/components/Tool/index.tsx +0 -13
  80. package/src/components/UploadDropzone/UploadDropzone.test.tsx +0 -40
  81. package/src/components/UploadDropzone/index.tsx +0 -173
  82. package/src/config/orders.ts +0 -28
  83. package/src/config/searchFacets.ts +0 -312
  84. package/src/constants.ts +0 -87
  85. package/src/contexts/AssetSourceDispatchContext.tsx +0 -37
  86. package/src/contexts/DropzoneDispatchContext.tsx +0 -34
  87. package/src/contexts/ToolOptionsContext.tsx +0 -65
  88. package/src/formSchema/index.test.ts +0 -56
  89. package/src/formSchema/index.ts +0 -39
  90. package/src/hooks/useBreakpointIndex.ts +0 -49
  91. package/src/hooks/useKeyPress.ts +0 -39
  92. package/src/hooks/useOnScreen.ts +0 -34
  93. package/src/hooks/usePortalPopoverProps.ts +0 -13
  94. package/src/hooks/useTypedSelector.ts +0 -7
  95. package/src/hooks/useVersionedClient.ts +0 -6
  96. package/src/index.ts +0 -5
  97. package/src/modules/assets/actions.ts +0 -42
  98. package/src/modules/assets/deleteAndUpdateEpics.test.ts +0 -87
  99. package/src/modules/assets/fetchEpic.test.ts +0 -73
  100. package/src/modules/assets/index.ts +0 -825
  101. package/src/modules/assets/reducer.test.ts +0 -91
  102. package/src/modules/assets/tagsAndListenerEpics.test.ts +0 -206
  103. package/src/modules/debug/index.ts +0 -28
  104. package/src/modules/dialog/actions.ts +0 -10
  105. package/src/modules/dialog/epics.test.ts +0 -168
  106. package/src/modules/dialog/index.ts +0 -238
  107. package/src/modules/dialog/reducer.test.ts +0 -185
  108. package/src/modules/index.ts +0 -124
  109. package/src/modules/notifications/epics.test.ts +0 -374
  110. package/src/modules/notifications/index.ts +0 -199
  111. package/src/modules/notifications/reducer.test.ts +0 -54
  112. package/src/modules/search/index.test.ts +0 -36
  113. package/src/modules/search/index.ts +0 -167
  114. package/src/modules/selected/index.ts +0 -22
  115. package/src/modules/selectors.test.ts +0 -21
  116. package/src/modules/selectors.ts +0 -17
  117. package/src/modules/tags/epics.test.ts +0 -96
  118. package/src/modules/tags/index.test.ts +0 -42
  119. package/src/modules/tags/index.ts +0 -540
  120. package/src/modules/types.ts +0 -3
  121. package/src/modules/uploads/actions.ts +0 -13
  122. package/src/modules/uploads/epics.test.ts +0 -109
  123. package/src/modules/uploads/index.test.ts +0 -59
  124. package/src/modules/uploads/index.ts +0 -282
  125. package/src/operators/checkTagName.test.ts +0 -29
  126. package/src/operators/checkTagName.ts +0 -33
  127. package/src/operators/debugThrottle.ts +0 -25
  128. package/src/plugin.tsx +0 -54
  129. package/src/schemas/tag.ts +0 -28
  130. package/src/styled/GlobalStyles/index.tsx +0 -40
  131. package/src/styled/react-select/creatable.tsx +0 -184
  132. package/src/styled/react-select/single.tsx +0 -184
  133. package/src/types/index.ts +0 -379
  134. package/src/types/sanity-ui.d.ts +0 -6
  135. package/src/utils/applyMediaTags.ts +0 -87
  136. package/src/utils/blocksToText.test.ts +0 -43
  137. package/src/utils/blocksToText.ts +0 -27
  138. package/src/utils/constructFilter.test.ts +0 -120
  139. package/src/utils/constructFilter.ts +0 -98
  140. package/src/utils/generatePreviewBlobUrl.test.ts +0 -70
  141. package/src/utils/generatePreviewBlobUrl.ts +0 -53
  142. package/src/utils/getAssetResolution.test.ts +0 -13
  143. package/src/utils/getAssetResolution.ts +0 -7
  144. package/src/utils/getDocumentAssetIds.test.ts +0 -50
  145. package/src/utils/getDocumentAssetIds.ts +0 -35
  146. package/src/utils/getSchemeColor.test.ts +0 -12
  147. package/src/utils/getSchemeColor.ts +0 -43
  148. package/src/utils/getTagSelectOptions.test.ts +0 -44
  149. package/src/utils/getTagSelectOptions.ts +0 -16
  150. package/src/utils/getUniqueDocuments.test.ts +0 -26
  151. package/src/utils/getUniqueDocuments.ts +0 -15
  152. package/src/utils/imageDprUrl.test.ts +0 -46
  153. package/src/utils/imageDprUrl.ts +0 -27
  154. package/src/utils/isSupportedAssetType.test.ts +0 -16
  155. package/src/utils/isSupportedAssetType.ts +0 -15
  156. package/src/utils/mediaField.ts +0 -73
  157. package/src/utils/sanitizeFormData.test.ts +0 -59
  158. package/src/utils/sanitizeFormData.ts +0 -26
  159. package/src/utils/typeGuards.test.ts +0 -18
  160. package/src/utils/typeGuards.ts +0 -9
  161. package/src/utils/uploadSanityAsset.test.ts +0 -29
  162. package/src/utils/uploadSanityAsset.ts +0 -97
  163. package/src/utils/withMaxConcurrency.test.ts +0 -43
  164. package/src/utils/withMaxConcurrency.ts +0 -55
  165. package/src/utils/zodFormResolver.ts +0 -17
  166. package/v2-incompatible.js +0 -11
@@ -1,379 +0,0 @@
1
- import type {Action} from '@reduxjs/toolkit'
2
- import type {
3
- SanityAssetDocument,
4
- SanityClient,
5
- SanityDocument,
6
- SanityImageAssetDocument,
7
- } from '@sanity/client'
8
- import type {ComponentType, JSX} from 'react'
9
- import type {Epic} from 'redux-observable'
10
- import * as z from 'zod'
11
-
12
- import type {DetailsProps} from '../components/DialogAssetEdit/Details'
13
- import type {SUPPORTED_ASSET_TYPES} from '../constants'
14
- import {getAssetFormSchema, tagFormSchema, tagOptionSchema} from '../formSchema'
15
- import type {RootReducerState} from '../modules/types'
16
-
17
- export type AssetTypes = (typeof SUPPORTED_ASSET_TYPES)[number]
18
-
19
- export type MediaTagsOptions = {
20
- mediaTags?: string[]
21
- }
22
-
23
- export type MediaToolOptions = {
24
- maximumUploadSize?: number
25
- createTagsOnUpload?: boolean
26
- components?: {
27
- details?: ComponentType<
28
- DetailsProps & {renderDefaultDetails: (props: DetailsProps) => JSX.Element}
29
- >
30
- }
31
- creditLine?: {
32
- enabled: boolean
33
- excludeSources?: string | string[]
34
- }
35
- directUploads?: boolean
36
- /**
37
- * Optional locales following Sanity recommended scheme: [{ id, title }]
38
- * https://www.sanity.io/docs/studio/localization#k4da239411955
39
- */
40
- locales?: Locale[]
41
- }
42
-
43
- export type Locale = {
44
- title: string
45
- id: string
46
- [key: string]: unknown
47
- }
48
-
49
- type LocalizedString = string | Record<string, string>
50
-
51
- type CustomFields = {
52
- altText?: LocalizedString
53
- description?: LocalizedString
54
- opt?: {
55
- media?: {
56
- tags?: SanityReference[]
57
- }
58
- }
59
- title?: LocalizedString
60
- }
61
-
62
- type SearchFacetInputCommon = {
63
- assetTypes: AssetType[]
64
- name: string
65
- operatorType: SearchFacetOperatorType
66
- operatorTypes?: (SearchFacetOperatorType | null)[]
67
- selectOnly?: boolean
68
- title: string
69
- }
70
-
71
- export type Asset = FileAsset | ImageAsset
72
-
73
- export type AssetFormData = z.infer<ReturnType<typeof getAssetFormSchema>>
74
-
75
- export type AssetItem = {
76
- _type: 'asset'
77
- asset: Asset
78
- error?: string
79
- picked: boolean
80
- updating: boolean
81
- }
82
-
83
- export type AssetType = 'file' | 'image'
84
-
85
- export type Block = {
86
- _type: string
87
- _key: string
88
- children: Span[]
89
- markDefs: MarkDef[]
90
- }
91
-
92
- export type BrowserView = 'grid' | 'table'
93
-
94
- export type ButtonVariant = 'danger' | 'default' | 'secondary'
95
-
96
- // TODO: rename
97
- export type CardAssetData = {
98
- id: string
99
- type: 'asset'
100
- }
101
-
102
- export type CardUploadData = {
103
- id: string
104
- type: 'upload'
105
- }
106
-
107
- export type Dialog =
108
- | DialogAssetEditProps
109
- | DialogConfirmProps
110
- | DialogSearchFacetsProps
111
- | DialogTagCreateProps
112
- | DialogTagEditProps
113
- | DialogTagsProps
114
-
115
- export type DialogAction = 'deleteAsset' | 'deleteTag'
116
-
117
- export type DialogAssetEditProps = {
118
- assetId?: string
119
- closeDialogId?: string
120
- id: string
121
- lastCreatedTag?: {
122
- label: string
123
- value: string
124
- }
125
- lastRemovedTagIds?: string[]
126
- type: 'assetEdit'
127
- }
128
-
129
- export type DialogConfirmProps = {
130
- closeDialogId?: string
131
- confirmCallbackAction: Action // TODO: reconsider
132
- confirmText: string
133
- description?: string
134
- headerTitle: string
135
- id: string
136
- title: string
137
- tone: 'critical' | 'primary'
138
- type: 'confirm'
139
- }
140
-
141
- export type DialogSearchFacetsProps = {
142
- closeDialogId?: string
143
- id: string
144
- type: 'searchFacets'
145
- }
146
-
147
- export type DialogTagsProps = {
148
- closeDialogId?: string
149
- id: string
150
- type: 'tags'
151
- }
152
-
153
- export type DialogTagCreateProps = {
154
- closeDialogId?: string
155
- id: string
156
- type: 'tagCreate'
157
- }
158
-
159
- export type DialogTagEditProps = {
160
- closeDialogId?: string
161
- id: string
162
- tagId?: string
163
- type: 'tagEdit'
164
- }
165
-
166
- export type Document = {
167
- _createdAt: string
168
- _id: string
169
- _rev: string
170
- _type: string
171
- _updatedAt: string
172
- name?: string
173
- title?: string
174
- }
175
-
176
- export type HttpError = {
177
- message: string
178
- statusCode: number
179
- }
180
-
181
- export type FileAsset = SanityAssetDocument &
182
- CustomFields & {
183
- _type: 'sanity.fileAsset'
184
- }
185
-
186
- export type ImageAsset = SanityImageAssetDocument &
187
- CustomFields & {
188
- _type: 'sanity.imageAsset'
189
- creditLine?: LocalizedString
190
- }
191
-
192
- export type MarkDef = {_key: string; _type: string}
193
-
194
- export type MyEpic = Epic<
195
- Action,
196
- Action,
197
- RootReducerState,
198
- {
199
- client: SanityClient
200
- }
201
- >
202
-
203
- export type Order = {
204
- direction: OrderDirection
205
- field: string
206
- }
207
-
208
- export type OrderDirection = 'asc' | 'desc'
209
-
210
- export type SanityReference = {
211
- _ref: string
212
- _type: 'reference'
213
- _weak?: boolean
214
- }
215
-
216
- export type SearchFacetInputProps =
217
- | SearchFacetInputNumberProps
218
- | SearchFacetInputSearchableProps
219
- | SearchFacetInputSelectProps
220
- | SearchFacetInputStringProps
221
-
222
- export type SearchFacetDivider = {
223
- type: 'divider'
224
- }
225
-
226
- export type SearchFacetGroup = {
227
- facets: (SearchFacetDivider | SearchFacetGroup | SearchFacetInputProps)[]
228
- title: string
229
- type: 'group'
230
- }
231
-
232
- export type SearchFacetInputNumberModifier = {
233
- fieldModifier?: (fieldName: string) => string
234
- name: string
235
- title: string
236
- }
237
-
238
- export type SearchFacetInputNumberProps = SearchFacetInputCommon & {
239
- field: string
240
- modifier?: string
241
- modifiers?: SearchFacetInputNumberModifier[]
242
- type: 'number'
243
- value?: number
244
- }
245
-
246
- export type SearchFacetInputSearchableProps = SearchFacetInputCommon & {
247
- field: string
248
- name: string
249
- options?: SearchFacetInputSelectListItemProps[]
250
- type: 'searchable'
251
- value?: TagSelectOption
252
- }
253
-
254
- export type SearchFacetInputSelectProps = SearchFacetInputCommon & {
255
- field?: string
256
- options: SearchFacetInputSelectListItemProps[]
257
- type: 'select'
258
- value: string
259
- }
260
-
261
- export type SearchFacetInputSelectListItemProps = {
262
- name: string
263
- title: string
264
- value: string
265
- }
266
-
267
- export type SearchFacetInputStringProps = SearchFacetInputCommon & {
268
- field: string
269
- modifier?: string
270
- type: 'string'
271
- value?: string
272
- }
273
-
274
- export type SearchFacetName =
275
- | 'altText'
276
- | 'creditLine'
277
- | 'description'
278
- | 'fileName'
279
- | 'height'
280
- | 'inCurrentDocument'
281
- | 'inUse'
282
- | 'isOpaque'
283
- | 'orientation'
284
- | 'size'
285
- | 'tag'
286
- | 'title'
287
- | 'type'
288
- | 'width'
289
-
290
- export type SearchFacetOperatorType =
291
- | 'doesNotInclude'
292
- | 'doesNotReference'
293
- | 'empty'
294
- | 'equalTo'
295
- | 'greaterThan'
296
- | 'greaterThanOrEqualTo'
297
- | 'includes'
298
- | 'is'
299
- | 'isNot'
300
- | 'lessThan'
301
- | 'lessThanOrEqualTo'
302
- | 'notEmpty'
303
- | 'references'
304
-
305
- export type SearchFacetOperators = Record<
306
- SearchFacetOperatorType,
307
- {
308
- fn: (value: number | string | undefined, field?: string) => string | undefined
309
- hideInput?: boolean
310
- label: string
311
- }
312
- >
313
-
314
- export type SanityUploadCompleteEvent = {
315
- asset: SanityAssetDocument | SanityImageAssetDocument
316
- id: string
317
- type: 'complete'
318
- }
319
-
320
- export type SanityUploadProgressEvent = {
321
- lengthComputable: boolean
322
- loaded: number
323
- percent: number
324
- stage: 'download' | 'upload'
325
- total: number
326
- type: 'progress'
327
- }
328
-
329
- export type SanityUploadResponseEvent = {
330
- body: {document: Partial<SanityAssetDocument | SanityImageAssetDocument>}
331
- headers: Record<string, string>
332
- method: string
333
- statusCode: number
334
- statusMessage: string
335
- type: 'response'
336
- url: string // preview image?
337
- }
338
-
339
- export type Span = {
340
- _key: string
341
- text: string
342
- marks: string[]
343
- }
344
-
345
- export type Tag = SanityDocument & {
346
- name: {
347
- _type: 'slug'
348
- current: string
349
- }
350
- }
351
-
352
- export type TagActions = 'applyAll' | 'delete' | 'edit' | 'removeAll' | 'search'
353
-
354
- export type TagFormData = z.infer<typeof tagFormSchema>
355
-
356
- export type TagItem = {
357
- _type: 'tag'
358
- tag: Tag
359
- error?: HttpError
360
- picked: boolean
361
- updating: boolean
362
- }
363
-
364
- export type TagSelectOption = z.infer<typeof tagOptionSchema>
365
-
366
- export type UploadItem = {
367
- _type: 'upload'
368
- assetType: AssetType
369
- hash: string
370
- name: string
371
- objectUrl?: string
372
- percent?: number
373
- size: number
374
- status: 'complete' | 'queued' | 'uploading'
375
- }
376
-
377
- export type WithId<T extends SearchFacetInputProps> = T & {
378
- id: string
379
- }
@@ -1,6 +0,0 @@
1
- import {type Theme} from '@sanity/ui'
2
-
3
- declare module 'styled-components' {
4
- // eslint-disable-next-line
5
- interface DefaultTheme extends Theme {}
6
- }
@@ -1,87 +0,0 @@
1
- import type {SanityClient} from '@sanity/client'
2
- import groq from 'groq'
3
- import {nanoid} from 'nanoid'
4
-
5
- import {TAG_DOCUMENT_NAME} from '../constants'
6
- import type {Tag} from '../types'
7
-
8
- type ApplyMediaTagsOptions = {
9
- client: SanityClient
10
- assetId: string
11
- mediaTags: string[]
12
- createTagsOnUpload?: boolean
13
- }
14
-
15
- // Serialize calls per asset so concurrent fields reading the same asset
16
- // don't race each other — the second call always runs after the first commits.
17
- const pendingByAsset = new Map<string, Promise<void>>()
18
-
19
- export function applyMediaTags(options: ApplyMediaTagsOptions): Promise<void> {
20
- const {assetId} = options
21
- const chain = (pendingByAsset.get(assetId) ?? Promise.resolve()).then(() =>
22
- doApplyMediaTags(options),
23
- )
24
- const cleanup = chain
25
- .catch(() => {})
26
- .finally(() => {
27
- if (pendingByAsset.get(assetId) === cleanup) pendingByAsset.delete(assetId)
28
- })
29
- pendingByAsset.set(assetId, cleanup)
30
- return chain
31
- }
32
-
33
- async function doApplyMediaTags({
34
- client,
35
- assetId,
36
- mediaTags,
37
- createTagsOnUpload = true,
38
- }: ApplyMediaTagsOptions): Promise<void> {
39
- if (!mediaTags || mediaTags.length === 0) return
40
-
41
- const resolvedTags = await Promise.all(
42
- mediaTags.map(async (tagName) => {
43
- const existingTag = await client.fetch<Tag | null>(
44
- groq`*[_type == "${TAG_DOCUMENT_NAME}" && name.current == $tagName][0]`,
45
- {tagName},
46
- )
47
- if (existingTag) return existingTag
48
- if (createTagsOnUpload) {
49
- const newTag = await client.create({
50
- _type: TAG_DOCUMENT_NAME,
51
- name: {_type: 'slug', current: tagName},
52
- })
53
- return newTag as Tag
54
- }
55
- return null
56
- }),
57
- )
58
-
59
- const validTags = resolvedTags.filter((tag): tag is Tag => tag !== null)
60
- if (validTags.length === 0) return
61
-
62
- const existing = await client.fetch<{tagIds: string[]} | null>(
63
- groq`*[_id == $assetId][0]{'tagIds': opt.media.tags[]._ref}`,
64
- {assetId},
65
- {useCdn: false}, // bypass CDN cache so we see the latest committed tag refs
66
- )
67
- const existingIds = new Set(existing?.tagIds ?? [])
68
-
69
- const tagReferences = validTags
70
- .filter((tag) => !existingIds.has(tag._id))
71
- .map((tag) => ({
72
- _key: nanoid(),
73
- _ref: tag._id,
74
- _type: 'reference' as const,
75
- _weak: true,
76
- }))
77
-
78
- if (tagReferences.length === 0) return
79
-
80
- await client
81
- .patch(assetId)
82
- .setIfMissing({opt: {}})
83
- .setIfMissing({'opt.media': {}})
84
- .setIfMissing({'opt.media.tags': []})
85
- .append('opt.media.tags', tagReferences)
86
- .commit()
87
- }
@@ -1,43 +0,0 @@
1
- import {describe, expect, it} from 'vitest'
2
-
3
- import type {Block} from '../types'
4
- import blocksToText from './blocksToText'
5
-
6
- describe('blocksToText', () => {
7
- it('returns plain strings unchanged', () => {
8
- expect(blocksToText('hello')).toBe('hello')
9
- expect(blocksToText('')).toBe('')
10
- })
11
-
12
- it('returns empty string for non-array non-string input', () => {
13
- expect(blocksToText(null as unknown as string)).toBe('')
14
- })
15
-
16
- it('joins block children text with blank lines between blocks', () => {
17
- const blocks: Block[] = [
18
- {
19
- _type: 'block',
20
- _key: 'a',
21
- markDefs: [],
22
- children: [{_key: 'a1', text: 'Line one', marks: []}],
23
- },
24
- {
25
- _type: 'block',
26
- _key: 'b',
27
- markDefs: [],
28
- children: [{_key: 'b1', text: 'Line two', marks: []}],
29
- },
30
- ]
31
- expect(blocksToText(blocks)).toBe('Line one\n\nLine two')
32
- })
33
-
34
- it('removes non-block nodes by default', () => {
35
- const blocks = [{_type: 'image', _key: 'i', markDefs: [], children: []}] as unknown as Block[]
36
- expect(blocksToText(blocks)).toBe('')
37
- })
38
-
39
- it('keeps placeholder for non-block nodes when nonTextBehavior is not remove', () => {
40
- const blocks = [{_type: 'image', _key: 'i', markDefs: [], children: []}] as unknown as Block[]
41
- expect(blocksToText(blocks, {nonTextBehavior: 'keep'})).toBe('[image block]')
42
- })
43
- })
@@ -1,27 +0,0 @@
1
- import type {Block} from '../types'
2
-
3
- const defaults = {nonTextBehavior: 'remove'}
4
-
5
- // Serialize portable text to plain text
6
- // Based off: https://www.sanity.io/docs/presenting-block-text#plain-text-serialization
7
-
8
- export default function (blocks: string | Block[] = '', opts = {}) {
9
- if (typeof blocks === 'string') {
10
- return blocks
11
- }
12
-
13
- if (!Array.isArray(blocks)) {
14
- return ''
15
- }
16
-
17
- const options = Object.assign({}, defaults, opts)
18
- return blocks
19
- .map((block) => {
20
- if (block._type !== 'block' || !block.children) {
21
- return options.nonTextBehavior === 'remove' ? '' : `[${block._type} block]`
22
- }
23
-
24
- return block.children.map((child) => child.text).join('')
25
- })
26
- .join('\n\n')
27
- }
@@ -1,120 +0,0 @@
1
- // @vitest-environment node
2
-
3
- import {describe, expect, it} from 'vitest'
4
-
5
- import {inputs} from '../config/searchFacets'
6
- import type {SearchFacetInputProps} from '../types'
7
- import constructFilter from './constructFilter'
8
-
9
- describe('constructFilter', () => {
10
- it('includes base filter that excludes drafts and restricts asset types', () => {
11
- const q = constructFilter({
12
- assetTypes: ['image', 'file'],
13
- searchFacets: [],
14
- searchQuery: undefined,
15
- })
16
-
17
- expect(q).toContain('_type in ["sanity.imageAsset","sanity.fileAsset"]')
18
- expect(q).toContain('!(_id in path("drafts.**"))')
19
- })
20
-
21
- it('limits to a single asset type in picker mode', () => {
22
- const q = constructFilter({
23
- assetTypes: ['image'],
24
- searchFacets: [],
25
- searchQuery: undefined,
26
- })
27
-
28
- expect(q).toContain('_type in ["sanity.imageAsset"]')
29
- })
30
-
31
- it('appends text search on trimmed query', () => {
32
- const q = constructFilter({
33
- assetTypes: ['file', 'image'],
34
- searchFacets: [],
35
- searchQuery: ' hello ',
36
- })
37
-
38
- expect(q).toContain(
39
- "[_id, altText, assetId, creditLine, description, originalFilename, title, url] match '*hello*'",
40
- )
41
- })
42
-
43
- it('composes number facet with field modifier (size / KB)', () => {
44
- const q = constructFilter({
45
- assetTypes: ['image'],
46
- searchFacets: [{...inputs.size, value: 500} as SearchFacetInputProps],
47
- searchQuery: undefined,
48
- })
49
-
50
- expect(q.replace(/\s+/g, ' ')).toContain('round(size / 1000) > 500')
51
- })
52
-
53
- it('composes searchable tag facet (references)', () => {
54
- const facet = {
55
- ...inputs.tag,
56
- operatorType: 'references' as const,
57
- value: {label: 'T', value: 'tag-id-1'},
58
- } as SearchFacetInputProps
59
-
60
- const q = constructFilter({
61
- assetTypes: ['image', 'file'],
62
- searchFacets: [facet],
63
- searchQuery: undefined,
64
- })
65
-
66
- expect(q).toContain("references('tag-id-1')")
67
- })
68
-
69
- it('composes select facet (inUse)', () => {
70
- const q = constructFilter({
71
- assetTypes: ['image', 'file'],
72
- searchFacets: [structuredClone(inputs.inUse)],
73
- searchQuery: undefined,
74
- })
75
-
76
- expect(q).toContain('count(*[references(^._id)]) > 0')
77
- })
78
-
79
- it('AND-joins base filter, search text, and multiple facets', () => {
80
- const q = constructFilter({
81
- assetTypes: ['image', 'file'],
82
- searchFacets: [{...inputs.title}, {...inputs.inUse}],
83
- searchQuery: 'x',
84
- })
85
-
86
- const parts = q.split(' && ')
87
- expect(parts.length).toBeGreaterThanOrEqual(4)
88
- })
89
-
90
- it('matches snapshot for stable GROQ shape (apiVersion / filter regressions)', () => {
91
- const q = constructFilter({
92
- assetTypes: ['file', 'image'],
93
- searchFacets: [
94
- {...inputs.size, value: 100} as SearchFacetInputProps,
95
- {
96
- ...inputs.tag,
97
- operatorType: 'references',
98
- value: {label: 'Example', value: 'abc123'},
99
- } as SearchFacetInputProps,
100
- ],
101
- searchQuery: 'portrait',
102
- })
103
-
104
- const normalized = q.replace(/\s+/g, ' ').trim()
105
-
106
- expect(normalized).toBe(
107
- '_type in ["sanity.fileAsset","sanity.imageAsset"] && !(_id in path("drafts.**")) && [_id, altText, assetId, creditLine, description, originalFilename, title, url] match \'*portrait*\' && round(size / 1000) > 100 && references(\'abc123\')',
108
- )
109
- })
110
-
111
- it('omits text search fragment when searchQuery is undefined', () => {
112
- const q = constructFilter({
113
- assetTypes: ['image', 'file'],
114
- searchFacets: [],
115
- searchQuery: undefined,
116
- })
117
-
118
- expect(q).not.toContain('match ')
119
- })
120
- })