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.
@@ -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(`![](${url})`)
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
- }
@@ -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
- }