sanity-plugin-media 4.3.4 → 4.3.6

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 (65) hide show
  1. package/dist/index.cjs +2529 -3561
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +190 -413
  4. package/dist/index.d.cts.map +1 -0
  5. package/dist/index.d.ts +190 -413
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +2532 -3564
  8. package/dist/index.js.map +1 -1
  9. package/package.json +28 -25
  10. package/src/__tests__/fixtures/mockSanityClient.ts +3 -3
  11. package/src/components/AssetGridVirtualized/index.tsx +3 -3
  12. package/src/components/AssetMetadata/index.tsx +1 -1
  13. package/src/components/AssetTableVirtualized/index.tsx +2 -2
  14. package/src/components/AutoTagInputWrapper/index.tsx +1 -3
  15. package/src/components/CardAsset/CardAsset.test.tsx +6 -6
  16. package/src/components/DialogAssetEdit/Details.tsx +2 -2
  17. package/src/components/DialogAssetEdit/DialogAssetEdit.test.tsx +1 -1
  18. package/src/components/DialogAssetEdit/index.tsx +5 -4
  19. package/src/components/DialogConfirm/index.tsx +2 -0
  20. package/src/components/DialogSearchFacets/index.tsx +1 -1
  21. package/src/components/DialogTagCreate/index.tsx +10 -2
  22. package/src/components/DialogTagEdit/DialogTagEdit.test.tsx +1 -1
  23. package/src/components/DialogTagEdit/index.tsx +18 -7
  24. package/src/components/DialogTags/index.tsx +1 -1
  25. package/src/components/Dialogs/index.tsx +1 -1
  26. package/src/components/Header/index.tsx +1 -1
  27. package/src/components/Items/index.tsx +1 -1
  28. package/src/components/Notifications/index.tsx +2 -2
  29. package/src/components/SearchFacet/index.tsx +1 -1
  30. package/src/components/SearchFacetSelect/index.tsx +2 -2
  31. package/src/components/SearchFacets/index.tsx +1 -1
  32. package/src/components/TableRowAsset/index.tsx +0 -1
  33. package/src/components/TagsVirtualized/index.tsx +2 -2
  34. package/src/components/UploadDropzone/index.tsx +1 -1
  35. package/src/config/orders.ts +1 -1
  36. package/src/contexts/AssetSourceDispatchContext.tsx +7 -6
  37. package/src/contexts/DropzoneDispatchContext.tsx +2 -4
  38. package/src/contexts/ToolOptionsContext.tsx +1 -0
  39. package/src/formSchema/index.ts +1 -1
  40. package/src/hooks/useBreakpointIndex.ts +5 -4
  41. package/src/modules/assets/deleteAndUpdateEpics.test.ts +2 -2
  42. package/src/modules/assets/fetchEpic.test.ts +1 -1
  43. package/src/modules/assets/index.ts +26 -69
  44. package/src/modules/assets/reducer.test.ts +3 -3
  45. package/src/modules/assets/tagsAndListenerEpics.test.ts +3 -3
  46. package/src/modules/dialog/epics.test.ts +1 -1
  47. package/src/modules/dialog/index.ts +2 -2
  48. package/src/modules/index.ts +3 -10
  49. package/src/modules/notifications/epics.test.ts +5 -5
  50. package/src/modules/notifications/index.ts +1 -1
  51. package/src/modules/search/index.test.ts +2 -2
  52. package/src/modules/search/index.ts +1 -1
  53. package/src/modules/tags/epics.test.ts +2 -2
  54. package/src/modules/tags/index.test.ts +2 -2
  55. package/src/modules/tags/index.ts +19 -19
  56. package/src/modules/uploads/epics.test.ts +2 -2
  57. package/src/modules/uploads/index.test.ts +3 -3
  58. package/src/modules/uploads/index.ts +3 -13
  59. package/src/styled/react-select/creatable.tsx +4 -4
  60. package/src/styled/react-select/single.tsx +9 -9
  61. package/src/types/index.ts +0 -33
  62. package/src/types/sanity-ui.d.ts +0 -1
  63. package/src/utils/generatePreviewBlobUrl.test.ts +0 -2
  64. package/src/utils/getDocumentAssetIds.ts +2 -2
  65. package/src/hooks/useOnScreen.ts +0 -34
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sanity-plugin-media",
3
- "version": "4.3.4",
3
+ "version": "4.3.6",
4
4
  "description": "This version of `sanity-plugin-media` is for Sanity Studio V3.",
5
5
  "keywords": [
6
6
  "asset",
@@ -34,7 +34,6 @@
34
34
  "types": "./dist/index.d.ts",
35
35
  "exports": {
36
36
  ".": {
37
- "source": "./src/index.ts",
38
37
  "import": "./dist/index.js",
39
38
  "require": "./dist/index.cjs",
40
39
  "default": "./dist/index.js"
@@ -42,50 +41,53 @@
42
41
  "./package.json": "./package.json"
43
42
  },
44
43
  "dependencies": {
45
- "@hookform/resolvers": "^3.1.1",
46
- "@reduxjs/toolkit": "^2.6.0",
44
+ "@hookform/resolvers": "^4.1.3",
45
+ "@reduxjs/toolkit": "^2.12.0",
47
46
  "@sanity/client": "^7.23.0",
48
47
  "@sanity/color": "^3.0.6",
49
48
  "@sanity/icons": "^3.7.4",
50
49
  "@sanity/incompatible-plugin": "^1.0.5",
51
50
  "@sanity/ui": "^3.2.0",
52
- "@sanity/uuid": "^3.0.1",
53
- "@tanem/react-nprogress": "^5.0.55",
54
- "copy-to-clipboard": "^3.3.1",
51
+ "@sanity/uuid": "^3.0.3",
52
+ "@tanem/react-nprogress": "^5.0.63",
53
+ "copy-to-clipboard": "^3.3.3",
55
54
  "date-fns": "^4.0.0",
56
- "filesize": "^9.0.0",
57
- "groq": "^3.0.0",
55
+ "filesize": "^9.0.11",
56
+ "groq": "^6.1.0",
58
57
  "is-hotkey-esm": "^1.0.0",
59
- "nanoid": "^3.3.8",
58
+ "nanoid": "^3.3.12",
60
59
  "pluralize": "^8.0.0",
61
- "react-dropzone": "^11.3.1",
60
+ "react-dropzone": "^11.7.1",
62
61
  "react-file-icon": "^1.6.0",
63
- "react-hook-form": "^7.54.2",
64
- "react-redux": "^9.2.0",
65
- "react-select": "^5.10.1",
66
- "react-virtuoso": "^4.12.5",
62
+ "react-hook-form": "^7.79.0",
63
+ "react-redux": "^9.3.0",
64
+ "react-select": "^5.10.2",
65
+ "react-virtuoso": "^4.18.7",
67
66
  "redux": "^5.0.1",
68
67
  "redux-observable": "3.0.0-rc.2",
69
- "rxjs": "^7.8.1",
70
- "zod": "^3.21.4"
68
+ "rxjs": "^7.8.2",
69
+ "zod": "^3.25.76"
71
70
  },
72
71
  "devDependencies": {
73
72
  "@sanity/pkg-utils": "^10.5.7",
74
- "@testing-library/jest-dom": "^6.6.3",
75
- "@testing-library/react": "^16.2.0",
73
+ "@testing-library/jest-dom": "^6.9.1",
74
+ "@testing-library/react": "^16.3.2",
76
75
  "@testing-library/user-event": "^14.6.1",
77
76
  "@types/pluralize": "^0.0.33",
78
77
  "@types/react": "^19.2.17",
79
78
  "@types/react-dom": "^19.2.3",
80
79
  "@types/react-file-icon": "^1.0.4",
81
- "jsdom": "^25.0.1",
80
+ "babel-plugin-styled-components": "^2.3.0",
81
+ "jsdom": "^29.1.1",
82
82
  "react": "^19.2.7",
83
83
  "react-dom": "^19.2.7",
84
- "react-is": "^19.0.0",
84
+ "react-is": "^19.2.7",
85
85
  "sanity": "^6.1.0",
86
86
  "styled-components": "^6.4.2",
87
- "typescript": "5.8.2",
88
- "@sanity/plugin-kit": "5.0.0"
87
+ "typescript": "5.9.3",
88
+ "@repo/package.config": "0.0.0",
89
+ "@repo/tsconfig": "0.0.0",
90
+ "@sanity/plugin-kit": "5.0.2"
89
91
  },
90
92
  "peerDependencies": {
91
93
  "react": "^18.3 || ^19",
@@ -99,12 +101,13 @@
99
101
  },
100
102
  "sanityPlugin": {
101
103
  "verifyPackage": {
104
+ "tsconfig": false,
105
+ "tsc": false,
102
106
  "eslintImports": false,
103
107
  "scripts": false
104
108
  }
105
109
  },
106
110
  "scripts": {
107
- "build": "plugin-kit verify-package --silent && pkg-utils build --strict --check --clean",
108
- "watch": "pkg-utils watch --strict"
111
+ "build": "plugin-kit verify-package --silent && pkg-utils build --strict --check --clean"
109
112
  }
110
113
  }
@@ -35,10 +35,10 @@ export function createMockSanityClient(
35
35
 
36
36
  const observable: MockSanityClient['observable'] = {
37
37
  ...observableBase,
38
- ...(observableOverrides ?? {}),
38
+ ...observableOverrides,
39
39
  assets: {
40
40
  ...observableBase.assets,
41
- ...(observableOverrides?.assets ?? {}),
41
+ ...observableOverrides?.assets,
42
42
  },
43
43
  }
44
44
 
@@ -70,7 +70,7 @@ export function mockPatchChain(result: unknown): {
70
70
  return chain
71
71
  }
72
72
 
73
- export function mockTransactionCommit(resolved: unknown = undefined): {
73
+ export function mockTransactionCommit(resolved?: unknown): {
74
74
  patch: ReturnType<typeof vi.fn>
75
75
  delete: ReturnType<typeof vi.fn>
76
76
  commit: ReturnType<typeof vi.fn>
@@ -72,7 +72,7 @@ const AssetGridVirtualized = (props: Props) => {
72
72
  className="media__custom-scrollbar"
73
73
  computeItemKey={(index) => {
74
74
  const item = items[index]
75
- return item?.id
75
+ return item?.id ?? index
76
76
  }}
77
77
  components={{
78
78
  Item: ItemContainer,
@@ -80,8 +80,8 @@ const AssetGridVirtualized = (props: Props) => {
80
80
  }}
81
81
  endReached={onLoadMore}
82
82
  itemContent={(index) => {
83
- const item = items[index]
84
- const selected = selectedIds.includes(item?.id)
83
+ const item = items[index]!
84
+ const selected = selectedIds.includes(item.id)
85
85
  return <VirtualCell item={item} selected={selected} />
86
86
  }}
87
87
  overscan={48}
@@ -59,7 +59,7 @@ const AssetMetadata = (props: Props) => {
59
59
  <Stack space={3}>
60
60
  <Row label="Size" value={filesize(asset?.size, {base: 10, round: 0})} />
61
61
  <Row label="MIME type" value={asset?.mimeType} />
62
- <Row label="Extension" value={(asset?.extension).toUpperCase()} />
62
+ <Row label="Extension" value={asset?.extension?.toUpperCase()} />
63
63
  {isImageAsset(asset) && <Row label="Dimensions" value={getAssetResolution(asset)} />}
64
64
  </Stack>
65
65
  </Box>
@@ -62,8 +62,8 @@ const AssetTableVirtualized = (props: Props) => {
62
62
  }}
63
63
  itemContent={(index) => {
64
64
  const item = items[index]
65
- const selected = selectedIds.includes(item?.id)
66
- return <VirtualRow item={item} selected={selected} />
65
+ const selected = selectedIds.includes(item?.id || '')
66
+ return <VirtualRow item={item!} selected={selected} />
67
67
  }}
68
68
  style={{overflowX: 'hidden'}}
69
69
  />
@@ -79,9 +79,7 @@ export function AutoTagInput(props: AutoTagInputProps) {
79
79
  title: `Failed to apply the media ${label} ${mediaTags.join(', ')}`,
80
80
  })
81
81
  })
82
- }, [currentAssetRef, mediaTags, client, createTagsOnUpload])
82
+ }, [currentAssetRef, mediaTags, client, createTagsOnUpload, toast])
83
83
 
84
84
  return renderDefault(props as InputProps)
85
85
  }
86
-
87
- export default AutoTagInput
@@ -195,7 +195,7 @@ describe('CardAsset', () => {
195
195
 
196
196
  await user.click(clickFooterFilename('photo.png'))
197
197
 
198
- expect(store.getState().assets.byIds['img-1'].picked).toBe(true)
198
+ expect(store.getState().assets.byIds['img-1']!.picked).toBe(true)
199
199
  })
200
200
 
201
201
  it('opens asset edit from the footer when in picker mode', async () => {
@@ -228,7 +228,7 @@ describe('CardAsset', () => {
228
228
  await user.click(clickPreview())
229
229
  setShiftPressed(false)
230
230
 
231
- expect(store.getState().assets.byIds['img-1'].picked).toBe(false)
231
+ expect(store.getState().assets.byIds['img-1']!.picked).toBe(false)
232
232
  })
233
233
 
234
234
  it('shift-clicks on preview to pick a range when not picked and lastPicked is set', async () => {
@@ -250,8 +250,8 @@ describe('CardAsset', () => {
250
250
  await user.click(clickPreview())
251
251
  setShiftPressed(false)
252
252
 
253
- expect(store.getState().assets.byIds['img-1'].picked).toBe(true)
254
- expect(store.getState().assets.byIds['prev-1'].picked).toBe(true)
253
+ expect(store.getState().assets.byIds['img-1']!.picked).toBe(true)
254
+ expect(store.getState().assets.byIds['prev-1']!.picked).toBe(true)
255
255
  })
256
256
 
257
257
  it('shift-clicks on footer to pick a range when not picked', async () => {
@@ -277,8 +277,8 @@ describe('CardAsset', () => {
277
277
  await user.click(clickFooterFilename('photo.png'))
278
278
  setShiftPressed(false)
279
279
 
280
- expect(store.getState().assets.byIds['img-1'].picked).toBe(true)
281
- expect(store.getState().assets.byIds['anchor-9'].picked).toBe(true)
280
+ expect(store.getState().assets.byIds['img-1']!.picked).toBe(true)
281
+ expect(store.getState().assets.byIds['anchor-9']!.picked).toBe(true)
282
282
  })
283
283
 
284
284
  it('shows the selection checkmark when selected and not updating', () => {
@@ -126,7 +126,7 @@ export default function Details({
126
126
  name={`creditLine.${locale.id}`}
127
127
  disabled={
128
128
  formUpdating ||
129
- creditLine?.excludeSources?.includes(currentAsset?.source?.name)
129
+ creditLine?.excludeSources?.includes(currentAsset?.['source']?.name)
130
130
  }
131
131
  />
132
132
  )}
@@ -170,7 +170,7 @@ export default function Details({
170
170
  name="creditLine"
171
171
  value={toStringField(currentAsset?.creditLine)}
172
172
  disabled={
173
- formUpdating || creditLine?.excludeSources?.includes(currentAsset?.source?.name)
173
+ formUpdating || creditLine?.excludeSources?.includes(currentAsset?.['source']?.name)
174
174
  }
175
175
  />
176
176
  )}
@@ -115,7 +115,7 @@ describe('DialogAssetEdit', () => {
115
115
  await user.type(inputByName(/asset details/i, screen, 'title'), 'Hero image')
116
116
  await user.click(dlg.getByRole('button', {name: /save and close/i}))
117
117
 
118
- expect(store.getState().assets.byIds.a1.updating).toBe(true)
118
+ expect(store.getState().assets.byIds['a1']!.updating).toBe(true)
119
119
 
120
120
  await waitFor(() => {
121
121
  let updateAction
@@ -72,9 +72,9 @@ const DialogAssetEdit = (props: Props) => {
72
72
  const makeLocaleObj = (field?: Record<string, string> | string) => {
73
73
  const obj: Record<string, string> = {}
74
74
  for (let i = 0; i < locales.length; i++) {
75
- const locale = locales[i]
75
+ const locale = locales[i]!
76
76
  if (typeof field === 'object' && field && field[locale.id]) {
77
- obj[locale.id] = field[locale.id]
77
+ obj[locale.id] = field[locale.id]!
78
78
  } else if (typeof field === 'string') {
79
79
  // Only populate the first locale to avoid spreading a legacy value
80
80
  // across all languages; the user should fill in other translations manually
@@ -240,9 +240,9 @@ const DialogAssetEdit = (props: Props) => {
240
240
  // Map tags to sanity references
241
241
  opt: {
242
242
  media: {
243
- ...sanitizedFormData.opt.media,
243
+ ...sanitizedFormData['opt'].media,
244
244
  tags:
245
- sanitizedFormData.opt.media.tags?.map((tag: TagSelectOption) => ({
245
+ sanitizedFormData['opt'].media.tags?.map((tag: TagSelectOption) => ({
246
246
  _ref: tag.value,
247
247
  _type: 'reference',
248
248
  _weak: true,
@@ -365,6 +365,7 @@ const DialogAssetEdit = (props: Props) => {
365
365
  return (
366
366
  <Dialog
367
367
  animate
368
+ // oxlint-disable-next-line react/react-compiler
368
369
  footer={<Footer />}
369
370
  header="Asset details"
370
371
  id={id}
@@ -63,7 +63,9 @@ const DialogConfirm = (props: Props) => {
63
63
  return (
64
64
  <Dialog
65
65
  animate
66
+ // oxlint-disable-next-line react/react-compiler
66
67
  footer={<Footer />}
68
+ // oxlint-disable-next-line react/react-compiler
67
69
  header={<Header />}
68
70
  id="confirm"
69
71
  onClose={handleClose}
@@ -25,7 +25,7 @@ const DialogSearchFacets = (props: Props) => {
25
25
  // Callbacks
26
26
  const handleClose = useCallback(() => {
27
27
  dispatch(dialogActions.clear())
28
- }, [])
28
+ }, [dispatch])
29
29
 
30
30
  return (
31
31
  <Dialog animate header="Filters" id={id} onClose={handleClose} width={1}>
@@ -54,7 +54,7 @@ const DialogTagCreate = (props: Props) => {
54
54
  const onSubmit: SubmitHandler<TagFormData> = (formData) => {
55
55
  const sanitizedFormData = sanitizeFormData(formData)
56
56
 
57
- dispatch(tagsActions.createRequest({name: sanitizedFormData.name}))
57
+ dispatch(tagsActions.createRequest({name: sanitizedFormData['name']}))
58
58
  }
59
59
 
60
60
  useEffect(() => {
@@ -79,7 +79,15 @@ const DialogTagCreate = (props: Props) => {
79
79
  )
80
80
 
81
81
  return (
82
- <Dialog animate footer={<Footer />} header="Create Tag" id={id} onClose={handleClose} width={1}>
82
+ <Dialog
83
+ animate
84
+ // oxlint-disable-next-line react/react-compiler
85
+ footer={<Footer />}
86
+ header="Create Tag"
87
+ id={id}
88
+ onClose={handleClose}
89
+ width={1}
90
+ >
83
91
  {/* Form fields */}
84
92
  <Box as="form" padding={4} onSubmit={handleSubmit(onSubmit)}>
85
93
  {/* Hidden button to enable enter key submissions */}
@@ -58,7 +58,7 @@ describe('DialogTagEdit', () => {
58
58
  await user.type(input, 'beta')
59
59
  await user.click(dlg.getByRole('button', {name: /save and close/i}))
60
60
 
61
- expect(store.getState().tags.byIds.t1.updating).toBe(true)
61
+ expect(store.getState().tags.byIds['t1']!.updating).toBe(true)
62
62
  })
63
63
 
64
64
  it('dispatches updateRequest with slug-shaped form data', async () => {
@@ -37,9 +37,12 @@ const DialogTagEdit = (props: Props) => {
37
37
  const [tagSnapshot, setTagSnapshot] = useState(tagItem?.tag)
38
38
 
39
39
  const currentTag = tagItem ? tagItem?.tag : tagSnapshot
40
- const generateDefaultValues = (tag?: Tag) => ({
41
- name: tag?.name?.current || '',
42
- })
40
+ const generateDefaultValues = useCallback(
41
+ (tag?: Tag) => ({
42
+ name: tag?.name?.current || '',
43
+ }),
44
+ [],
45
+ )
43
46
 
44
47
  const {
45
48
  // Read the formState before render to subscribe the form state through Proxy
@@ -72,7 +75,7 @@ const DialogTagEdit = (props: Props) => {
72
75
  formData: {
73
76
  name: {
74
77
  _type: 'slug',
75
- current: sanitizedFormData.name,
78
+ current: sanitizedFormData['name'],
76
79
  },
77
80
  },
78
81
  tag: tagItem?.tag,
@@ -103,7 +106,7 @@ const DialogTagEdit = (props: Props) => {
103
106
  reset(generateDefaultValues(result as Tag))
104
107
  }
105
108
  },
106
- [reset],
109
+ [reset, generateDefaultValues],
107
110
  )
108
111
 
109
112
  useEffect(() => {
@@ -112,7 +115,7 @@ const DialogTagEdit = (props: Props) => {
112
115
  message: tagItem.error?.message,
113
116
  })
114
117
  }
115
- }, [setError, tagItem.error])
118
+ }, [setError, tagItem?.error])
116
119
 
117
120
  // - Listen for asset mutations and update snapshot
118
121
  useEffect(() => {
@@ -159,7 +162,15 @@ const DialogTagEdit = (props: Props) => {
159
162
  }
160
163
 
161
164
  return (
162
- <Dialog animate footer={<Footer />} header="Edit Tag" id={id} onClose={handleClose} width={1}>
165
+ <Dialog
166
+ animate
167
+ // oxlint-disable-next-line react/react-compiler
168
+ footer={<Footer />}
169
+ header="Edit Tag"
170
+ id={id}
171
+ onClose={handleClose}
172
+ width={1}
173
+ >
163
174
  {/* Form fields */}
164
175
  <Box as="form" padding={4} onSubmit={handleSubmit(onSubmit)}>
165
176
  {/* Deleted notification */}
@@ -24,7 +24,7 @@ const DialogTags = (props: Props) => {
24
24
  // Callbacks
25
25
  const handleClose = useCallback(() => {
26
26
  dispatch(dialogActions.clear())
27
- }, [])
27
+ }, [dispatch])
28
28
 
29
29
  return (
30
30
  <Dialog animate header="All Tags" id={id} onClose={handleClose} width={1}>
@@ -16,7 +16,7 @@ const Dialogs = () => {
16
16
  return null
17
17
  }
18
18
 
19
- const dialog = dialogs[index]
19
+ const dialog = dialogs[index]!
20
20
  const childDialogs = renderDialogs(dialogs, index + 1)
21
21
 
22
22
  if (dialog.type === 'assetEdit') {
@@ -55,7 +55,7 @@ const Header = (props: Props) => {
55
55
  icon={UploadIcon}
56
56
  mode="bleed"
57
57
  onClick={open}
58
- text={`Upload ${assetTypes.length === 1 ? pluralize(assetTypes[0]) : 'assets'}`}
58
+ text={`Upload ${assetTypes.length === 1 ? pluralize(assetTypes[0]!) : 'assets'}`}
59
59
  />
60
60
  )}
61
61
 
@@ -38,7 +38,7 @@ const Items = () => {
38
38
  if (breakpointIndex <= 1 && tagsPanelVisible) {
39
39
  dispatch(tagsActions.panelVisibleSet({panelVisible: false}))
40
40
  }
41
- }, [breakpointIndex])
41
+ }, [breakpointIndex, dispatch, tagsPanelVisible])
42
42
 
43
43
  const isEmpty = !hasItems && hasFetchedOnce && !fetching
44
44
 
@@ -9,14 +9,14 @@ const Notifications = () => {
9
9
 
10
10
  useEffect(() => {
11
11
  if (items.length > 0) {
12
- const lastItem = items[items.length - 1]
12
+ const lastItem = items[items.length - 1]!
13
13
  toast.push({
14
14
  closable: true,
15
15
  status: lastItem.status,
16
16
  title: lastItem.title,
17
17
  })
18
18
  }
19
- }, [items.length])
19
+ }, [items, toast])
20
20
 
21
21
  return null
22
22
  }
@@ -17,7 +17,7 @@ type Props = {
17
17
  const Container = styled<typeof Box, {$scheme: ThemeColorSchemeKey}>(Box)(({$scheme, theme}) => {
18
18
  return css`
19
19
  background: ${getSchemeColor($scheme, 'bg')};
20
- border-radius: ${rem(theme.sanity.radius[2])};
20
+ border-radius: ${rem(theme.sanity.radius[2]!)};
21
21
  `
22
22
  })
23
23
 
@@ -86,14 +86,14 @@ const SearchFacetSelect = ({facet}: Props) => {
86
86
  id="list"
87
87
  menu={
88
88
  <Menu>
89
- {options?.map((item, index) => {
89
+ {options?.map((item) => {
90
90
  const selected = item.name === selectedItem?.name
91
91
  return (
92
92
  <MenuItem
93
93
  disabled={selected}
94
94
  fontSize={1}
95
95
  key={item.name}
96
- onClick={() => handleListItemClick(options[index])}
96
+ onClick={() => handleListItemClick(item)}
97
97
  padding={2}
98
98
  text={item.title}
99
99
  />
@@ -14,7 +14,7 @@ type Props = {
14
14
  const StackContainer = styled(Flex)(({theme}: {theme: Theme}) => {
15
15
  return css`
16
16
  > * {
17
- margin-bottom: ${rem(theme.sanity.space[2])};
17
+ margin-bottom: ${rem(theme.sanity.space[2]!)};
18
18
  }
19
19
  `
20
20
  })
@@ -90,7 +90,6 @@ const StyledWarningIcon = styled(WarningFilledIcon)(({theme}) => {
90
90
  }
91
91
  })
92
92
 
93
- // eslint-disable-next-line complexity
94
93
  const TableRowAsset = (props: Props) => {
95
94
  const {id, selected} = props
96
95
 
@@ -145,11 +145,11 @@ const TagsVirtualized = () => {
145
145
  if (typeof item === 'string') {
146
146
  return item
147
147
  }
148
- return item.tag._id
148
+ return item!.tag._id
149
149
  }}
150
150
  isScrolling={setIsScrolling}
151
151
  itemContent={(index) => {
152
- return <VirtualRow isScrolling={isScrolling} item={items[index]} />
152
+ return <VirtualRow isScrolling={isScrolling} item={items[index]!} />
153
153
  }}
154
154
  style={{flex: 1, overflowX: 'hidden'}}
155
155
  totalCount={items.length}
@@ -53,7 +53,7 @@ async function filterFiles(fileList: FileList) {
53
53
  try {
54
54
  await file.slice(0, 1).arrayBuffer()
55
55
  filteredFiles.push(file)
56
- } catch (err) {
56
+ } catch {
57
57
  // do nothing: file is a package or folder
58
58
  }
59
59
  }
@@ -24,5 +24,5 @@ const ORDER_DICTIONARY: Record<string, {asc: string; desc: string}> = {
24
24
  }
25
25
 
26
26
  export const getOrderTitle = (field: string, direction: OrderDirection): string => {
27
- return ORDER_DICTIONARY[field][direction]
27
+ return ORDER_DICTIONARY[field]![direction]
28
28
  }
@@ -1,4 +1,4 @@
1
- import {type ReactNode, createContext, useContext} from 'react'
1
+ import {type ReactNode, createContext, useContext, useMemo} from 'react'
2
2
  import type {AssetSourceComponentProps} from 'sanity'
3
3
 
4
4
  type ContextProps = {
@@ -15,9 +15,12 @@ const AssetSourceDispatchContext = createContext<ContextProps | undefined>(undef
15
15
  export const AssetBrowserDispatchProvider = (props: Props) => {
16
16
  const {children, onSelect} = props
17
17
 
18
- const contextValue: ContextProps = {
19
- onSelect,
20
- }
18
+ const contextValue: ContextProps = useMemo(
19
+ () => ({
20
+ onSelect,
21
+ }),
22
+ [onSelect],
23
+ )
21
24
 
22
25
  return (
23
26
  <AssetSourceDispatchContext.Provider value={contextValue}>
@@ -33,5 +36,3 @@ export const useAssetSourceActions = () => {
33
36
  }
34
37
  return context
35
38
  }
36
-
37
- export default AssetSourceDispatchContext
@@ -1,4 +1,4 @@
1
- import {type ReactNode, createContext, useContext} from 'react'
1
+ import {type ReactNode, createContext, useContext, useMemo} from 'react'
2
2
 
3
3
  type ContextProps = {
4
4
  open: () => void
@@ -14,7 +14,7 @@ const DropzoneDispatchContext = createContext<ContextProps | undefined>(undefine
14
14
  export const DropzoneDispatchProvider = (props: Props) => {
15
15
  const {children, open} = props
16
16
 
17
- const contextValue: ContextProps = {open}
17
+ const contextValue: ContextProps = useMemo(() => ({open}), [open])
18
18
 
19
19
  return (
20
20
  <DropzoneDispatchContext.Provider value={contextValue}>
@@ -30,5 +30,3 @@ export const useDropzoneActions = () => {
30
30
  }
31
31
  return context
32
32
  }
33
-
34
- export default DropzoneDispatchContext
@@ -19,6 +19,7 @@ type Props = {
19
19
  }
20
20
 
21
21
  export const ToolOptionsProvider = ({options, children}: PropsWithChildren<Props>) => {
22
+ // oxlint-disable-next-line react-compiler
22
23
  const value = useMemo<ContextProps>(() => {
23
24
  let creditLineExcludeSources
24
25
 
@@ -1,7 +1,7 @@
1
1
  import * as z from 'zod'
2
2
 
3
3
  // Helper to generate localized string schema
4
- export function localizedStringSchema(locales?: {id: string}[]) {
4
+ function localizedStringSchema(locales?: {id: string}[]) {
5
5
  if (!locales || locales.length === 0) {
6
6
  return z.string().trim().optional()
7
7
  }
@@ -22,10 +22,10 @@ const useBreakpointIndex = (): number => {
22
22
  mediaQueryLists.forEach((mql) => {
23
23
  try {
24
24
  mql.addEventListener('change', handleBreakpoint)
25
- } catch (err) {
25
+ } catch {
26
26
  try {
27
27
  mql.addListener(handleBreakpoint)
28
- } catch (_err) {
28
+ } catch {
29
29
  // Do nothing
30
30
  }
31
31
  }
@@ -33,14 +33,15 @@ const useBreakpointIndex = (): number => {
33
33
  return () => {
34
34
  try {
35
35
  mediaQueryLists.forEach((mql) => mql.removeEventListener('change', handleBreakpoint))
36
- } catch (err) {
36
+ } catch {
37
37
  try {
38
38
  mediaQueryLists.forEach((mql) => mql.removeListener(handleBreakpoint))
39
- } catch (_err) {
39
+ } catch {
40
40
  // Do nothing
41
41
  }
42
42
  }
43
43
  }
44
+ // oxlint-disable-next-line react-hooks/exhaustive-deps - use the hook from `@sanity/ui` instead of this home-rolled one
44
45
  }, [])
45
46
 
46
47
  return value