sanity-plugin-media 4.3.6 → 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.
- package/package.json +6 -15
- package/dist/index.cjs +0 -4721
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -239
- package/dist/index.d.cts.map +0 -1
- package/sanity.json +0 -8
- package/src/__tests__/fixtures/createEpicTestStore.ts +0 -28
- package/src/__tests__/fixtures/listenMock.ts +0 -9
- package/src/__tests__/fixtures/mockSanityClient.ts +0 -84
- package/src/__tests__/fixtures/renderWithProviders.tsx +0 -55
- package/src/__tests__/fixtures/rootState.ts +0 -27
- package/src/__tests__/fixtures/withinDialog.ts +0 -28
- package/src/components/AssetGridVirtualized/index.tsx +0 -94
- package/src/components/AssetMetadata/index.tsx +0 -122
- package/src/components/AssetTableVirtualized/index.tsx +0 -73
- package/src/components/AutoTagInputWrapper/index.tsx +0 -85
- package/src/components/Browser/Browser.test.tsx +0 -45
- package/src/components/Browser/index.tsx +0 -90
- package/src/components/Browser/useBrowserInit.ts +0 -126
- package/src/components/ButtonAssetCopy/index.tsx +0 -65
- package/src/components/ButtonViewGroup/index.tsx +0 -39
- package/src/components/CardAsset/CardAsset.test.tsx +0 -323
- package/src/components/CardAsset/index.tsx +0 -290
- package/src/components/CardUpload/index.tsx +0 -161
- package/src/components/Controls/index.tsx +0 -136
- package/src/components/DebugControls/index.tsx +0 -80
- package/src/components/Dialog/index.tsx +0 -11
- package/src/components/DialogAssetEdit/Details.tsx +0 -181
- package/src/components/DialogAssetEdit/DialogAssetEdit.test.tsx +0 -216
- package/src/components/DialogAssetEdit/index.tsx +0 -493
- package/src/components/DialogConfirm/index.tsx +0 -90
- package/src/components/DialogSearchFacets/index.tsx +0 -42
- package/src/components/DialogTagCreate/DialogTagCreate.test.tsx +0 -121
- package/src/components/DialogTagCreate/index.tsx +0 -111
- package/src/components/DialogTagEdit/DialogTagEdit.test.tsx +0 -165
- package/src/components/DialogTagEdit/index.tsx +0 -201
- package/src/components/DialogTags/index.tsx +0 -45
- package/src/components/Dialogs/index.tsx +0 -76
- package/src/components/DocumentList/index.tsx +0 -62
- package/src/components/FileAssetPreview/index.tsx +0 -37
- package/src/components/FileIcon/index.tsx +0 -43
- package/src/components/FormBuilderTool/FormBuilderTool.test.tsx +0 -63
- package/src/components/FormBuilderTool/index.tsx +0 -69
- package/src/components/FormFieldInputLabel/index.tsx +0 -66
- package/src/components/FormFieldInputTags/index.tsx +0 -98
- package/src/components/FormFieldInputText/index.tsx +0 -41
- package/src/components/FormFieldInputTextarea/index.tsx +0 -43
- package/src/components/FormSubmitButton/index.tsx +0 -59
- package/src/components/Header/index.tsx +0 -80
- package/src/components/Image/index.tsx +0 -41
- package/src/components/Items/index.tsx +0 -68
- package/src/components/Notifications/index.tsx +0 -24
- package/src/components/OrderSelect/index.tsx +0 -66
- package/src/components/PickedBar/index.tsx +0 -77
- package/src/components/Progress/index.tsx +0 -38
- package/src/components/ReduxProvider/index.tsx +0 -96
- package/src/components/SearchFacet/index.tsx +0 -66
- package/src/components/SearchFacetNumber/index.tsx +0 -133
- package/src/components/SearchFacetSelect/index.tsx +0 -110
- package/src/components/SearchFacetString/index.tsx +0 -88
- package/src/components/SearchFacetTags/index.tsx +0 -121
- package/src/components/SearchFacets/index.tsx +0 -72
- package/src/components/SearchFacetsControl/index.tsx +0 -140
- package/src/components/TableHeader/index.tsx +0 -110
- package/src/components/TableHeaderItem/index.tsx +0 -61
- package/src/components/TableRowAsset/index.tsx +0 -419
- package/src/components/TableRowUpload/index.tsx +0 -164
- package/src/components/Tag/index.tsx +0 -200
- package/src/components/TagIcon/index.tsx +0 -22
- package/src/components/TagView/index.tsx +0 -39
- package/src/components/TagViewHeader/index.tsx +0 -70
- package/src/components/TagsPanel/index.tsx +0 -40
- package/src/components/TagsVirtualized/index.tsx +0 -160
- package/src/components/TextInputNumber/index.tsx +0 -32
- package/src/components/TextInputSearch/index.tsx +0 -60
- package/src/components/Tool/index.tsx +0 -13
- package/src/components/UploadDropzone/UploadDropzone.test.tsx +0 -40
- package/src/components/UploadDropzone/index.tsx +0 -173
- package/src/config/orders.ts +0 -28
- package/src/config/searchFacets.ts +0 -312
- package/src/constants.ts +0 -87
- package/src/contexts/AssetSourceDispatchContext.tsx +0 -38
- package/src/contexts/DropzoneDispatchContext.tsx +0 -32
- package/src/contexts/ToolOptionsContext.tsx +0 -66
- package/src/formSchema/index.test.ts +0 -56
- package/src/formSchema/index.ts +0 -39
- package/src/hooks/useBreakpointIndex.ts +0 -50
- package/src/hooks/useKeyPress.ts +0 -39
- package/src/hooks/usePortalPopoverProps.ts +0 -13
- package/src/hooks/useTypedSelector.ts +0 -7
- package/src/hooks/useVersionedClient.ts +0 -6
- package/src/index.ts +0 -5
- package/src/modules/assets/actions.ts +0 -42
- package/src/modules/assets/deleteAndUpdateEpics.test.ts +0 -87
- package/src/modules/assets/fetchEpic.test.ts +0 -73
- package/src/modules/assets/index.ts +0 -782
- package/src/modules/assets/reducer.test.ts +0 -91
- package/src/modules/assets/tagsAndListenerEpics.test.ts +0 -206
- package/src/modules/debug/index.ts +0 -28
- package/src/modules/dialog/actions.ts +0 -10
- package/src/modules/dialog/epics.test.ts +0 -168
- package/src/modules/dialog/index.ts +0 -238
- package/src/modules/dialog/reducer.test.ts +0 -185
- package/src/modules/index.ts +0 -117
- package/src/modules/notifications/epics.test.ts +0 -374
- package/src/modules/notifications/index.ts +0 -199
- package/src/modules/notifications/reducer.test.ts +0 -54
- package/src/modules/search/index.test.ts +0 -36
- package/src/modules/search/index.ts +0 -167
- package/src/modules/selected/index.ts +0 -22
- package/src/modules/selectors.test.ts +0 -21
- package/src/modules/selectors.ts +0 -17
- package/src/modules/tags/epics.test.ts +0 -96
- package/src/modules/tags/index.test.ts +0 -42
- package/src/modules/tags/index.ts +0 -540
- package/src/modules/types.ts +0 -3
- package/src/modules/uploads/actions.ts +0 -13
- package/src/modules/uploads/epics.test.ts +0 -109
- package/src/modules/uploads/index.test.ts +0 -59
- package/src/modules/uploads/index.ts +0 -272
- package/src/operators/checkTagName.test.ts +0 -29
- package/src/operators/checkTagName.ts +0 -33
- package/src/operators/debugThrottle.ts +0 -25
- package/src/plugin.tsx +0 -54
- package/src/schemas/tag.ts +0 -28
- package/src/styled/GlobalStyles/index.tsx +0 -40
- package/src/styled/react-select/creatable.tsx +0 -184
- package/src/styled/react-select/single.tsx +0 -184
- package/src/types/index.ts +0 -346
- package/src/types/sanity-ui.d.ts +0 -5
- package/src/utils/applyMediaTags.ts +0 -87
- package/src/utils/blocksToText.test.ts +0 -43
- package/src/utils/blocksToText.ts +0 -27
- package/src/utils/constructFilter.test.ts +0 -120
- package/src/utils/constructFilter.ts +0 -98
- package/src/utils/generatePreviewBlobUrl.test.ts +0 -68
- package/src/utils/generatePreviewBlobUrl.ts +0 -53
- package/src/utils/getAssetResolution.test.ts +0 -13
- package/src/utils/getAssetResolution.ts +0 -7
- package/src/utils/getDocumentAssetIds.test.ts +0 -50
- package/src/utils/getDocumentAssetIds.ts +0 -35
- package/src/utils/getSchemeColor.test.ts +0 -12
- package/src/utils/getSchemeColor.ts +0 -43
- package/src/utils/getTagSelectOptions.test.ts +0 -44
- package/src/utils/getTagSelectOptions.ts +0 -16
- package/src/utils/getUniqueDocuments.test.ts +0 -26
- package/src/utils/getUniqueDocuments.ts +0 -15
- package/src/utils/imageDprUrl.test.ts +0 -46
- package/src/utils/imageDprUrl.ts +0 -27
- package/src/utils/isSupportedAssetType.test.ts +0 -16
- package/src/utils/isSupportedAssetType.ts +0 -15
- package/src/utils/mediaField.ts +0 -73
- package/src/utils/sanitizeFormData.test.ts +0 -59
- package/src/utils/sanitizeFormData.ts +0 -26
- package/src/utils/typeGuards.test.ts +0 -18
- package/src/utils/typeGuards.ts +0 -9
- package/src/utils/uploadSanityAsset.test.ts +0 -29
- package/src/utils/uploadSanityAsset.ts +0 -97
- package/src/utils/withMaxConcurrency.test.ts +0 -43
- package/src/utils/withMaxConcurrency.ts +0 -55
- package/src/utils/zodFormResolver.ts +0 -17
- package/v2-incompatible.js +0 -11
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
import type {MutationEvent} from '@sanity/client'
|
|
2
|
-
import {Box, Button, Card, Flex, Text} from '@sanity/ui'
|
|
3
|
-
import groq from 'groq'
|
|
4
|
-
import {type ReactNode, useCallback, useEffect, useState} from 'react'
|
|
5
|
-
import {type SubmitHandler, useForm} from 'react-hook-form'
|
|
6
|
-
import {useDispatch} from 'react-redux'
|
|
7
|
-
|
|
8
|
-
import {tagFormSchema} from '../../formSchema'
|
|
9
|
-
import useTypedSelector from '../../hooks/useTypedSelector'
|
|
10
|
-
import useVersionedClient from '../../hooks/useVersionedClient'
|
|
11
|
-
import {dialogActions} from '../../modules/dialog'
|
|
12
|
-
import {selectTagById, tagsActions} from '../../modules/tags'
|
|
13
|
-
import type {DialogTagEditProps, Tag, TagFormData} from '../../types'
|
|
14
|
-
import sanitizeFormData from '../../utils/sanitizeFormData'
|
|
15
|
-
import zodFormResolver from '../../utils/zodFormResolver'
|
|
16
|
-
import Dialog from '../Dialog'
|
|
17
|
-
import FormFieldInputText from '../FormFieldInputText'
|
|
18
|
-
import FormSubmitButton from '../FormSubmitButton'
|
|
19
|
-
|
|
20
|
-
type Props = {
|
|
21
|
-
children: ReactNode
|
|
22
|
-
dialog: DialogTagEditProps
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const DialogTagEdit = (props: Props) => {
|
|
26
|
-
const {
|
|
27
|
-
children,
|
|
28
|
-
dialog: {id, tagId},
|
|
29
|
-
} = props
|
|
30
|
-
|
|
31
|
-
const client = useVersionedClient()
|
|
32
|
-
|
|
33
|
-
const dispatch = useDispatch()
|
|
34
|
-
const tagItem = useTypedSelector((state) => selectTagById(state, String(tagId))) // TODO: double check string cast
|
|
35
|
-
|
|
36
|
-
// - Generate a snapshot of the current tag
|
|
37
|
-
const [tagSnapshot, setTagSnapshot] = useState(tagItem?.tag)
|
|
38
|
-
|
|
39
|
-
const currentTag = tagItem ? tagItem?.tag : tagSnapshot
|
|
40
|
-
const generateDefaultValues = useCallback(
|
|
41
|
-
(tag?: Tag) => ({
|
|
42
|
-
name: tag?.name?.current || '',
|
|
43
|
-
}),
|
|
44
|
-
[],
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
const {
|
|
48
|
-
// Read the formState before render to subscribe the form state through Proxy
|
|
49
|
-
formState: {errors, isDirty, isValid},
|
|
50
|
-
handleSubmit,
|
|
51
|
-
register,
|
|
52
|
-
reset,
|
|
53
|
-
setError,
|
|
54
|
-
} = useForm<TagFormData>({
|
|
55
|
-
defaultValues: generateDefaultValues(tagItem?.tag),
|
|
56
|
-
mode: 'onChange',
|
|
57
|
-
resolver: zodFormResolver<TagFormData>(tagFormSchema),
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
const formUpdating = !tagItem || tagItem?.updating
|
|
61
|
-
|
|
62
|
-
const handleClose = () => {
|
|
63
|
-
dispatch(dialogActions.remove({id}))
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Submit react-hook-form
|
|
67
|
-
const onSubmit: SubmitHandler<TagFormData> = (formData) => {
|
|
68
|
-
if (!tagItem?.tag) {
|
|
69
|
-
return
|
|
70
|
-
}
|
|
71
|
-
const sanitizedFormData = sanitizeFormData(formData)
|
|
72
|
-
dispatch(
|
|
73
|
-
tagsActions.updateRequest({
|
|
74
|
-
closeDialogId: tagItem?.tag?._id,
|
|
75
|
-
formData: {
|
|
76
|
-
name: {
|
|
77
|
-
_type: 'slug',
|
|
78
|
-
current: sanitizedFormData['name'],
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
tag: tagItem?.tag,
|
|
82
|
-
}),
|
|
83
|
-
)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const handleDelete = () => {
|
|
87
|
-
if (!tagItem?.tag) {
|
|
88
|
-
return
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
dispatch(
|
|
92
|
-
dialogActions.showConfirmDeleteTag({
|
|
93
|
-
closeDialogId: tagItem?.tag?._id,
|
|
94
|
-
tag: tagItem?.tag,
|
|
95
|
-
}),
|
|
96
|
-
)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const handleTagUpdate = useCallback(
|
|
100
|
-
(update: MutationEvent) => {
|
|
101
|
-
const {result, transition} = update
|
|
102
|
-
if (result && transition === 'update') {
|
|
103
|
-
// Regenerate snapshot
|
|
104
|
-
setTagSnapshot(result as Tag)
|
|
105
|
-
// Reset react-hook-form
|
|
106
|
-
reset(generateDefaultValues(result as Tag))
|
|
107
|
-
}
|
|
108
|
-
},
|
|
109
|
-
[reset, generateDefaultValues],
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
useEffect(() => {
|
|
113
|
-
if (tagItem?.error) {
|
|
114
|
-
setError('name', {
|
|
115
|
-
message: tagItem.error?.message,
|
|
116
|
-
})
|
|
117
|
-
}
|
|
118
|
-
}, [setError, tagItem?.error])
|
|
119
|
-
|
|
120
|
-
// - Listen for asset mutations and update snapshot
|
|
121
|
-
useEffect(() => {
|
|
122
|
-
if (!tagItem?.tag) {
|
|
123
|
-
return undefined
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Remember that Sanity listeners ignore joins, order clauses and projections
|
|
127
|
-
const subscriptionAsset = client
|
|
128
|
-
.listen(groq`*[_id == $id]`, {id: tagItem?.tag._id})
|
|
129
|
-
.subscribe(handleTagUpdate)
|
|
130
|
-
|
|
131
|
-
return () => {
|
|
132
|
-
subscriptionAsset?.unsubscribe()
|
|
133
|
-
}
|
|
134
|
-
}, [client, handleTagUpdate, tagItem?.tag])
|
|
135
|
-
|
|
136
|
-
const Footer = () => (
|
|
137
|
-
<Box padding={3}>
|
|
138
|
-
<Flex justify="space-between">
|
|
139
|
-
{/* Delete button */}
|
|
140
|
-
<Button
|
|
141
|
-
disabled={formUpdating}
|
|
142
|
-
fontSize={1}
|
|
143
|
-
mode="bleed"
|
|
144
|
-
onClick={handleDelete}
|
|
145
|
-
text="Delete"
|
|
146
|
-
tone="critical"
|
|
147
|
-
/>
|
|
148
|
-
|
|
149
|
-
{/* Submit button */}
|
|
150
|
-
<FormSubmitButton
|
|
151
|
-
disabled={formUpdating || !isDirty || !isValid}
|
|
152
|
-
isValid={isValid}
|
|
153
|
-
lastUpdated={tagItem?.tag?._updatedAt}
|
|
154
|
-
onClick={handleSubmit(onSubmit)}
|
|
155
|
-
/>
|
|
156
|
-
</Flex>
|
|
157
|
-
</Box>
|
|
158
|
-
)
|
|
159
|
-
|
|
160
|
-
if (!currentTag) {
|
|
161
|
-
return null
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return (
|
|
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
|
-
>
|
|
174
|
-
{/* Form fields */}
|
|
175
|
-
<Box as="form" padding={4} onSubmit={handleSubmit(onSubmit)}>
|
|
176
|
-
{/* Deleted notification */}
|
|
177
|
-
{!tagItem && (
|
|
178
|
-
<Card marginBottom={3} padding={3} radius={2} shadow={1} tone="critical">
|
|
179
|
-
<Text size={1}>This tag cannot be found – it may have been deleted.</Text>
|
|
180
|
-
</Card>
|
|
181
|
-
)}
|
|
182
|
-
|
|
183
|
-
{/* Hidden button to enable enter key submissions */}
|
|
184
|
-
<button style={{display: 'none'}} tabIndex={-1} type="submit" />
|
|
185
|
-
|
|
186
|
-
{/* Title */}
|
|
187
|
-
<FormFieldInputText
|
|
188
|
-
{...register('name')}
|
|
189
|
-
disabled={formUpdating}
|
|
190
|
-
error={errors?.name?.message}
|
|
191
|
-
label="Name"
|
|
192
|
-
name="name"
|
|
193
|
-
/>
|
|
194
|
-
</Box>
|
|
195
|
-
|
|
196
|
-
{children}
|
|
197
|
-
</Dialog>
|
|
198
|
-
)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
export default DialogTagEdit
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import {Box} from '@sanity/ui'
|
|
2
|
-
import {type ReactNode, useCallback} from 'react'
|
|
3
|
-
import {useDispatch} from 'react-redux'
|
|
4
|
-
|
|
5
|
-
import {dialogActions} from '../../modules/dialog'
|
|
6
|
-
import type {DialogTagsProps} from '../../types'
|
|
7
|
-
import Dialog from '../Dialog'
|
|
8
|
-
import TagView from '../TagView'
|
|
9
|
-
|
|
10
|
-
type Props = {
|
|
11
|
-
children: ReactNode
|
|
12
|
-
dialog: DialogTagsProps
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const DialogTags = (props: Props) => {
|
|
16
|
-
const {
|
|
17
|
-
children,
|
|
18
|
-
dialog: {id},
|
|
19
|
-
} = props
|
|
20
|
-
|
|
21
|
-
// Redux
|
|
22
|
-
const dispatch = useDispatch()
|
|
23
|
-
|
|
24
|
-
// Callbacks
|
|
25
|
-
const handleClose = useCallback(() => {
|
|
26
|
-
dispatch(dialogActions.clear())
|
|
27
|
-
}, [dispatch])
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<Dialog animate header="All Tags" id={id} onClose={handleClose} width={1}>
|
|
31
|
-
<Box
|
|
32
|
-
style={{
|
|
33
|
-
height: '100%',
|
|
34
|
-
minHeight: '420px', // explicit height required as <TagView> is virtualized
|
|
35
|
-
}}
|
|
36
|
-
>
|
|
37
|
-
<TagView />
|
|
38
|
-
</Box>
|
|
39
|
-
|
|
40
|
-
{children}
|
|
41
|
-
</Dialog>
|
|
42
|
-
)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export default DialogTags
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import useTypedSelector from '../../hooks/useTypedSelector'
|
|
2
|
-
import type {Dialog} from '../../types'
|
|
3
|
-
import DialogAssetEdit from '../DialogAssetEdit'
|
|
4
|
-
import DialogConfirm from '../DialogConfirm'
|
|
5
|
-
import DialogSearchFacets from '../DialogSearchFacets'
|
|
6
|
-
import DialogTagCreate from '../DialogTagCreate'
|
|
7
|
-
import DialogTagEdit from '../DialogTagEdit'
|
|
8
|
-
import DialogTags from '../DialogTags'
|
|
9
|
-
|
|
10
|
-
const Dialogs = () => {
|
|
11
|
-
// Redux
|
|
12
|
-
const currentDialogs = useTypedSelector((state) => state.dialog.items)
|
|
13
|
-
|
|
14
|
-
const renderDialogs = (dialogs: Dialog[], index: number) => {
|
|
15
|
-
if (dialogs.length === 0 || index >= dialogs.length) {
|
|
16
|
-
return null
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const dialog = dialogs[index]!
|
|
20
|
-
const childDialogs = renderDialogs(dialogs, index + 1)
|
|
21
|
-
|
|
22
|
-
if (dialog.type === 'assetEdit') {
|
|
23
|
-
return (
|
|
24
|
-
<DialogAssetEdit dialog={dialog} key={index}>
|
|
25
|
-
{childDialogs}
|
|
26
|
-
</DialogAssetEdit>
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (dialog.type === 'confirm') {
|
|
31
|
-
return (
|
|
32
|
-
<DialogConfirm dialog={dialog} key={index}>
|
|
33
|
-
{childDialogs}
|
|
34
|
-
</DialogConfirm>
|
|
35
|
-
)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (dialog.type === 'searchFacets') {
|
|
39
|
-
return (
|
|
40
|
-
<DialogSearchFacets dialog={dialog} key={index}>
|
|
41
|
-
{childDialogs}
|
|
42
|
-
</DialogSearchFacets>
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (dialog.type === 'tagCreate') {
|
|
47
|
-
return (
|
|
48
|
-
<DialogTagCreate dialog={dialog} key={index}>
|
|
49
|
-
{childDialogs}
|
|
50
|
-
</DialogTagCreate>
|
|
51
|
-
)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (dialog.type === 'tagEdit') {
|
|
55
|
-
return (
|
|
56
|
-
<DialogTagEdit dialog={dialog} key={index}>
|
|
57
|
-
{childDialogs}
|
|
58
|
-
</DialogTagEdit>
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (dialog.type === 'tags') {
|
|
63
|
-
return (
|
|
64
|
-
<DialogTags dialog={dialog} key={index}>
|
|
65
|
-
{childDialogs}
|
|
66
|
-
</DialogTags>
|
|
67
|
-
)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return null
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return renderDialogs(currentDialogs, 0)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export default Dialogs
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import type {SanityDocument} from '@sanity/client'
|
|
2
|
-
import {Box, Button, Card, Stack, Text} from '@sanity/ui'
|
|
3
|
-
import {Preview, type SchemaType, useSchema} from 'sanity'
|
|
4
|
-
import {useIntentLink} from 'sanity/router'
|
|
5
|
-
|
|
6
|
-
type Props = {
|
|
7
|
-
documents: SanityDocument[]
|
|
8
|
-
isLoading: boolean
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const DocumentList = ({documents, isLoading}: Props) => {
|
|
12
|
-
const schema = useSchema()
|
|
13
|
-
|
|
14
|
-
if (isLoading) {
|
|
15
|
-
return (
|
|
16
|
-
<Text muted size={1}>
|
|
17
|
-
Loading...
|
|
18
|
-
</Text>
|
|
19
|
-
)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (documents.length === 0) {
|
|
23
|
-
return (
|
|
24
|
-
<Text muted size={1}>
|
|
25
|
-
No documents are referencing this asset
|
|
26
|
-
</Text>
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
<Card flex={1} marginBottom={2} padding={2} radius={2} shadow={1}>
|
|
32
|
-
<Stack space={2}>
|
|
33
|
-
{documents?.map((doc) => (
|
|
34
|
-
<ReferringDocument doc={doc} key={doc._id} schemaType={schema.get(doc._type)} />
|
|
35
|
-
))}
|
|
36
|
-
</Stack>
|
|
37
|
-
</Card>
|
|
38
|
-
)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const ReferringDocument = (props: {doc: SanityDocument; schemaType?: SchemaType}) => {
|
|
42
|
-
const {doc, schemaType} = props
|
|
43
|
-
|
|
44
|
-
const {onClick} = useIntentLink({
|
|
45
|
-
intent: 'edit',
|
|
46
|
-
params: {id: doc._id},
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
return schemaType ? (
|
|
50
|
-
<Button key={doc._id} mode="bleed" onClick={onClick} padding={2} style={{width: '100%'}}>
|
|
51
|
-
<Preview layout="default" schemaType={schemaType} value={doc} />
|
|
52
|
-
</Button>
|
|
53
|
-
) : (
|
|
54
|
-
<Box padding={2}>
|
|
55
|
-
<Text size={1}>
|
|
56
|
-
A document of the unknown type <em>{doc._type}</em>
|
|
57
|
-
</Text>
|
|
58
|
-
</Box>
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export default DocumentList
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import {Flex} from '@sanity/ui'
|
|
2
|
-
|
|
3
|
-
import type {Asset} from '../../types'
|
|
4
|
-
import FileIcon from '../FileIcon'
|
|
5
|
-
|
|
6
|
-
type Props = {
|
|
7
|
-
asset: Asset
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const FileAssetPreview = (props: Props) => {
|
|
11
|
-
const {asset} = props
|
|
12
|
-
|
|
13
|
-
if (asset.mimeType.search('audio') === 0) {
|
|
14
|
-
return (
|
|
15
|
-
<Flex align="center" justify="center" style={{height: '100%'}}>
|
|
16
|
-
<audio controls src={asset.url} style={{width: '100%'}} />
|
|
17
|
-
</Flex>
|
|
18
|
-
)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (asset.mimeType.search('video') === 0) {
|
|
22
|
-
return (
|
|
23
|
-
<video
|
|
24
|
-
controls
|
|
25
|
-
src={asset.url}
|
|
26
|
-
style={{
|
|
27
|
-
height: '100%',
|
|
28
|
-
width: '100%',
|
|
29
|
-
}}
|
|
30
|
-
/>
|
|
31
|
-
)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return <FileIcon extension={asset.extension} width="50%" />
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export default FileAssetPreview
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import {Box, Flex, type Theme} from '@sanity/ui'
|
|
2
|
-
import {type MouseEvent} from 'react'
|
|
3
|
-
import {defaultStyles, FileIcon as ReactFileIcon} from 'react-file-icon'
|
|
4
|
-
import type {DefaultExtensionType} from 'react-file-icon'
|
|
5
|
-
import {styled, css} from 'styled-components'
|
|
6
|
-
|
|
7
|
-
type Props = {
|
|
8
|
-
extension?: string
|
|
9
|
-
onClick?: (e: MouseEvent) => void
|
|
10
|
-
width: string
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// Force react-file-icon styles
|
|
14
|
-
const Container = styled(Box)(({theme}: {theme: Theme}) => {
|
|
15
|
-
return css`
|
|
16
|
-
text {
|
|
17
|
-
font-family: ${theme.sanity.fonts.text.family} !important;
|
|
18
|
-
font-size: 8px !important;
|
|
19
|
-
font-weight: 500 !important;
|
|
20
|
-
}
|
|
21
|
-
`
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
const FileIcon = (props: Props) => {
|
|
25
|
-
const {extension, onClick, width} = props
|
|
26
|
-
|
|
27
|
-
return (
|
|
28
|
-
<Flex align="center" justify="center" onClick={onClick} style={{height: '100%'}}>
|
|
29
|
-
<Container style={{width}}>
|
|
30
|
-
{extension ? (
|
|
31
|
-
<ReactFileIcon
|
|
32
|
-
extension={extension}
|
|
33
|
-
{...defaultStyles[extension as DefaultExtensionType]}
|
|
34
|
-
/>
|
|
35
|
-
) : (
|
|
36
|
-
<ReactFileIcon />
|
|
37
|
-
)}
|
|
38
|
-
</Container>
|
|
39
|
-
</Flex>
|
|
40
|
-
)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export default FileIcon
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import {LayerProvider, studioTheme, ThemeProvider, ToastProvider} from '@sanity/ui'
|
|
2
|
-
import {render, screen, waitFor} from '@testing-library/react'
|
|
3
|
-
import {of} from 'rxjs'
|
|
4
|
-
import {ColorSchemeProvider} from 'sanity'
|
|
5
|
-
import {describe, expect, it, vi, beforeEach} from 'vitest'
|
|
6
|
-
|
|
7
|
-
import {createListenMock} from '../../__tests__/fixtures/listenMock'
|
|
8
|
-
import {createMockSanityClient} from '../../__tests__/fixtures/mockSanityClient'
|
|
9
|
-
import {ToolOptionsProvider} from '../../contexts/ToolOptionsContext'
|
|
10
|
-
import useVersionedClient from '../../hooks/useVersionedClient'
|
|
11
|
-
import FormBuilderTool from './index'
|
|
12
|
-
|
|
13
|
-
vi.mock('../../hooks/useVersionedClient', () => ({
|
|
14
|
-
default: vi.fn(),
|
|
15
|
-
}))
|
|
16
|
-
|
|
17
|
-
vi.mock('sanity', async (importOriginal) => {
|
|
18
|
-
const mod = await importOriginal<typeof import('sanity')>()
|
|
19
|
-
return {
|
|
20
|
-
...mod,
|
|
21
|
-
useFormValue: () => ({_id: 'doc-1', _type: 'article'}),
|
|
22
|
-
}
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
describe('FormBuilderTool', () => {
|
|
26
|
-
beforeEach(() => {
|
|
27
|
-
const fetch = vi.fn().mockReturnValue(of({items: []}))
|
|
28
|
-
vi.mocked(useVersionedClient).mockReturnValue(
|
|
29
|
-
createMockSanityClient({
|
|
30
|
-
listen: createListenMock(),
|
|
31
|
-
observable: {fetch},
|
|
32
|
-
}),
|
|
33
|
-
)
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('renders picker header for image asset type', async () => {
|
|
37
|
-
render(
|
|
38
|
-
<ColorSchemeProvider scheme="light">
|
|
39
|
-
<ThemeProvider theme={studioTheme}>
|
|
40
|
-
<ToastProvider>
|
|
41
|
-
<LayerProvider>
|
|
42
|
-
<ToolOptionsProvider options={{creditLine: {enabled: false}}}>
|
|
43
|
-
<FormBuilderTool
|
|
44
|
-
{...({
|
|
45
|
-
assetType: 'image',
|
|
46
|
-
onClose: vi.fn(),
|
|
47
|
-
onSelect: vi.fn(),
|
|
48
|
-
schemaType: {},
|
|
49
|
-
selectedAssets: undefined,
|
|
50
|
-
} as any)}
|
|
51
|
-
/>
|
|
52
|
-
</ToolOptionsProvider>
|
|
53
|
-
</LayerProvider>
|
|
54
|
-
</ToastProvider>
|
|
55
|
-
</ThemeProvider>
|
|
56
|
-
</ColorSchemeProvider>,
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
await waitFor(() => {
|
|
60
|
-
expect(screen.getByText(/Insert image/i)).toBeInTheDocument()
|
|
61
|
-
})
|
|
62
|
-
})
|
|
63
|
-
})
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import {Box, Portal, PortalProvider, useLayer} from '@sanity/ui'
|
|
2
|
-
import {type SyntheticEvent, useEffect, useState} from 'react'
|
|
3
|
-
import {type AssetSourceComponentProps, type SanityDocument, useFormValue} from 'sanity'
|
|
4
|
-
|
|
5
|
-
import useKeyPress from '../../hooks/useKeyPress'
|
|
6
|
-
import Browser from '../Browser'
|
|
7
|
-
|
|
8
|
-
const FormBuilderTool = (props: AssetSourceComponentProps) => {
|
|
9
|
-
const {onClose} = props
|
|
10
|
-
|
|
11
|
-
const portalElement = useRootPortalElement()
|
|
12
|
-
|
|
13
|
-
// Get current Sanity document
|
|
14
|
-
const currentDocument = useFormValue([]) as SanityDocument
|
|
15
|
-
|
|
16
|
-
// Close on escape key press
|
|
17
|
-
useKeyPress('escape', onClose)
|
|
18
|
-
|
|
19
|
-
// Stop propagation and prevent document mouse events from firing.
|
|
20
|
-
// This is a bit of a hack to make this work with `editModal = 'popover'` and prevent Sanity's <Popover /> component from
|
|
21
|
-
// prematurely closing, as it attaches events on `document` to detect outside clicks.
|
|
22
|
-
const handleStopPropagation = (event: SyntheticEvent) => {
|
|
23
|
-
event.nativeEvent.stopImmediatePropagation()
|
|
24
|
-
event.stopPropagation()
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const {zIndex} = useLayer()
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<PortalProvider element={portalElement}>
|
|
31
|
-
<Portal>
|
|
32
|
-
<Box
|
|
33
|
-
onDragEnter={handleStopPropagation}
|
|
34
|
-
onDragLeave={handleStopPropagation}
|
|
35
|
-
onDragOver={handleStopPropagation}
|
|
36
|
-
onDrop={handleStopPropagation}
|
|
37
|
-
onMouseUp={handleStopPropagation}
|
|
38
|
-
style={{
|
|
39
|
-
bottom: 0,
|
|
40
|
-
height: 'auto',
|
|
41
|
-
left: 0,
|
|
42
|
-
position: 'fixed',
|
|
43
|
-
top: 0,
|
|
44
|
-
width: '100%',
|
|
45
|
-
zIndex,
|
|
46
|
-
}}
|
|
47
|
-
>
|
|
48
|
-
<Browser document={currentDocument} schemaType={props.schemaType} {...props} />
|
|
49
|
-
</Box>
|
|
50
|
-
</Portal>
|
|
51
|
-
</PortalProvider>
|
|
52
|
-
)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export default FormBuilderTool
|
|
56
|
-
|
|
57
|
-
const useRootPortalElement = () => {
|
|
58
|
-
const [container] = useState(() => document.createElement('div'))
|
|
59
|
-
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
container.classList.add('media-portal')
|
|
62
|
-
document.body.appendChild(container)
|
|
63
|
-
return () => {
|
|
64
|
-
document.body.removeChild(container)
|
|
65
|
-
}
|
|
66
|
-
}, [container])
|
|
67
|
-
|
|
68
|
-
return container
|
|
69
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import {ErrorOutlineIcon} from '@sanity/icons'
|
|
2
|
-
import {Box, Inline, Text, Tooltip} from '@sanity/ui'
|
|
3
|
-
import {styled} from 'styled-components'
|
|
4
|
-
|
|
5
|
-
type Props = {
|
|
6
|
-
description?: string
|
|
7
|
-
error?: string
|
|
8
|
-
label: string
|
|
9
|
-
name: string
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const StyledErrorOutlineIcon = styled(ErrorOutlineIcon)(({theme}) => {
|
|
13
|
-
return {
|
|
14
|
-
color: theme.sanity.color.spot.red,
|
|
15
|
-
}
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
const FormFieldInputLabel = (props: Props) => {
|
|
19
|
-
const {description, error, label, name} = props
|
|
20
|
-
|
|
21
|
-
return (
|
|
22
|
-
<>
|
|
23
|
-
{/* Label */}
|
|
24
|
-
<Box marginY={3}>
|
|
25
|
-
<Inline space={2}>
|
|
26
|
-
<Text as="label" htmlFor={name} size={1} weight="semibold">
|
|
27
|
-
{label}
|
|
28
|
-
</Text>
|
|
29
|
-
|
|
30
|
-
{/* Error icon + tooltip */}
|
|
31
|
-
{error && (
|
|
32
|
-
<Text size={1}>
|
|
33
|
-
<Tooltip
|
|
34
|
-
animate
|
|
35
|
-
content={
|
|
36
|
-
<Box padding={2}>
|
|
37
|
-
<Text muted size={1}>
|
|
38
|
-
<StyledErrorOutlineIcon style={{marginRight: '0.1em'}} />
|
|
39
|
-
{error}
|
|
40
|
-
</Text>
|
|
41
|
-
</Box>
|
|
42
|
-
}
|
|
43
|
-
fallbackPlacements={['top', 'left']}
|
|
44
|
-
placement="right"
|
|
45
|
-
portal
|
|
46
|
-
>
|
|
47
|
-
<StyledErrorOutlineIcon />
|
|
48
|
-
</Tooltip>
|
|
49
|
-
</Text>
|
|
50
|
-
)}
|
|
51
|
-
</Inline>
|
|
52
|
-
</Box>
|
|
53
|
-
|
|
54
|
-
{/* Description */}
|
|
55
|
-
{description && (
|
|
56
|
-
<Box marginY={3}>
|
|
57
|
-
<Text htmlFor={name} muted size={1}>
|
|
58
|
-
{description}
|
|
59
|
-
</Text>
|
|
60
|
-
</Box>
|
|
61
|
-
)}
|
|
62
|
-
</>
|
|
63
|
-
)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export default FormFieldInputLabel
|