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.
- package/dist/index.d.ts +190 -413
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2532 -3564
- package/dist/index.js.map +1 -1
- package/package.json +29 -35
- package/dist/index.cjs +0 -5753
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -462
- 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 -87
- 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 -492
- package/src/components/DialogConfirm/index.tsx +0 -88
- package/src/components/DialogSearchFacets/index.tsx +0 -42
- package/src/components/DialogTagCreate/DialogTagCreate.test.tsx +0 -121
- package/src/components/DialogTagCreate/index.tsx +0 -103
- package/src/components/DialogTagEdit/DialogTagEdit.test.tsx +0 -165
- package/src/components/DialogTagEdit/index.tsx +0 -190
- 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 -420
- 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 -37
- package/src/contexts/DropzoneDispatchContext.tsx +0 -34
- package/src/contexts/ToolOptionsContext.tsx +0 -65
- package/src/formSchema/index.test.ts +0 -56
- package/src/formSchema/index.ts +0 -39
- package/src/hooks/useBreakpointIndex.ts +0 -49
- package/src/hooks/useKeyPress.ts +0 -39
- package/src/hooks/useOnScreen.ts +0 -34
- 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 -825
- 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 -124
- 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 -282
- 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 -379
- package/src/types/sanity-ui.d.ts +0 -6
- 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 -70
- 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,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
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import {Box} from '@sanity/ui'
|
|
2
|
-
import {Controller} from 'react-hook-form'
|
|
3
|
-
import CreatableSelect from 'react-select/creatable'
|
|
4
|
-
import {useColorSchemeValue} from 'sanity'
|
|
5
|
-
|
|
6
|
-
import useTypedSelector from '../../hooks/useTypedSelector'
|
|
7
|
-
import {reactSelectComponents, reactSelectStyles} from '../../styled/react-select/creatable'
|
|
8
|
-
import type {TagSelectOption} from '../../types'
|
|
9
|
-
import FormFieldInputLabel from '../FormFieldInputLabel'
|
|
10
|
-
|
|
11
|
-
type Props = {
|
|
12
|
-
control: any
|
|
13
|
-
description?: string
|
|
14
|
-
disabled?: boolean
|
|
15
|
-
error?: string
|
|
16
|
-
label: string
|
|
17
|
-
name: string
|
|
18
|
-
onCreateTag: (tagName: string) => void
|
|
19
|
-
options: {
|
|
20
|
-
label: string
|
|
21
|
-
value: string
|
|
22
|
-
}[]
|
|
23
|
-
placeholder?: string
|
|
24
|
-
value?: TagSelectOption[] | null
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const FormFieldInputTags = (props: Props) => {
|
|
28
|
-
const {
|
|
29
|
-
control,
|
|
30
|
-
description,
|
|
31
|
-
disabled,
|
|
32
|
-
error,
|
|
33
|
-
label,
|
|
34
|
-
name,
|
|
35
|
-
onCreateTag,
|
|
36
|
-
options,
|
|
37
|
-
placeholder,
|
|
38
|
-
value,
|
|
39
|
-
} = props
|
|
40
|
-
|
|
41
|
-
const scheme = useColorSchemeValue()
|
|
42
|
-
|
|
43
|
-
// Redux
|
|
44
|
-
const creating = useTypedSelector((state) => state.tags.creating)
|
|
45
|
-
const tagsFetching = useTypedSelector((state) => state.tags.fetching)
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
<Box
|
|
49
|
-
// HACK: force stacking context to ensure react-select dropdown sits above other fields
|
|
50
|
-
style={{zIndex: 2}}
|
|
51
|
-
>
|
|
52
|
-
{/* Label */}
|
|
53
|
-
<FormFieldInputLabel description={description} error={error} label={label} name={name} />
|
|
54
|
-
|
|
55
|
-
{/* Select */}
|
|
56
|
-
<Controller
|
|
57
|
-
control={control}
|
|
58
|
-
defaultValue={value}
|
|
59
|
-
name={name}
|
|
60
|
-
render={({field}) => {
|
|
61
|
-
const {onBlur, onChange, value: controllerValue} = field
|
|
62
|
-
// TODO: investigate overriding `onChange` and updating form state manually.
|
|
63
|
-
// `opt.media.tags` is initialised with `null` as a defaultValue in react-hook-form
|
|
64
|
-
// Ideally, we'd be able to set `opt.media.tags` as null when all items are cleared, rather than
|
|
65
|
-
// setting it to an empty array (which is currently causing false positives in denoting whether the form is dirty)
|
|
66
|
-
//
|
|
67
|
-
// To illustrate this issue:
|
|
68
|
-
// - Edit an asset with no tags
|
|
69
|
-
// - Add a new tag (either an existing one, or create one inline)
|
|
70
|
-
// - Remove the tag you've just created
|
|
71
|
-
//
|
|
72
|
-
// At this point, the form will still be marked as dirty when it shouldnt be
|
|
73
|
-
return (
|
|
74
|
-
<CreatableSelect
|
|
75
|
-
components={reactSelectComponents}
|
|
76
|
-
instanceId="tags"
|
|
77
|
-
isClearable={false} // TODO: re-enable when we're able to correctly (manually) re-validate on clear
|
|
78
|
-
isDisabled={creating || disabled || tagsFetching}
|
|
79
|
-
isLoading={creating}
|
|
80
|
-
isMulti
|
|
81
|
-
name={name}
|
|
82
|
-
noOptionsMessage={() => 'No tags'}
|
|
83
|
-
onBlur={onBlur}
|
|
84
|
-
onChange={onChange}
|
|
85
|
-
onCreateOption={onCreateTag}
|
|
86
|
-
options={options}
|
|
87
|
-
placeholder={tagsFetching ? 'Loading...' : placeholder}
|
|
88
|
-
styles={reactSelectStyles(scheme)}
|
|
89
|
-
value={controllerValue}
|
|
90
|
-
/>
|
|
91
|
-
)
|
|
92
|
-
}}
|
|
93
|
-
/>
|
|
94
|
-
</Box>
|
|
95
|
-
)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export default FormFieldInputTags
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import {Box, TextInput} from '@sanity/ui'
|
|
2
|
-
import {forwardRef} from 'react'
|
|
3
|
-
|
|
4
|
-
import FormFieldInputLabel from '../FormFieldInputLabel'
|
|
5
|
-
|
|
6
|
-
type Props = {
|
|
7
|
-
description?: string
|
|
8
|
-
disabled?: boolean
|
|
9
|
-
error?: string
|
|
10
|
-
label: string
|
|
11
|
-
name: string
|
|
12
|
-
placeholder?: string
|
|
13
|
-
value?: string
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
type Ref = HTMLInputElement
|
|
17
|
-
|
|
18
|
-
const FormFieldInputText = forwardRef<Ref, Props>((props: Props, ref) => {
|
|
19
|
-
const {description, disabled, error, label, name, placeholder, value, ...rest} = props
|
|
20
|
-
|
|
21
|
-
return (
|
|
22
|
-
<Box>
|
|
23
|
-
{/* Label */}
|
|
24
|
-
<FormFieldInputLabel description={description} error={error} label={label} name={name} />
|
|
25
|
-
{/* Input */}
|
|
26
|
-
<TextInput
|
|
27
|
-
{...rest}
|
|
28
|
-
autoComplete="off"
|
|
29
|
-
autoFocus
|
|
30
|
-
defaultValue={value}
|
|
31
|
-
disabled={disabled}
|
|
32
|
-
id={name}
|
|
33
|
-
name={name}
|
|
34
|
-
placeholder={placeholder}
|
|
35
|
-
ref={ref}
|
|
36
|
-
/>
|
|
37
|
-
</Box>
|
|
38
|
-
)
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
export default FormFieldInputText
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import {Box, TextArea} from '@sanity/ui'
|
|
2
|
-
import {forwardRef} from 'react'
|
|
3
|
-
|
|
4
|
-
import FormFieldInputLabel from '../FormFieldInputLabel'
|
|
5
|
-
|
|
6
|
-
type Props = {
|
|
7
|
-
description?: string
|
|
8
|
-
disabled?: boolean
|
|
9
|
-
error?: string
|
|
10
|
-
label: string
|
|
11
|
-
name: string
|
|
12
|
-
placeholder?: string
|
|
13
|
-
rows?: number
|
|
14
|
-
value?: string
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
type Ref = HTMLTextAreaElement
|
|
18
|
-
|
|
19
|
-
const FormFieldInputTextarea = forwardRef<Ref, Props>((props: Props, ref) => {
|
|
20
|
-
const {description, disabled, error, label, name, placeholder, rows, value, ...rest} = props
|
|
21
|
-
|
|
22
|
-
return (
|
|
23
|
-
<Box>
|
|
24
|
-
{/* Label */}
|
|
25
|
-
<FormFieldInputLabel description={description} error={error} label={label} name={name} />
|
|
26
|
-
|
|
27
|
-
{/* Input */}
|
|
28
|
-
<TextArea
|
|
29
|
-
{...rest}
|
|
30
|
-
autoComplete="off"
|
|
31
|
-
defaultValue={value}
|
|
32
|
-
disabled={disabled}
|
|
33
|
-
id={name}
|
|
34
|
-
name={name}
|
|
35
|
-
placeholder={placeholder}
|
|
36
|
-
ref={ref}
|
|
37
|
-
rows={rows}
|
|
38
|
-
/>
|
|
39
|
-
</Box>
|
|
40
|
-
)
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
export default FormFieldInputTextarea
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import {Box, Button, Text, Tooltip} from '@sanity/ui'
|
|
2
|
-
import {format} from 'date-fns'
|
|
3
|
-
import {type ReactNode} from 'react'
|
|
4
|
-
|
|
5
|
-
type Props = {
|
|
6
|
-
disabled: boolean
|
|
7
|
-
isValid: boolean
|
|
8
|
-
lastUpdated?: string
|
|
9
|
-
onClick: () => void
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const FormSubmitButton = (props: Props) => {
|
|
13
|
-
const {disabled, isValid, lastUpdated, onClick} = props
|
|
14
|
-
|
|
15
|
-
let content: ReactNode
|
|
16
|
-
if (isValid) {
|
|
17
|
-
if (lastUpdated) {
|
|
18
|
-
content = (
|
|
19
|
-
<>
|
|
20
|
-
Last updated
|
|
21
|
-
<br /> {format(new Date(lastUpdated), 'PPp')}
|
|
22
|
-
</>
|
|
23
|
-
)
|
|
24
|
-
} else {
|
|
25
|
-
content = 'No unpublished changes'
|
|
26
|
-
}
|
|
27
|
-
} else {
|
|
28
|
-
content =
|
|
29
|
-
'There are validation errors that need to be fixed before this document can be published'
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return (
|
|
33
|
-
<Tooltip
|
|
34
|
-
animate
|
|
35
|
-
content={
|
|
36
|
-
<Box padding={3} style={{maxWidth: '185px'}}>
|
|
37
|
-
<Text muted size={1}>
|
|
38
|
-
{content}
|
|
39
|
-
</Text>
|
|
40
|
-
</Box>
|
|
41
|
-
}
|
|
42
|
-
disabled={'ontouchstart' in window}
|
|
43
|
-
placement="top"
|
|
44
|
-
portal
|
|
45
|
-
>
|
|
46
|
-
<Box>
|
|
47
|
-
<Button
|
|
48
|
-
disabled={disabled}
|
|
49
|
-
fontSize={1}
|
|
50
|
-
onClick={onClick}
|
|
51
|
-
text="Save and close"
|
|
52
|
-
tone="primary"
|
|
53
|
-
/>
|
|
54
|
-
</Box>
|
|
55
|
-
</Tooltip>
|
|
56
|
-
)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export default FormSubmitButton
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import {CloseIcon, Icon, UploadIcon} from '@sanity/icons'
|
|
2
|
-
import {Box, Button, Flex, Inline, Text} from '@sanity/ui'
|
|
3
|
-
import pluralize from 'pluralize'
|
|
4
|
-
|
|
5
|
-
import {useAssetSourceActions} from '../../contexts/AssetSourceDispatchContext'
|
|
6
|
-
import {useDropzoneActions} from '../../contexts/DropzoneDispatchContext'
|
|
7
|
-
import {useToolOptions} from '../../contexts/ToolOptionsContext'
|
|
8
|
-
import useTypedSelector from '../../hooks/useTypedSelector'
|
|
9
|
-
|
|
10
|
-
type Props = {
|
|
11
|
-
onClose?: () => void
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const Header = (props: Props) => {
|
|
15
|
-
const {onClose} = props
|
|
16
|
-
|
|
17
|
-
const {open} = useDropzoneActions()
|
|
18
|
-
const {onSelect} = useAssetSourceActions()
|
|
19
|
-
|
|
20
|
-
// Redux
|
|
21
|
-
const assetTypes = useTypedSelector((state) => state.assets.assetTypes)
|
|
22
|
-
const selectedDocument = useTypedSelector((state) => state.selected.document)
|
|
23
|
-
|
|
24
|
-
const {directUploads} = useToolOptions()
|
|
25
|
-
|
|
26
|
-
// Row: Current document / close button
|
|
27
|
-
return (
|
|
28
|
-
<Box paddingY={2}>
|
|
29
|
-
<Flex align="center" justify="space-between">
|
|
30
|
-
{/* Label */}
|
|
31
|
-
<Box flex={1} marginX={3}>
|
|
32
|
-
<Inline style={{whiteSpace: 'nowrap'}}>
|
|
33
|
-
<Text textOverflow="ellipsis" weight="semibold">
|
|
34
|
-
<span>{onSelect ? `Insert ${assetTypes.join(' or ')}` : 'Browse Assets'}</span>
|
|
35
|
-
</Text>
|
|
36
|
-
|
|
37
|
-
{selectedDocument && (
|
|
38
|
-
<Box display={['none', 'none', 'block']}>
|
|
39
|
-
<Text>
|
|
40
|
-
<span style={{margin: '0 0.5em'}}>
|
|
41
|
-
<Icon symbol="arrow-right" />
|
|
42
|
-
</span>
|
|
43
|
-
<span style={{textTransform: 'capitalize'}}>{selectedDocument._type}</span>
|
|
44
|
-
</Text>
|
|
45
|
-
</Box>
|
|
46
|
-
)}
|
|
47
|
-
</Inline>
|
|
48
|
-
</Box>
|
|
49
|
-
|
|
50
|
-
<Flex marginX={2}>
|
|
51
|
-
{/* Upload */}
|
|
52
|
-
{directUploads && (
|
|
53
|
-
<Button
|
|
54
|
-
fontSize={1}
|
|
55
|
-
icon={UploadIcon}
|
|
56
|
-
mode="bleed"
|
|
57
|
-
onClick={open}
|
|
58
|
-
text={`Upload ${assetTypes.length === 1 ? pluralize(assetTypes[0]) : 'assets'}`}
|
|
59
|
-
/>
|
|
60
|
-
)}
|
|
61
|
-
|
|
62
|
-
{/* Close */}
|
|
63
|
-
{onClose && (
|
|
64
|
-
<Box style={{flexShrink: 0}}>
|
|
65
|
-
<Button
|
|
66
|
-
disabled={!onClose}
|
|
67
|
-
icon={CloseIcon}
|
|
68
|
-
mode="bleed"
|
|
69
|
-
onClick={onClose}
|
|
70
|
-
radius={2}
|
|
71
|
-
/>
|
|
72
|
-
</Box>
|
|
73
|
-
)}
|
|
74
|
-
</Flex>
|
|
75
|
-
</Flex>
|
|
76
|
-
</Box>
|
|
77
|
-
)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export default Header
|