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,200 +0,0 @@
1
- import {ArrowDownIcon, ArrowUpIcon, CloseIcon, EditIcon, SearchIcon, TrashIcon} from '@sanity/icons'
2
- import {Box, Button, Container, Flex, Text, Tooltip} from '@sanity/ui'
3
- import {type ReactNode} from 'react'
4
- import {useDispatch} from 'react-redux'
5
- import {styled} from 'styled-components'
6
-
7
- import {inputs} from '../../config/searchFacets'
8
- import {PANEL_HEIGHT} from '../../constants'
9
- import useTypedSelector from '../../hooks/useTypedSelector'
10
- import {selectAssetsPicked} from '../../modules/assets'
11
- import {dialogActions} from '../../modules/dialog'
12
- import {DIALOG_ACTIONS} from '../../modules/dialog/actions'
13
- import {searchActions, selectIsSearchFacetTag} from '../../modules/search'
14
- import type {SearchFacetInputSearchableProps, TagActions, TagItem} from '../../types'
15
-
16
- type Props = {
17
- actions?: TagActions[]
18
- tag: TagItem
19
- }
20
-
21
- const TagContainer = styled(Flex)`
22
- height: ${PANEL_HEIGHT}px;
23
- `
24
-
25
- const ButtonContainer = styled(Flex)`
26
- @media (pointer: fine) {
27
- visibility: hidden;
28
- }
29
-
30
- @media (hover: hover) and (pointer: fine) {
31
- ${TagContainer}:hover & {
32
- visibility: visible;
33
- }
34
- }
35
- `
36
-
37
- type TagButtonProps = {
38
- disabled?: boolean
39
- icon: ReactNode
40
- onClick: () => void
41
- tone?: 'critical' | 'primary'
42
- tooltip: string
43
- }
44
-
45
- const TagButton = (props: TagButtonProps) => {
46
- const {disabled, icon, onClick, tone, tooltip} = props
47
-
48
- return (
49
- <Tooltip
50
- animate
51
- content={
52
- <Container padding={2} width={0}>
53
- <Text muted size={1}>
54
- {tooltip}
55
- </Text>
56
- </Container>
57
- }
58
- disabled={'ontouchstart' in window}
59
- placement="top"
60
- portal
61
- >
62
- <Button
63
- disabled={disabled}
64
- fontSize={1}
65
- icon={icon}
66
- mode="bleed"
67
- onClick={onClick}
68
- padding={2}
69
- tone={tone}
70
- />
71
- </Tooltip>
72
- )
73
- }
74
-
75
- const Tag = (props: Props) => {
76
- const {actions, tag} = props
77
-
78
- // Redux
79
- const dispatch = useDispatch()
80
- const assetsPicked = useTypedSelector(selectAssetsPicked)
81
- const isSearchFacetTag = useTypedSelector((state) => selectIsSearchFacetTag(state, tag?.tag?._id))
82
-
83
- // Callbacks
84
- const handleSearchFacetTagRemove = () => {
85
- dispatch(searchActions.facetsRemoveByTag({tagId: tag.tag._id}))
86
- }
87
-
88
- const handleShowAddTagToAssetsDialog = () => {
89
- dispatch(dialogActions.showConfirmAssetsTagAdd({assetsPicked, tag: tag.tag}))
90
- }
91
-
92
- const handleShowRemoveTagFromAssetsDialog = () => {
93
- dispatch(dialogActions.showConfirmAssetsTagRemove({assetsPicked, tag: tag.tag}))
94
- }
95
-
96
- const handleShowTagDeleteDialog = () => {
97
- dispatch(dialogActions.showConfirmDeleteTag({tag: tag.tag}))
98
- }
99
-
100
- const handleShowTagEditDialog = () => {
101
- dispatch(DIALOG_ACTIONS.showTagEdit({tagId: tag?.tag?._id}))
102
- }
103
-
104
- const handleSearchFacetTagAddOrUpdate = () => {
105
- const searchFacet = {
106
- ...inputs.tag,
107
- value: {
108
- label: tag?.tag?.name?.current,
109
- value: tag?.tag?._id,
110
- },
111
- } as SearchFacetInputSearchableProps
112
-
113
- if (isSearchFacetTag) {
114
- dispatch(
115
- searchActions.facetsUpdate({
116
- name: 'tag',
117
- operatorType: 'references',
118
- value: searchFacet.value,
119
- }),
120
- )
121
- } else {
122
- dispatch(searchActions.facetsAdd({facet: searchFacet}))
123
- }
124
- }
125
-
126
- return (
127
- <TagContainer align="center" flex={1} justify="space-between" paddingLeft={3}>
128
- <Box flex={1}>
129
- <Text
130
- muted
131
- size={1}
132
- style={{
133
- opacity: tag?.updating ? 0.5 : 1.0,
134
- userSelect: 'none',
135
- }}
136
- textOverflow="ellipsis"
137
- >
138
- {tag?.tag?.name?.current}
139
- </Text>
140
- </Box>
141
-
142
- <ButtonContainer align="center" style={{flexShrink: 0}}>
143
- {/* Search facet toggle */}
144
- {actions?.includes('search') && (
145
- <TagButton
146
- disabled={tag?.updating}
147
- icon={isSearchFacetTag ? <CloseIcon /> : <SearchIcon />}
148
- onClick={
149
- isSearchFacetTag ? handleSearchFacetTagRemove : handleSearchFacetTagAddOrUpdate
150
- }
151
- tooltip={isSearchFacetTag ? 'Remove filter' : 'Filter by tag'}
152
- />
153
- )}
154
- {/* Edit icon */}
155
- {actions?.includes('edit') && (
156
- <TagButton
157
- disabled={tag?.updating}
158
- icon={<EditIcon />}
159
- onClick={handleShowTagEditDialog}
160
- tone="primary"
161
- tooltip="Edit tag"
162
- />
163
- )}
164
- {/* Apply to all */}
165
- {actions?.includes('applyAll') && (
166
- <TagButton
167
- disabled={tag?.updating}
168
- icon={<ArrowUpIcon />}
169
- onClick={handleShowAddTagToAssetsDialog}
170
- tone="primary"
171
- tooltip="Add tag to selected assets"
172
- />
173
- )}
174
- {/* Remove from all */}
175
- {actions?.includes('removeAll') && (
176
- <TagButton
177
- disabled={tag?.updating}
178
- icon={<ArrowDownIcon />}
179
- onClick={handleShowRemoveTagFromAssetsDialog}
180
- tone="critical"
181
- tooltip="Remove tag from selected assets"
182
- />
183
- )}
184
-
185
- {/* Delete icon */}
186
- {actions?.includes('delete') && (
187
- <TagButton
188
- disabled={tag?.updating}
189
- icon={<TrashIcon />}
190
- onClick={handleShowTagDeleteDialog}
191
- tone="critical"
192
- tooltip="Delete tag"
193
- />
194
- )}
195
- </ButtonContainer>
196
- </TagContainer>
197
- )
198
- }
199
-
200
- export default Tag
@@ -1,22 +0,0 @@
1
- const TagIcon = () => (
2
- <svg
3
- data-sanity-icon="media__tag" // For icon usage with @sanity/ui <Button />
4
- fill="currentColor"
5
- height="1em"
6
- stroke="currentColor"
7
- strokeWidth="0"
8
- viewBox="0 0 512 512"
9
- width="1em"
10
- >
11
- <path
12
- d="M435.25 48h-122.9a14.46 14.46 0 00-10.2 4.2L56.45 297.9a28.85 28.85 0 000 40.7l117 117a28.85 28.85 0 0040.7 0L459.75 210a14.46 14.46 0 004.2-10.2v-123a28.66 28.66 0 00-28.7-28.8z"
13
- fill="none"
14
- strokeLinecap="round"
15
- strokeLinejoin="round"
16
- strokeWidth="32"
17
- />
18
- <path d="M384 160a32 32 0 1132-32 32 32 0 01-32 32z" />
19
- </svg>
20
- )
21
-
22
- export default TagIcon
@@ -1,39 +0,0 @@
1
- import {Box, Flex, Text} from '@sanity/ui'
2
-
3
- import useTypedSelector from '../../hooks/useTypedSelector'
4
- import {selectAssetsPickedLength} from '../../modules/assets'
5
- import {selectTags} from '../../modules/tags'
6
- import TagsVirtualized from '../TagsVirtualized'
7
- import TagViewHeader from '../TagViewHeader'
8
-
9
- const TagView = () => {
10
- const numPickedAssets = useTypedSelector(selectAssetsPickedLength)
11
- const tags = useTypedSelector(selectTags)
12
- const fetching = useTypedSelector((state) => state.tags.fetching)
13
- const fetchCount = useTypedSelector((state) => state.tags.fetchCount)
14
- const fetchComplete = fetchCount !== -1
15
- const hasTags = !fetching && tags?.length > 0
16
- const hasPicked = !!(numPickedAssets > 0)
17
-
18
- return (
19
- <Flex direction="column" flex={1} height="fill">
20
- <TagViewHeader
21
- allowCreate
22
- light={hasPicked}
23
- title={hasPicked ? 'Tags (in selection)' : 'Tags'}
24
- />
25
-
26
- {fetchComplete && !hasTags && (
27
- <Box padding={3}>
28
- <Text muted size={1}>
29
- <em>No tags</em>
30
- </Text>
31
- </Box>
32
- )}
33
-
34
- {hasTags && <TagsVirtualized />}
35
- </Flex>
36
- )
37
- }
38
-
39
- export default TagView
@@ -1,70 +0,0 @@
1
- import {ComposeIcon} from '@sanity/icons'
2
- import {Box, Button, Flex, Inline, Label} from '@sanity/ui'
3
- import {useDispatch} from 'react-redux'
4
- import {useColorSchemeValue} from 'sanity'
5
-
6
- import {PANEL_HEIGHT} from '../../constants'
7
- import useTypedSelector from '../../hooks/useTypedSelector'
8
- import {DIALOG_ACTIONS} from '../../modules/dialog/actions'
9
- import {getSchemeColor} from '../../utils/getSchemeColor'
10
-
11
- type Props = {
12
- allowCreate?: boolean
13
- light?: boolean
14
- title: string
15
- }
16
-
17
- const TagViewHeader = ({allowCreate, light, title}: Props) => {
18
- const scheme = useColorSchemeValue()
19
-
20
- const dispatch = useDispatch()
21
- const tagsCreating = useTypedSelector((state) => state.tags.creating)
22
- const tagsFetching = useTypedSelector((state) => state.tags.fetching)
23
-
24
- const handleTagCreate = () => {
25
- dispatch(DIALOG_ACTIONS.showTagCreate())
26
- }
27
-
28
- return (
29
- <>
30
- <Flex
31
- align="center"
32
- justify="space-between"
33
- paddingLeft={3}
34
- style={{
35
- background: light ? getSchemeColor(scheme, 'bg') : 'inherit',
36
- borderBottom: '1px solid var(--card-border-color)',
37
- flexShrink: 0,
38
- height: `${PANEL_HEIGHT}px`,
39
- }}
40
- >
41
- <Inline space={2}>
42
- <Label size={0}>{title}</Label>
43
- {tagsFetching && (
44
- <Label size={0} style={{opacity: 0.3}}>
45
- Loading...
46
- </Label>
47
- )}
48
- </Inline>
49
- {/* Create new tag button */}
50
- {allowCreate && (
51
- <Box marginRight={1}>
52
- <Button
53
- disabled={tagsCreating}
54
- fontSize={1} //
55
- icon={ComposeIcon}
56
- mode="bleed"
57
- onClick={handleTagCreate}
58
- style={{
59
- background: 'transparent',
60
- boxShadow: 'none',
61
- }}
62
- />
63
- </Box>
64
- )}
65
- </Flex>
66
- </>
67
- )
68
- }
69
-
70
- export default TagViewHeader
@@ -1,40 +0,0 @@
1
- import {Box} from '@sanity/ui'
2
-
3
- import {TAGS_PANEL_WIDTH} from '../../constants'
4
- import useTypedSelector from '../../hooks/useTypedSelector'
5
- import TagView from '../TagView'
6
-
7
- const TagsPanel = () => {
8
- const tagsPanelVisible = useTypedSelector((state) => state.tags.panelVisible)
9
-
10
- if (!tagsPanelVisible) {
11
- return null
12
- }
13
-
14
- return (
15
- <Box
16
- style={{
17
- position: 'relative',
18
- width: TAGS_PANEL_WIDTH,
19
- }}
20
- >
21
- <Box
22
- className="media__custom-scrollbar"
23
- style={{
24
- borderLeft: '1px solid var(--card-border-color)',
25
- height: '100%',
26
- overflowX: 'hidden',
27
- overflowY: 'auto',
28
- position: 'absolute',
29
- right: 0,
30
- top: 0,
31
- width: '100%',
32
- }}
33
- >
34
- <TagView />
35
- </Box>
36
- </Box>
37
- )
38
- }
39
-
40
- export default TagsPanel
@@ -1,160 +0,0 @@
1
- import {Flex, Label} from '@sanity/ui'
2
- import {memo, useState} from 'react'
3
- import {Virtuoso} from 'react-virtuoso'
4
-
5
- import {PANEL_HEIGHT} from '../../constants'
6
- import useTypedSelector from '../../hooks/useTypedSelector'
7
- import {selectAssetsPicked} from '../../modules/assets'
8
- import {selectTags} from '../../modules/tags'
9
- import type {TagActions, TagItem} from '../../types'
10
- import Tag from '../Tag'
11
-
12
- const VirtualRow = memo(
13
- ({
14
- isScrolling,
15
- item,
16
- }: {
17
- isScrolling?: boolean
18
- item:
19
- | string
20
- | (TagItem & {
21
- actions: TagActions[]
22
- })
23
- }) => {
24
- // Render label
25
- if (typeof item === 'string') {
26
- return (
27
- <Flex
28
- align="center"
29
- justify="space-between"
30
- key={item}
31
- paddingX={3}
32
- style={{height: `${PANEL_HEIGHT}px`}}
33
- >
34
- <Label size={0}>{item}</Label>
35
- </Flex>
36
- )
37
- }
38
-
39
- // Render tag - only display actions if we're not in the process of scrolling
40
- return <Tag actions={isScrolling ? undefined : item.actions} key={item.tag?._id} tag={item} />
41
- },
42
- )
43
-
44
- const TagsVirtualized = () => {
45
- const assetsPicked = useTypedSelector(selectAssetsPicked)
46
- const tags = useTypedSelector(selectTags)
47
-
48
- // State
49
- const [isScrolling, setIsScrolling] = useState(false)
50
-
51
- // TODO: refactor, there's most certainly a more performant way to do this
52
-
53
- // Filter out all tag IDS used (across all) and dedupe
54
- const pickedTagIds = assetsPicked?.reduce((acc: string[], val) => {
55
- const assetTagIds = val?.asset?.opt?.media?.tags?.map((tag) => tag._ref) || []
56
- acc = acc.concat(assetTagIds)
57
- return acc
58
- }, [])
59
- const pickedTagIdsUnique = [...new Set(pickedTagIds)]
60
-
61
- // Segment tags into two buckets:
62
- // 1. those which exist in all picked assets ('applied to all')
63
- // 2. those which exist in some picked assets ('applied to some')
64
- const tagIdsSegmented = pickedTagIdsUnique.reduce(
65
- (acc: {appliedToAll: string[]; appliedToSome: string[]}, tagId) => {
66
- const tagIsInEveryAsset = assetsPicked.every((assetItem) => {
67
- const tagIndex =
68
- assetItem.asset.opt?.media?.tags?.findIndex((tag) => tag._ref === tagId) ?? -1
69
- return tagIndex >= 0
70
- })
71
-
72
- if (tagIsInEveryAsset) {
73
- acc.appliedToAll.push(tagId)
74
- } else {
75
- acc.appliedToSome.push(tagId)
76
- }
77
-
78
- return acc
79
- },
80
- {
81
- appliedToAll: [],
82
- appliedToSome: [],
83
- },
84
- )
85
-
86
- const tagsAppliedToAll = tags
87
- .filter((tag) => tagIdsSegmented.appliedToAll.includes(tag.tag._id))
88
- .map((tagItem) => ({
89
- ...tagItem,
90
- actions: ['delete', 'edit', 'removeAll', 'search'] as TagActions[],
91
- }))
92
- const tagsAppliedToSome = tags
93
- .filter((tag) => tagIdsSegmented.appliedToSome.includes(tag.tag._id))
94
- .map((tagItem) => ({
95
- ...tagItem,
96
- actions: ['applyAll', 'delete', 'edit', 'removeAll', 'search'] as TagActions[],
97
- }))
98
- const tagsUnused = tags
99
- .filter((tag) => !pickedTagIdsUnique.includes(tag.tag._id))
100
- .map((tagItem) => ({
101
- ...tagItem,
102
- actions: ['applyAll', 'delete', 'edit', 'search'] as TagActions[],
103
- }))
104
-
105
- let items: (
106
- | string
107
- | (TagItem & {
108
- actions: TagActions[]
109
- })
110
- )[] = []
111
- if (assetsPicked.length === 0) {
112
- items = tags.map((tagItem) => ({
113
- ...tagItem,
114
- actions: ['delete', 'edit', 'search'] as TagActions[],
115
- }))
116
- } else {
117
- if (tagsAppliedToAll?.length > 0) {
118
- items = [
119
- ...items, //
120
- assetsPicked.length === 1 ? 'Used' : 'Used by all',
121
- ...tagsAppliedToAll,
122
- ]
123
- }
124
- if (tagsAppliedToSome?.length > 0) {
125
- items = [
126
- ...items, //
127
- 'Used by some',
128
- ...tagsAppliedToSome,
129
- ]
130
- }
131
- if (tagsUnused?.length > 0) {
132
- items = [
133
- ...items, //
134
- 'Unused',
135
- ...tagsUnused,
136
- ]
137
- }
138
- }
139
-
140
- return (
141
- <Virtuoso
142
- className="media__custom-scrollbar"
143
- computeItemKey={(index) => {
144
- const item = items[index]
145
- if (typeof item === 'string') {
146
- return item
147
- }
148
- return item.tag._id
149
- }}
150
- isScrolling={setIsScrolling}
151
- itemContent={(index) => {
152
- return <VirtualRow isScrolling={isScrolling} item={items[index]} />
153
- }}
154
- style={{flex: 1, overflowX: 'hidden'}}
155
- totalCount={items.length}
156
- />
157
- )
158
- }
159
-
160
- export default TagsVirtualized
@@ -1,32 +0,0 @@
1
- import {TextInput} from '@sanity/ui'
2
- import {type ChangeEvent} from 'react'
3
-
4
- // TODO: use correct type
5
- type Props = any & {
6
- onValueChange: (value: number) => void
7
- value?: number
8
- }
9
-
10
- const TextInputNumber = (props: Props) => {
11
- const {onValueChange, value, ...remainingProps} = props
12
-
13
- const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
14
- const val = e.target.value
15
- const regex = /^[0-9\b]+$/
16
-
17
- // Test for number and strip leading zeroes
18
- if (val === '' || regex.test(val)) {
19
- onValueChange(parseInt(val, 10) || '')
20
- }
21
- }
22
-
23
- return (
24
- <TextInput
25
- {...remainingProps}
26
- onChange={handleChange} //
27
- value={value ?? ''}
28
- />
29
- )
30
- }
31
-
32
- export default TextInputNumber
@@ -1,60 +0,0 @@
1
- import {CloseIcon, SearchIcon} from '@sanity/icons'
2
- import {Box, Flex, TextInput} from '@sanity/ui'
3
- import {type ChangeEvent} from 'react'
4
- import {useDispatch} from 'react-redux'
5
-
6
- import useTypedSelector from '../../hooks/useTypedSelector'
7
- import {searchActions} from '../../modules/search'
8
-
9
- const TextInputSearch = () => {
10
- // Redux
11
- const searchQuery = useTypedSelector((state) => state.search.query)
12
-
13
- // Redux
14
- const dispatch = useDispatch()
15
-
16
- // Callbacks
17
- const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
18
- dispatch(searchActions.querySet({searchQuery: e.currentTarget.value}))
19
- }
20
-
21
- const handleClear = () => {
22
- dispatch(searchActions.querySet({searchQuery: ''}))
23
- }
24
-
25
- return (
26
- <Box style={{position: 'relative'}}>
27
- <TextInput
28
- fontSize={1}
29
- icon={SearchIcon}
30
- onChange={handleChange}
31
- placeholder="Search"
32
- radius={2}
33
- value={searchQuery}
34
- />
35
-
36
- {/* Clear form button */}
37
- {searchQuery.length > 0 && (
38
- <Flex
39
- align="center"
40
- justify="center"
41
- onClick={handleClear}
42
- style={{
43
- cursor: 'pointer',
44
- height: '100%',
45
- opacity: 0.75,
46
- position: 'absolute',
47
- right: 0,
48
- top: 0,
49
- width: '2em',
50
- zIndex: 1, // force stacking context
51
- }}
52
- >
53
- <CloseIcon />
54
- </Flex>
55
- )}
56
- </Box>
57
- )
58
- }
59
-
60
- export default TextInputSearch
@@ -1,13 +0,0 @@
1
- import {Flex} from '@sanity/ui'
2
-
3
- import Browser from '../Browser'
4
-
5
- const Tool = () => {
6
- return (
7
- <Flex direction="column" height="fill" flex={1}>
8
- <Browser />
9
- </Flex>
10
- )
11
- }
12
-
13
- export default Tool
@@ -1,40 +0,0 @@
1
- import {describe, expect, it} from 'vitest'
2
-
3
- import {renderWithProviders} from '../../__tests__/fixtures/renderWithProviders'
4
- import {initialState as assetsInitialState} from '../../modules/assets'
5
- import UploadDropzone from './index'
6
-
7
- describe('UploadDropzone', () => {
8
- it('still renders file input when directUploads is false (dropzone in disabled mode)', () => {
9
- const {container} = renderWithProviders(
10
- <UploadDropzone>
11
- <div />
12
- </UploadDropzone>,
13
- {
14
- toolOptions: {creditLine: {enabled: false}, directUploads: false},
15
- preloaded: {
16
- assets: {...assetsInitialState, assetTypes: ['image', 'file']},
17
- },
18
- },
19
- )
20
-
21
- expect(container.querySelector('input[type="file"]')).toBeTruthy()
22
- })
23
-
24
- it('enables file input when directUploads is true', () => {
25
- const {container} = renderWithProviders(
26
- <UploadDropzone>
27
- <div />
28
- </UploadDropzone>,
29
- {
30
- toolOptions: {creditLine: {enabled: false}, directUploads: true},
31
- preloaded: {
32
- assets: {...assetsInitialState, assetTypes: ['image', 'file']},
33
- },
34
- },
35
- )
36
-
37
- const input = container.querySelector('input[type="file"]')
38
- expect(input).not.toHaveAttribute('disabled')
39
- })
40
- })