sanity-plugin-markdown 3.0.1 → 4.1.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/LICENSE +1 -1
- package/README.md +138 -15
- package/lib/_chunks/plugin-b7a179e6.js +162 -0
- package/lib/_chunks/plugin-b7a179e6.js.map +1 -0
- package/lib/_chunks/plugin-ca10aa4c.js +151 -0
- package/lib/_chunks/plugin-ca10aa4c.js.map +1 -0
- package/lib/index.d.ts +108 -0
- package/lib/index.esm.js +2 -1
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +11 -1
- package/lib/index.js.map +1 -1
- package/lib/indexNext.esm.js +2 -0
- package/lib/indexNext.esm.js.map +1 -0
- package/lib/indexNext.js +11 -0
- package/lib/indexNext.js.map +1 -0
- package/package.json +45 -26
- package/src/commonExports.ts +4 -0
- package/src/components/MarkdownInput.tsx +108 -0
- package/src/components/MarkdownInputStyles.tsx +61 -0
- package/src/components/useSimpleMdeReact.tsx +12 -0
- package/src/index.ts +2 -15
- package/src/indexNext.ts +1 -0
- package/src/plugin.tsx +54 -0
- package/src/schema.ts +26 -3
- package/lib/src/index.d.ts +0 -37
- package/src/components/Editor.tsx +0 -134
- package/src/hooks/useDebounce.ts +0 -14
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import MDEditor from '@uiw/react-md-editor'
|
|
2
|
-
import useDebounce from '../hooks/useDebounce'
|
|
3
|
-
import {PatchEvent, SanityClient, set, StringInputProps, unset, useClient} from 'sanity'
|
|
4
|
-
import React, {
|
|
5
|
-
ClipboardEvent,
|
|
6
|
-
forwardRef,
|
|
7
|
-
Ref,
|
|
8
|
-
SetStateAction,
|
|
9
|
-
useCallback,
|
|
10
|
-
useEffect,
|
|
11
|
-
useState,
|
|
12
|
-
DragEvent,
|
|
13
|
-
} from 'react'
|
|
14
|
-
import {Card, useTheme} from '@sanity/ui'
|
|
15
|
-
import rehypeSanitize from 'rehype-sanitize'
|
|
16
|
-
|
|
17
|
-
export const MarkdownEditor = forwardRef(function MarkdownEditor(
|
|
18
|
-
props: StringInputProps,
|
|
19
|
-
ref: Ref<any>
|
|
20
|
-
) {
|
|
21
|
-
const {
|
|
22
|
-
value = '',
|
|
23
|
-
onChange,
|
|
24
|
-
elementProps: {onBlur, onFocus},
|
|
25
|
-
readOnly,
|
|
26
|
-
} = props
|
|
27
|
-
const [editedValue, setEditedValue] = useState<string | undefined>(value)
|
|
28
|
-
const debouncedValue = useDebounce(editedValue, 100)
|
|
29
|
-
// const client = useClient({apiVersion: '2021-03-25'})
|
|
30
|
-
const client = useClient({apiVersion: '2022-01-01'})
|
|
31
|
-
useEffect(() => {
|
|
32
|
-
setEditedValue(value)
|
|
33
|
-
}, [value])
|
|
34
|
-
|
|
35
|
-
useEffect(() => {
|
|
36
|
-
if (!debouncedValue && value) {
|
|
37
|
-
onChange(PatchEvent.from([unset()]))
|
|
38
|
-
} else if (debouncedValue !== value) {
|
|
39
|
-
onChange(PatchEvent.from([set(debouncedValue)]))
|
|
40
|
-
}
|
|
41
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
42
|
-
}, [debouncedValue, onChange])
|
|
43
|
-
|
|
44
|
-
const {sanity: studioTheme} = useTheme()
|
|
45
|
-
const onPaste = useCallback(
|
|
46
|
-
async (event: ClipboardEvent<HTMLDivElement>) => {
|
|
47
|
-
await onImagePasted(event.clipboardData, setEditedValue, client)
|
|
48
|
-
},
|
|
49
|
-
[setEditedValue, client]
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
const onDrop = useCallback(
|
|
53
|
-
async (event: DragEvent<HTMLDivElement>) => {
|
|
54
|
-
event.preventDefault()
|
|
55
|
-
event.stopPropagation()
|
|
56
|
-
if (event.dataTransfer) {
|
|
57
|
-
await onImagePasted(event.dataTransfer, setEditedValue, client)
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
[setEditedValue, client]
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
return (
|
|
64
|
-
<div ref={ref} data-color-mode={studioTheme.color.dark ? 'dark' : 'light'}>
|
|
65
|
-
{readOnly ? (
|
|
66
|
-
<Card border padding={3}>
|
|
67
|
-
<MDEditor.Markdown source={value} rehypePlugins={[[rehypeSanitize]]} />
|
|
68
|
-
</Card>
|
|
69
|
-
) : (
|
|
70
|
-
<MDEditor
|
|
71
|
-
value={editedValue}
|
|
72
|
-
onChange={setEditedValue}
|
|
73
|
-
onBlur={onBlur}
|
|
74
|
-
onFocus={onFocus}
|
|
75
|
-
previewOptions={{
|
|
76
|
-
rehypePlugins: [[rehypeSanitize]],
|
|
77
|
-
}}
|
|
78
|
-
preview="edit"
|
|
79
|
-
onPaste={onPaste}
|
|
80
|
-
onDrop={onDrop}
|
|
81
|
-
/>
|
|
82
|
-
)}
|
|
83
|
-
</div>
|
|
84
|
-
)
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
// https://github.com/uiwjs/react-md-editor/issues/83#issuecomment-1185471844
|
|
88
|
-
async function onImagePasted(
|
|
89
|
-
dataTransfer: DataTransfer,
|
|
90
|
-
setMarkdown: (value: SetStateAction<string | undefined>) => void,
|
|
91
|
-
client: SanityClient
|
|
92
|
-
) {
|
|
93
|
-
const files: File[] = []
|
|
94
|
-
for (let index = 0; index < dataTransfer.items.length; index += 1) {
|
|
95
|
-
const file = dataTransfer.files.item(index)
|
|
96
|
-
|
|
97
|
-
if (file) {
|
|
98
|
-
files.push(file)
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
await Promise.all(
|
|
103
|
-
files.map(async (file) => {
|
|
104
|
-
const url = await client.assets.upload('image', file).then((doc) => `${doc.url}?w=450`)
|
|
105
|
-
const insertedMarkdown = insertToTextArea(``)
|
|
106
|
-
if (!insertedMarkdown) {
|
|
107
|
-
return
|
|
108
|
-
}
|
|
109
|
-
setMarkdown(insertedMarkdown)
|
|
110
|
-
})
|
|
111
|
-
)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function insertToTextArea(insertString: string) {
|
|
115
|
-
const textarea = document.querySelector('textarea')
|
|
116
|
-
if (!textarea) {
|
|
117
|
-
return null
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
let sentence = textarea.value
|
|
121
|
-
const len = sentence.length
|
|
122
|
-
const pos = textarea.selectionStart
|
|
123
|
-
const end = textarea.selectionEnd
|
|
124
|
-
|
|
125
|
-
const front = sentence.slice(0, pos)
|
|
126
|
-
const back = sentence.slice(pos, len)
|
|
127
|
-
|
|
128
|
-
sentence = front + insertString + back
|
|
129
|
-
|
|
130
|
-
textarea.value = sentence
|
|
131
|
-
textarea.selectionEnd = end + insertString.length
|
|
132
|
-
|
|
133
|
-
return sentence
|
|
134
|
-
}
|
package/src/hooks/useDebounce.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import {useState, useEffect} from 'react'
|
|
2
|
-
|
|
3
|
-
export default function useDebounce(value: unknown, delay: number) {
|
|
4
|
-
const [debouncedValue, setDebouncedValue] = useState(value)
|
|
5
|
-
useEffect(() => {
|
|
6
|
-
const handler = setTimeout(() => {
|
|
7
|
-
setDebouncedValue(value)
|
|
8
|
-
}, delay)
|
|
9
|
-
|
|
10
|
-
return () => clearTimeout(handler)
|
|
11
|
-
}, [value, delay])
|
|
12
|
-
|
|
13
|
-
return debouncedValue
|
|
14
|
-
}
|