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
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -7,26 +7,20 @@
|
|
|
7
7
|
|
|
8
8
|
A Markdown editor with preview for Sanity Studio.
|
|
9
9
|
|
|
10
|
-
Supports Github flavored markdown and image uploads.
|
|
10
|
+
Supports Github flavored markdown and image uploads.
|
|
11
|
+
You can either drag image(s) into the editor or click the bottom bar to bring up a file selector.
|
|
11
12
|
The resulting image URL(s) are inserted with a default width parameter which you can change to your liking using the [Sanity image pipeline parameters](https://www.sanity.io/docs/image-urls).
|
|
12
|
-
|
|
13
|
-
### Known issues with the current v3 version
|
|
14
13
|
|
|
15
|
-
The
|
|
14
|
+
The current version is a wrapper around [React SimpleMDE (EasyMDE) Markdown Editor](https://github.com/RIP21/react-simplemde-editor#react-simplemde-easymde-markdown-editor),
|
|
15
|
+
and by extension, [EasyMDE](https://github.com/Ionaru/easy-markdown-editor).
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
You can still add markdown image tags, but you will have to get the image url yourself for now.
|
|
17
|
+

|
|
19
18
|
|
|
20
19
|
## Installation
|
|
20
|
+
Install `sanity-plugin-markdown` and `easymde@2` (peer dependency).
|
|
21
21
|
|
|
22
22
|
```
|
|
23
|
-
npm install --save sanity-plugin-markdown
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
or
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
yarn add sanity-plugin-markdown
|
|
23
|
+
npm install --save sanity-plugin-markdown easymde@2
|
|
30
24
|
```
|
|
31
25
|
|
|
32
26
|
## Usage
|
|
@@ -59,10 +53,139 @@ const myDocument = {
|
|
|
59
53
|
]
|
|
60
54
|
}
|
|
61
55
|
```
|
|
62
|
-
###
|
|
56
|
+
### Next.js compatability
|
|
57
|
+
Next.js *without* Next 13 app directory does not support css imports from `node_modules`.
|
|
58
|
+
|
|
59
|
+
To use this plugin in this context (`pages` directory), use the `sanity-plugin-markdown/next` import instead of `sanity-plugin-markdown`:
|
|
60
|
+
```js
|
|
61
|
+
import { markdownSchema } from "sanity-plugin-markdown/next";
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Then, make sure to add
|
|
65
|
+
```js
|
|
66
|
+
import 'easymde/dist/easymde.min.css'
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
to the top of `pages/_app.tsx`.
|
|
70
|
+
|
|
71
|
+
### Customizing the default markdown input editor
|
|
72
|
+
|
|
73
|
+
The plugin takes an `input` config option that can be used in combination with the `MarkdownInput` export
|
|
74
|
+
to configure the underlying React SimpleMDE component:
|
|
75
|
+
|
|
76
|
+
* Create a custom component that wraps MarkdownInput
|
|
77
|
+
* Memoize reactMdeProps and pass along
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
// CustomMarkdownInput.tsx
|
|
81
|
+
import { MarkdownInput, MarkdownInputProps } from 'sanity-plugin-markdown'
|
|
82
|
+
|
|
83
|
+
export function CustomMarkdownInput(props) {
|
|
84
|
+
const reactMdeProps: MarkdownInputProps['reactMdeProps'] =
|
|
85
|
+
useMemo(() => {
|
|
86
|
+
return {
|
|
87
|
+
options: {
|
|
88
|
+
toolbar: ['bold', 'italic'],
|
|
89
|
+
// more options available, see:
|
|
90
|
+
// https://github.com/Ionaru/easy-markdown-editor#options-list
|
|
91
|
+
},
|
|
92
|
+
// more props available, see:
|
|
93
|
+
// https://github.com/RIP21/react-simplemde-editor#react-simplemde-easymde-markdown-editor
|
|
94
|
+
}
|
|
95
|
+
}, [])
|
|
96
|
+
|
|
97
|
+
return <MarkdownInput {...props} reactMdeProps={reactMdeProps} />
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
Set the plugin input option:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
// studio.config.ts
|
|
104
|
+
import {markdownSchema} from 'sanity-plugin-markdown'
|
|
105
|
+
import {CustomMarkdownInput} from './CustomMarkdownInput'
|
|
106
|
+
|
|
107
|
+
export default defineConfig({
|
|
108
|
+
// ... rest of the config
|
|
109
|
+
plugins: [
|
|
110
|
+
markdownSchema({input: CustomMarkdownInput}),
|
|
111
|
+
]
|
|
112
|
+
})
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Customize editor for a single field
|
|
116
|
+
|
|
117
|
+
Implement a custom input similar to the one above, and use it as `components.input` on the field directly.
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
defineField({
|
|
121
|
+
type: 'markdown',
|
|
122
|
+
name: 'markdown',
|
|
123
|
+
title: 'Markdown',
|
|
124
|
+
components: {input: CustomMarkdownInput}
|
|
125
|
+
})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Customizing editor preview
|
|
129
|
+
|
|
130
|
+
One way to customize the preview that does not involve ReactDOMServer
|
|
131
|
+
(used by React SimpleMDE) is to install [marked](https://github.com/markedjs/marked) and
|
|
132
|
+
[DOMPurify](https://github.com/cure53/DOMPurify) and create a custom preview:
|
|
133
|
+
|
|
134
|
+
`npm i marked dompurify`
|
|
135
|
+
|
|
136
|
+
Then use these to create a custom editor:
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
// MarkdownInputCustomPreview.tsx
|
|
140
|
+
import { MarkdownInput, MarkdownInputProps } from 'sanity-plugin-markdown'
|
|
141
|
+
import DOMPurify from 'dompurify'
|
|
142
|
+
import {marked} from 'marked'
|
|
143
|
+
|
|
144
|
+
export function CustomMarkdownInput(props) {
|
|
145
|
+
const reactMdeProps: MarkdownInputProps['reactMdeProps'] =
|
|
146
|
+
useMemo(() => {
|
|
147
|
+
return {
|
|
148
|
+
options: {
|
|
149
|
+
previewRender: (markdownText) => {
|
|
150
|
+
// configure as needed according to
|
|
151
|
+
// https://github.com/markedjs/marked#docs
|
|
152
|
+
return DOMPurify.sanitize(marked.parse(markdownText))
|
|
153
|
+
}
|
|
154
|
+
//customizing using renderingConfig is also an option
|
|
155
|
+
},
|
|
156
|
+
}
|
|
157
|
+
}, [])
|
|
158
|
+
|
|
159
|
+
return <MarkdownInput {...props} reactMdeProps={reactMdeProps} />
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Use the component as described in previous sections.
|
|
164
|
+
|
|
165
|
+
### Custom image urls
|
|
63
166
|
|
|
64
|
-
|
|
167
|
+
Provide a function to options.imageUrl that takes a SanityImageAssetDocument and returns a string.
|
|
65
168
|
|
|
169
|
+
The function will be invoked whenever an image is pasted or dragged into the markdown editor,
|
|
170
|
+
after upload completes.
|
|
171
|
+
|
|
172
|
+
The default implementation uses
|
|
173
|
+
```js
|
|
174
|
+
imageAsset => `${imageAsset.url}?w=450`
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
#### Example imageUrl option
|
|
178
|
+
|
|
179
|
+
```js
|
|
180
|
+
defineField({
|
|
181
|
+
type: 'markdown',
|
|
182
|
+
name: 'markdown',
|
|
183
|
+
title: 'Markdown',
|
|
184
|
+
options: {
|
|
185
|
+
imageUrl: imageAsset => `${imageAsset.url}?w=400&h=400`
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
```
|
|
66
189
|
|
|
67
190
|
## License
|
|
68
191
|
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _templateObject;
|
|
4
|
+
function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }
|
|
5
|
+
var sanity = require('sanity');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
var react = require('react');
|
|
8
|
+
var styled = require('styled-components');
|
|
9
|
+
var ui = require('@sanity/ui');
|
|
10
|
+
function _interopDefaultCompat(e) {
|
|
11
|
+
return e && typeof e === 'object' && 'default' in e ? e : {
|
|
12
|
+
default: e
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
var styled__default = /*#__PURE__*/_interopDefaultCompat(styled);
|
|
16
|
+
const MarkdownInputStyles = styled__default.default(ui.Box)(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n & .CodeMirror.CodeMirror {\n color: ", ";\n border-color: ", ";\n background-color: inherit;\n }\n\n & .cm-s-easymde .CodeMirror-cursor {\n border-color: ", ";\n }\n\n & .editor-toolbar,\n .editor-preview-side {\n border-color: ", ";\n }\n\n & .CodeMirror-focused .CodeMirror-selected.CodeMirror-selected.CodeMirror-selected {\n background-color: ", ";\n }\n\n & .CodeMirror-selected.CodeMirror-selected.CodeMirror-selected {\n background-color: ", ";\n }\n\n & .editor-toolbar > * {\n color: ", ";\n }\n\n & .editor-toolbar > .active,\n .editor-toolbar > button:hover,\n .editor-preview pre,\n .cm-s-easymde .cm-comment {\n background-color: ", ";\n }\n\n & .editor-preview {\n background-color: ", ";\n\n & h1,\n h2,\n h3,\n h4,\n h5,\n h6 {\n font-size: revert;\n }\n\n & ul,\n li {\n list-style: revert;\n padding: revert;\n }\n\n & a {\n text-decoration: revert;\n }\n }\n"])), _ref => {
|
|
17
|
+
let {
|
|
18
|
+
theme
|
|
19
|
+
} = _ref;
|
|
20
|
+
return theme.sanity.color.card.enabled.fg;
|
|
21
|
+
}, _ref2 => {
|
|
22
|
+
let {
|
|
23
|
+
theme
|
|
24
|
+
} = _ref2;
|
|
25
|
+
return theme.sanity.color.card.enabled.border;
|
|
26
|
+
}, _ref3 => {
|
|
27
|
+
let {
|
|
28
|
+
theme
|
|
29
|
+
} = _ref3;
|
|
30
|
+
return theme.sanity.color.card.enabled.fg;
|
|
31
|
+
}, _ref4 => {
|
|
32
|
+
let {
|
|
33
|
+
theme
|
|
34
|
+
} = _ref4;
|
|
35
|
+
return theme.sanity.color.card.enabled.border;
|
|
36
|
+
}, _ref5 => {
|
|
37
|
+
let {
|
|
38
|
+
theme
|
|
39
|
+
} = _ref5;
|
|
40
|
+
return theme.sanity.color.selectable.primary.hovered.bg;
|
|
41
|
+
}, _ref6 => {
|
|
42
|
+
let {
|
|
43
|
+
theme
|
|
44
|
+
} = _ref6;
|
|
45
|
+
return theme.sanity.color.card.enabled.bg;
|
|
46
|
+
}, _ref7 => {
|
|
47
|
+
let {
|
|
48
|
+
theme
|
|
49
|
+
} = _ref7;
|
|
50
|
+
return theme.sanity.color.card.enabled.fg;
|
|
51
|
+
}, _ref8 => {
|
|
52
|
+
let {
|
|
53
|
+
theme
|
|
54
|
+
} = _ref8;
|
|
55
|
+
return theme.sanity.color.card.enabled.bg;
|
|
56
|
+
}, _ref9 => {
|
|
57
|
+
let {
|
|
58
|
+
theme
|
|
59
|
+
} = _ref9;
|
|
60
|
+
return theme.sanity.color.card.enabled.bg;
|
|
61
|
+
});
|
|
62
|
+
const SimpleMdeReact = react.lazy(() => import('react-simplemde-editor'));
|
|
63
|
+
function useSimpleMdeReact() {
|
|
64
|
+
const [mounted, setMounted] = react.useState(false);
|
|
65
|
+
react.useEffect(() => {
|
|
66
|
+
requestAnimationFrame(() => setMounted(true));
|
|
67
|
+
}, []);
|
|
68
|
+
return mounted ? SimpleMdeReact : null;
|
|
69
|
+
}
|
|
70
|
+
const defaultMdeTools = ["heading", "bold", "italic", "|", "quote", "unordered-list", "ordered-list", "|", "link", "image", "code", "|", "preview", "side-by-side"];
|
|
71
|
+
function MarkdownInput(props) {
|
|
72
|
+
var _a;
|
|
73
|
+
const {
|
|
74
|
+
value = "",
|
|
75
|
+
onChange,
|
|
76
|
+
elementProps: {
|
|
77
|
+
onBlur,
|
|
78
|
+
onFocus,
|
|
79
|
+
ref
|
|
80
|
+
},
|
|
81
|
+
reactMdeProps: {
|
|
82
|
+
options: mdeCustomOptions,
|
|
83
|
+
...reactMdeProps
|
|
84
|
+
} = {},
|
|
85
|
+
schemaType
|
|
86
|
+
} = props;
|
|
87
|
+
const client = sanity.useClient({
|
|
88
|
+
apiVersion: "2022-01-01"
|
|
89
|
+
});
|
|
90
|
+
const {
|
|
91
|
+
imageUrl
|
|
92
|
+
} = (_a = schemaType.options) != null ? _a : {};
|
|
93
|
+
const imageUpload = react.useCallback((file, onSuccess, onError) => {
|
|
94
|
+
client.assets.upload("image", file).then(doc => onSuccess(imageUrl ? imageUrl(doc) : "".concat(doc.url, "?w=450"))).catch(e => {
|
|
95
|
+
console.error(e);
|
|
96
|
+
onError(e.message);
|
|
97
|
+
});
|
|
98
|
+
}, [client, imageUrl]);
|
|
99
|
+
const mdeOptions = react.useMemo(() => {
|
|
100
|
+
return {
|
|
101
|
+
autofocus: false,
|
|
102
|
+
spellChecker: false,
|
|
103
|
+
sideBySideFullscreen: false,
|
|
104
|
+
uploadImage: true,
|
|
105
|
+
imageUploadFunction: imageUpload,
|
|
106
|
+
toolbar: defaultMdeTools,
|
|
107
|
+
status: false,
|
|
108
|
+
...mdeCustomOptions
|
|
109
|
+
};
|
|
110
|
+
}, [imageUpload, mdeCustomOptions]);
|
|
111
|
+
const handleChange = react.useCallback(newValue => {
|
|
112
|
+
onChange(sanity.PatchEvent.from(newValue ? sanity.set(newValue) : sanity.unset()));
|
|
113
|
+
}, [onChange]);
|
|
114
|
+
const SimpleMdeReact = useSimpleMdeReact();
|
|
115
|
+
return /* @__PURE__ */jsxRuntime.jsx(MarkdownInputStyles, {
|
|
116
|
+
children: SimpleMdeReact && /* @__PURE__ */jsxRuntime.jsx(react.Suspense, {
|
|
117
|
+
fallback: /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
|
|
118
|
+
padding: 3,
|
|
119
|
+
children: /* @__PURE__ */jsxRuntime.jsx(ui.Text, {
|
|
120
|
+
children: "Loading editor..."
|
|
121
|
+
})
|
|
122
|
+
}),
|
|
123
|
+
children: /* @__PURE__ */jsxRuntime.jsx(SimpleMdeReact, {
|
|
124
|
+
...reactMdeProps,
|
|
125
|
+
ref,
|
|
126
|
+
value,
|
|
127
|
+
onChange: handleChange,
|
|
128
|
+
onBlur,
|
|
129
|
+
onFocus,
|
|
130
|
+
options: mdeOptions,
|
|
131
|
+
spellCheck: false
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
const markdownTypeName = "markdown";
|
|
137
|
+
const markdownSchemaType = sanity.defineType({
|
|
138
|
+
type: "string",
|
|
139
|
+
name: markdownTypeName,
|
|
140
|
+
title: "Markdown",
|
|
141
|
+
components: {
|
|
142
|
+
input: MarkdownInput
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
const markdownSchema = sanity.definePlugin(config => {
|
|
146
|
+
return {
|
|
147
|
+
name: "markdown-editor",
|
|
148
|
+
schema: {
|
|
149
|
+
types: [config && config.input ? {
|
|
150
|
+
...markdownSchemaType,
|
|
151
|
+
components: {
|
|
152
|
+
input: config.input
|
|
153
|
+
}
|
|
154
|
+
} : markdownSchemaType]
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
});
|
|
158
|
+
exports.MarkdownInput = MarkdownInput;
|
|
159
|
+
exports.defaultMdeTools = defaultMdeTools;
|
|
160
|
+
exports.markdownSchema = markdownSchema;
|
|
161
|
+
exports.markdownSchemaType = markdownSchemaType;
|
|
162
|
+
//# sourceMappingURL=plugin-b7a179e6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-b7a179e6.js","sources":["../../src/components/MarkdownInputStyles.tsx","../../src/components/useSimpleMdeReact.tsx","../../src/components/MarkdownInput.tsx","../../src/schema.ts","../../src/plugin.tsx"],"sourcesContent":["import styled from 'styled-components'\nimport {Box} from '@sanity/ui'\n\nexport const MarkdownInputStyles = styled(Box)`\n & .CodeMirror.CodeMirror {\n color: ${({theme}) => theme.sanity.color.card.enabled.fg};\n border-color: ${({theme}) => theme.sanity.color.card.enabled.border};\n background-color: inherit;\n }\n\n & .cm-s-easymde .CodeMirror-cursor {\n border-color: ${({theme}) => theme.sanity.color.card.enabled.fg};\n }\n\n & .editor-toolbar,\n .editor-preview-side {\n border-color: ${({theme}) => theme.sanity.color.card.enabled.border};\n }\n\n & .CodeMirror-focused .CodeMirror-selected.CodeMirror-selected.CodeMirror-selected {\n background-color: ${({theme}) => theme.sanity.color.selectable.primary.hovered.bg};\n }\n\n & .CodeMirror-selected.CodeMirror-selected.CodeMirror-selected {\n background-color: ${({theme}) => theme.sanity.color.card.enabled.bg};\n }\n\n & .editor-toolbar > * {\n color: ${({theme}) => theme.sanity.color.card.enabled.fg};\n }\n\n & .editor-toolbar > .active,\n .editor-toolbar > button:hover,\n .editor-preview pre,\n .cm-s-easymde .cm-comment {\n background-color: ${({theme}) => theme.sanity.color.card.enabled.bg};\n }\n\n & .editor-preview {\n background-color: ${({theme}) => theme.sanity.color.card.enabled.bg};\n\n & h1,\n h2,\n h3,\n h4,\n h5,\n h6 {\n font-size: revert;\n }\n\n & ul,\n li {\n list-style: revert;\n padding: revert;\n }\n\n & a {\n text-decoration: revert;\n }\n }\n`\n","import {lazy, useEffect, useState} from 'react'\n\nexport const SimpleMdeReact = lazy(() => import('react-simplemde-editor'))\n\nexport function useSimpleMdeReact() {\n const [mounted, setMounted] = useState(false)\n useEffect(() => {\n requestAnimationFrame(() => setMounted(true))\n }, [])\n\n return mounted ? SimpleMdeReact : null\n}\n","import {type Options as EasyMdeOptions} from 'easymde'\nimport React, {Suspense, useCallback, useMemo} from 'react'\n// dont import non-types here, it will break SSR on next\nimport type {SimpleMDEReactProps} from 'react-simplemde-editor'\nimport {PatchEvent, set, StringInputProps, unset, useClient} from 'sanity'\nimport {MarkdownOptions} from '../schema'\nimport {MarkdownInputStyles} from './MarkdownInputStyles'\nimport {useSimpleMdeReact} from './useSimpleMdeReact'\nimport {Box, Text} from '@sanity/ui'\n\nexport interface MarkdownInputProps extends StringInputProps {\n /**\n * These are passed along directly to\n *\n * Note: MarkdownInput sets certain reactMdeProps.options by default.\n * These will be merged with any custom options.\n * */\n reactMdeProps?: Omit<SimpleMDEReactProps, 'value' | 'onChange'>\n}\n\nexport const defaultMdeTools: EasyMdeOptions['toolbar'] = [\n 'heading',\n 'bold',\n 'italic',\n '|',\n 'quote',\n 'unordered-list',\n 'ordered-list',\n '|',\n 'link',\n 'image',\n 'code',\n '|',\n 'preview',\n 'side-by-side',\n]\n\nexport function MarkdownInput(props: MarkdownInputProps) {\n const {\n value = '',\n onChange,\n elementProps: {onBlur, onFocus, ref},\n reactMdeProps: {options: mdeCustomOptions, ...reactMdeProps} = {},\n schemaType,\n } = props\n const client = useClient({apiVersion: '2022-01-01'})\n const {imageUrl} = (schemaType.options as MarkdownOptions | undefined) ?? {}\n\n const imageUpload = useCallback(\n (file: File, onSuccess: (url: string) => void, onError: (error: string) => void) => {\n client.assets\n .upload('image', file)\n .then((doc) => onSuccess(imageUrl ? imageUrl(doc) : `${doc.url}?w=450`))\n .catch((e) => {\n console.error(e)\n onError(e.message)\n })\n },\n [client, imageUrl]\n )\n\n const mdeOptions: EasyMdeOptions = useMemo(() => {\n return {\n autofocus: false,\n spellChecker: false,\n sideBySideFullscreen: false,\n uploadImage: true,\n imageUploadFunction: imageUpload,\n toolbar: defaultMdeTools,\n status: false,\n ...mdeCustomOptions,\n }\n }, [imageUpload, mdeCustomOptions])\n\n const handleChange = useCallback(\n (newValue: string) => {\n onChange(PatchEvent.from(newValue ? set(newValue) : unset()))\n },\n [onChange]\n )\n\n const SimpleMdeReact = useSimpleMdeReact()\n\n return (\n <MarkdownInputStyles>\n {SimpleMdeReact && (\n <Suspense\n fallback={\n <Box padding={3}>\n <Text>Loading editor...</Text>\n </Box>\n }\n >\n <SimpleMdeReact\n {...reactMdeProps}\n ref={ref}\n value={value}\n onChange={handleChange}\n onBlur={onBlur}\n onFocus={onFocus}\n options={mdeOptions}\n spellCheck={false}\n />\n </Suspense>\n )}\n </MarkdownInputStyles>\n )\n}\n","import {defineType, StringDefinition} from 'sanity'\nimport {MarkdownInput} from './components/MarkdownInput'\nimport {SanityImageAssetDocument} from '@sanity/client'\n\nexport const markdownTypeName = 'markdown' as const\n\nexport interface MarkdownOptions {\n /**\n * Used to create image url for any uploaded image.\n * The function will be invoked whenever an image is pasted or dragged into the\n * markdown editor, after upload completes.\n *\n * The default implementation uses\n * ```js\n * imageAsset => `${imageAsset.url}?w=450`\n * ```\n * ## Example\n * ```js\n * {\n * imageUrl: imageAsset => `${imageAsset.url}?w=400&h=400`\n * }\n * ```\n * @param imageAsset\n */\n imageUrl?: (imageAsset: SanityImageAssetDocument) => string\n}\n\n/**\n * @public\n */\nexport interface MarkdownDefinition extends Omit<StringDefinition, 'type' | 'fields' | 'options'> {\n type: typeof markdownTypeName\n options?: MarkdownOptions\n}\n\ndeclare module '@sanity/types' {\n // makes type: 'markdown' narrow correctly when using defineType/defineField/defineArrayMember\n export interface IntrinsicDefinitions {\n markdown: MarkdownDefinition\n }\n}\n\nexport const markdownSchemaType = defineType({\n type: 'string',\n name: markdownTypeName,\n title: 'Markdown',\n components: {input: MarkdownInput},\n})\n","import {definePlugin, StringInputProps} from 'sanity'\nimport {markdownSchemaType} from './schema'\nimport {ReactElement} from 'react'\n\nexport interface MarkdownConfig {\n /**\n * When provided, will replace the default input component.\n *\n * Use this to customize MarkdownInput by wrapping it in a custom component,\n * and provide any custom props for https://github.com/RIP21/react-simplemde-editor#react-simplemde-easymde-markdown-editor\n * via the `reactMdeProps` prop.\n *\n * ### Example\n *\n * ```tsx\n * // CustomMarkdownInput.tsx\n * import { MarkdownInput, MarkdownInputProps } from 'sanity-plugin-markdown'\n *\n * export function CustomMarkdownInput(props) {\n * const reactMdeProps: MarkdownInputProps['reactMdeProps'] =\n * useMemo(() => {\n * return {\n * options: {\n * toolbar: ['bold', 'italic'],\n * // more options available, see:\n * // https://github.com/Ionaru/easy-markdown-editor#options-list\n * },\n * // more props available, see:\n * // https://github.com/RIP21/react-simplemde-editor#react-simplemde-easymde-markdown-editor\n * }\n * }, [])\n *\n * return <MarkdownInput {...props} reactMdeProps={reactMdeProps} />\n * }\n *\n * // studio.config.ts\n * markdownSchema({input: CustomMarkdownInput})\n * ```\n */\n input?: (props: StringInputProps) => ReactElement\n}\n\nexport const markdownSchema = definePlugin((config: MarkdownConfig | void) => {\n return {\n name: 'markdown-editor',\n schema: {\n types: [\n config && config.input\n ? {...markdownSchemaType, components: {input: config.input}}\n : markdownSchemaType,\n ],\n },\n }\n})\n"],"names":["MarkdownInputStyles","styled","Box","_templateObject","_taggedTemplateLiteral","_ref","theme","sanity","color","card","enabled","fg","_ref2","border","_ref3","_ref4","_ref5","selectable","primary","hovered","bg","_ref6","_ref7","_ref8","_ref9","SimpleMdeReact","lazy","useSimpleMdeReact","mounted","setMounted","useState","useEffect","requestAnimationFrame","defaultMdeTools","MarkdownInput","props","_a","value","onChange","elementProps","onBlur","onFocus","ref","reactMdeProps","options","mdeCustomOptions","schemaType","client","useClient","apiVersion","imageUrl","imageUpload","useCallback","file","onSuccess","onError","assets","upload","then","doc","concat","url","catch","e","console","error","message","mdeOptions","useMemo","autofocus","spellChecker","sideBySideFullscreen","uploadImage","imageUploadFunction","toolbar","status","handleChange","newValue","PatchEvent","from","set","unset","jsx","children","Suspense","fallback","padding","Text","spellCheck","markdownTypeName","markdownSchemaType","defineType","type","name","title","components","input","markdownSchema","definePlugin","config","schema","types"],"mappings":"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"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
var _templateObject;
|
|
2
|
+
function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }
|
|
3
|
+
import { useClient, PatchEvent, set, unset, defineType, definePlugin } from 'sanity';
|
|
4
|
+
import { jsx } from 'react/jsx-runtime';
|
|
5
|
+
import { lazy, useState, useEffect, useCallback, useMemo, Suspense } from 'react';
|
|
6
|
+
import styled from 'styled-components';
|
|
7
|
+
import { Box, Text } from '@sanity/ui';
|
|
8
|
+
const MarkdownInputStyles = styled(Box)(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n & .CodeMirror.CodeMirror {\n color: ", ";\n border-color: ", ";\n background-color: inherit;\n }\n\n & .cm-s-easymde .CodeMirror-cursor {\n border-color: ", ";\n }\n\n & .editor-toolbar,\n .editor-preview-side {\n border-color: ", ";\n }\n\n & .CodeMirror-focused .CodeMirror-selected.CodeMirror-selected.CodeMirror-selected {\n background-color: ", ";\n }\n\n & .CodeMirror-selected.CodeMirror-selected.CodeMirror-selected {\n background-color: ", ";\n }\n\n & .editor-toolbar > * {\n color: ", ";\n }\n\n & .editor-toolbar > .active,\n .editor-toolbar > button:hover,\n .editor-preview pre,\n .cm-s-easymde .cm-comment {\n background-color: ", ";\n }\n\n & .editor-preview {\n background-color: ", ";\n\n & h1,\n h2,\n h3,\n h4,\n h5,\n h6 {\n font-size: revert;\n }\n\n & ul,\n li {\n list-style: revert;\n padding: revert;\n }\n\n & a {\n text-decoration: revert;\n }\n }\n"])), _ref => {
|
|
9
|
+
let {
|
|
10
|
+
theme
|
|
11
|
+
} = _ref;
|
|
12
|
+
return theme.sanity.color.card.enabled.fg;
|
|
13
|
+
}, _ref2 => {
|
|
14
|
+
let {
|
|
15
|
+
theme
|
|
16
|
+
} = _ref2;
|
|
17
|
+
return theme.sanity.color.card.enabled.border;
|
|
18
|
+
}, _ref3 => {
|
|
19
|
+
let {
|
|
20
|
+
theme
|
|
21
|
+
} = _ref3;
|
|
22
|
+
return theme.sanity.color.card.enabled.fg;
|
|
23
|
+
}, _ref4 => {
|
|
24
|
+
let {
|
|
25
|
+
theme
|
|
26
|
+
} = _ref4;
|
|
27
|
+
return theme.sanity.color.card.enabled.border;
|
|
28
|
+
}, _ref5 => {
|
|
29
|
+
let {
|
|
30
|
+
theme
|
|
31
|
+
} = _ref5;
|
|
32
|
+
return theme.sanity.color.selectable.primary.hovered.bg;
|
|
33
|
+
}, _ref6 => {
|
|
34
|
+
let {
|
|
35
|
+
theme
|
|
36
|
+
} = _ref6;
|
|
37
|
+
return theme.sanity.color.card.enabled.bg;
|
|
38
|
+
}, _ref7 => {
|
|
39
|
+
let {
|
|
40
|
+
theme
|
|
41
|
+
} = _ref7;
|
|
42
|
+
return theme.sanity.color.card.enabled.fg;
|
|
43
|
+
}, _ref8 => {
|
|
44
|
+
let {
|
|
45
|
+
theme
|
|
46
|
+
} = _ref8;
|
|
47
|
+
return theme.sanity.color.card.enabled.bg;
|
|
48
|
+
}, _ref9 => {
|
|
49
|
+
let {
|
|
50
|
+
theme
|
|
51
|
+
} = _ref9;
|
|
52
|
+
return theme.sanity.color.card.enabled.bg;
|
|
53
|
+
});
|
|
54
|
+
const SimpleMdeReact = lazy(() => import('react-simplemde-editor'));
|
|
55
|
+
function useSimpleMdeReact() {
|
|
56
|
+
const [mounted, setMounted] = useState(false);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
requestAnimationFrame(() => setMounted(true));
|
|
59
|
+
}, []);
|
|
60
|
+
return mounted ? SimpleMdeReact : null;
|
|
61
|
+
}
|
|
62
|
+
const defaultMdeTools = ["heading", "bold", "italic", "|", "quote", "unordered-list", "ordered-list", "|", "link", "image", "code", "|", "preview", "side-by-side"];
|
|
63
|
+
function MarkdownInput(props) {
|
|
64
|
+
var _a;
|
|
65
|
+
const {
|
|
66
|
+
value = "",
|
|
67
|
+
onChange,
|
|
68
|
+
elementProps: {
|
|
69
|
+
onBlur,
|
|
70
|
+
onFocus,
|
|
71
|
+
ref
|
|
72
|
+
},
|
|
73
|
+
reactMdeProps: {
|
|
74
|
+
options: mdeCustomOptions,
|
|
75
|
+
...reactMdeProps
|
|
76
|
+
} = {},
|
|
77
|
+
schemaType
|
|
78
|
+
} = props;
|
|
79
|
+
const client = useClient({
|
|
80
|
+
apiVersion: "2022-01-01"
|
|
81
|
+
});
|
|
82
|
+
const {
|
|
83
|
+
imageUrl
|
|
84
|
+
} = (_a = schemaType.options) != null ? _a : {};
|
|
85
|
+
const imageUpload = useCallback((file, onSuccess, onError) => {
|
|
86
|
+
client.assets.upload("image", file).then(doc => onSuccess(imageUrl ? imageUrl(doc) : "".concat(doc.url, "?w=450"))).catch(e => {
|
|
87
|
+
console.error(e);
|
|
88
|
+
onError(e.message);
|
|
89
|
+
});
|
|
90
|
+
}, [client, imageUrl]);
|
|
91
|
+
const mdeOptions = useMemo(() => {
|
|
92
|
+
return {
|
|
93
|
+
autofocus: false,
|
|
94
|
+
spellChecker: false,
|
|
95
|
+
sideBySideFullscreen: false,
|
|
96
|
+
uploadImage: true,
|
|
97
|
+
imageUploadFunction: imageUpload,
|
|
98
|
+
toolbar: defaultMdeTools,
|
|
99
|
+
status: false,
|
|
100
|
+
...mdeCustomOptions
|
|
101
|
+
};
|
|
102
|
+
}, [imageUpload, mdeCustomOptions]);
|
|
103
|
+
const handleChange = useCallback(newValue => {
|
|
104
|
+
onChange(PatchEvent.from(newValue ? set(newValue) : unset()));
|
|
105
|
+
}, [onChange]);
|
|
106
|
+
const SimpleMdeReact = useSimpleMdeReact();
|
|
107
|
+
return /* @__PURE__ */jsx(MarkdownInputStyles, {
|
|
108
|
+
children: SimpleMdeReact && /* @__PURE__ */jsx(Suspense, {
|
|
109
|
+
fallback: /* @__PURE__ */jsx(Box, {
|
|
110
|
+
padding: 3,
|
|
111
|
+
children: /* @__PURE__ */jsx(Text, {
|
|
112
|
+
children: "Loading editor..."
|
|
113
|
+
})
|
|
114
|
+
}),
|
|
115
|
+
children: /* @__PURE__ */jsx(SimpleMdeReact, {
|
|
116
|
+
...reactMdeProps,
|
|
117
|
+
ref,
|
|
118
|
+
value,
|
|
119
|
+
onChange: handleChange,
|
|
120
|
+
onBlur,
|
|
121
|
+
onFocus,
|
|
122
|
+
options: mdeOptions,
|
|
123
|
+
spellCheck: false
|
|
124
|
+
})
|
|
125
|
+
})
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
const markdownTypeName = "markdown";
|
|
129
|
+
const markdownSchemaType = defineType({
|
|
130
|
+
type: "string",
|
|
131
|
+
name: markdownTypeName,
|
|
132
|
+
title: "Markdown",
|
|
133
|
+
components: {
|
|
134
|
+
input: MarkdownInput
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
const markdownSchema = definePlugin(config => {
|
|
138
|
+
return {
|
|
139
|
+
name: "markdown-editor",
|
|
140
|
+
schema: {
|
|
141
|
+
types: [config && config.input ? {
|
|
142
|
+
...markdownSchemaType,
|
|
143
|
+
components: {
|
|
144
|
+
input: config.input
|
|
145
|
+
}
|
|
146
|
+
} : markdownSchemaType]
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
});
|
|
150
|
+
export { MarkdownInput, defaultMdeTools, markdownSchema, markdownSchemaType };
|
|
151
|
+
//# sourceMappingURL=plugin-ca10aa4c.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-ca10aa4c.js","sources":["../../src/components/MarkdownInputStyles.tsx","../../src/components/useSimpleMdeReact.tsx","../../src/components/MarkdownInput.tsx","../../src/schema.ts","../../src/plugin.tsx"],"sourcesContent":["import styled from 'styled-components'\nimport {Box} from '@sanity/ui'\n\nexport const MarkdownInputStyles = styled(Box)`\n & .CodeMirror.CodeMirror {\n color: ${({theme}) => theme.sanity.color.card.enabled.fg};\n border-color: ${({theme}) => theme.sanity.color.card.enabled.border};\n background-color: inherit;\n }\n\n & .cm-s-easymde .CodeMirror-cursor {\n border-color: ${({theme}) => theme.sanity.color.card.enabled.fg};\n }\n\n & .editor-toolbar,\n .editor-preview-side {\n border-color: ${({theme}) => theme.sanity.color.card.enabled.border};\n }\n\n & .CodeMirror-focused .CodeMirror-selected.CodeMirror-selected.CodeMirror-selected {\n background-color: ${({theme}) => theme.sanity.color.selectable.primary.hovered.bg};\n }\n\n & .CodeMirror-selected.CodeMirror-selected.CodeMirror-selected {\n background-color: ${({theme}) => theme.sanity.color.card.enabled.bg};\n }\n\n & .editor-toolbar > * {\n color: ${({theme}) => theme.sanity.color.card.enabled.fg};\n }\n\n & .editor-toolbar > .active,\n .editor-toolbar > button:hover,\n .editor-preview pre,\n .cm-s-easymde .cm-comment {\n background-color: ${({theme}) => theme.sanity.color.card.enabled.bg};\n }\n\n & .editor-preview {\n background-color: ${({theme}) => theme.sanity.color.card.enabled.bg};\n\n & h1,\n h2,\n h3,\n h4,\n h5,\n h6 {\n font-size: revert;\n }\n\n & ul,\n li {\n list-style: revert;\n padding: revert;\n }\n\n & a {\n text-decoration: revert;\n }\n }\n`\n","import {lazy, useEffect, useState} from 'react'\n\nexport const SimpleMdeReact = lazy(() => import('react-simplemde-editor'))\n\nexport function useSimpleMdeReact() {\n const [mounted, setMounted] = useState(false)\n useEffect(() => {\n requestAnimationFrame(() => setMounted(true))\n }, [])\n\n return mounted ? SimpleMdeReact : null\n}\n","import {type Options as EasyMdeOptions} from 'easymde'\nimport React, {Suspense, useCallback, useMemo} from 'react'\n// dont import non-types here, it will break SSR on next\nimport type {SimpleMDEReactProps} from 'react-simplemde-editor'\nimport {PatchEvent, set, StringInputProps, unset, useClient} from 'sanity'\nimport {MarkdownOptions} from '../schema'\nimport {MarkdownInputStyles} from './MarkdownInputStyles'\nimport {useSimpleMdeReact} from './useSimpleMdeReact'\nimport {Box, Text} from '@sanity/ui'\n\nexport interface MarkdownInputProps extends StringInputProps {\n /**\n * These are passed along directly to\n *\n * Note: MarkdownInput sets certain reactMdeProps.options by default.\n * These will be merged with any custom options.\n * */\n reactMdeProps?: Omit<SimpleMDEReactProps, 'value' | 'onChange'>\n}\n\nexport const defaultMdeTools: EasyMdeOptions['toolbar'] = [\n 'heading',\n 'bold',\n 'italic',\n '|',\n 'quote',\n 'unordered-list',\n 'ordered-list',\n '|',\n 'link',\n 'image',\n 'code',\n '|',\n 'preview',\n 'side-by-side',\n]\n\nexport function MarkdownInput(props: MarkdownInputProps) {\n const {\n value = '',\n onChange,\n elementProps: {onBlur, onFocus, ref},\n reactMdeProps: {options: mdeCustomOptions, ...reactMdeProps} = {},\n schemaType,\n } = props\n const client = useClient({apiVersion: '2022-01-01'})\n const {imageUrl} = (schemaType.options as MarkdownOptions | undefined) ?? {}\n\n const imageUpload = useCallback(\n (file: File, onSuccess: (url: string) => void, onError: (error: string) => void) => {\n client.assets\n .upload('image', file)\n .then((doc) => onSuccess(imageUrl ? imageUrl(doc) : `${doc.url}?w=450`))\n .catch((e) => {\n console.error(e)\n onError(e.message)\n })\n },\n [client, imageUrl]\n )\n\n const mdeOptions: EasyMdeOptions = useMemo(() => {\n return {\n autofocus: false,\n spellChecker: false,\n sideBySideFullscreen: false,\n uploadImage: true,\n imageUploadFunction: imageUpload,\n toolbar: defaultMdeTools,\n status: false,\n ...mdeCustomOptions,\n }\n }, [imageUpload, mdeCustomOptions])\n\n const handleChange = useCallback(\n (newValue: string) => {\n onChange(PatchEvent.from(newValue ? set(newValue) : unset()))\n },\n [onChange]\n )\n\n const SimpleMdeReact = useSimpleMdeReact()\n\n return (\n <MarkdownInputStyles>\n {SimpleMdeReact && (\n <Suspense\n fallback={\n <Box padding={3}>\n <Text>Loading editor...</Text>\n </Box>\n }\n >\n <SimpleMdeReact\n {...reactMdeProps}\n ref={ref}\n value={value}\n onChange={handleChange}\n onBlur={onBlur}\n onFocus={onFocus}\n options={mdeOptions}\n spellCheck={false}\n />\n </Suspense>\n )}\n </MarkdownInputStyles>\n )\n}\n","import {defineType, StringDefinition} from 'sanity'\nimport {MarkdownInput} from './components/MarkdownInput'\nimport {SanityImageAssetDocument} from '@sanity/client'\n\nexport const markdownTypeName = 'markdown' as const\n\nexport interface MarkdownOptions {\n /**\n * Used to create image url for any uploaded image.\n * The function will be invoked whenever an image is pasted or dragged into the\n * markdown editor, after upload completes.\n *\n * The default implementation uses\n * ```js\n * imageAsset => `${imageAsset.url}?w=450`\n * ```\n * ## Example\n * ```js\n * {\n * imageUrl: imageAsset => `${imageAsset.url}?w=400&h=400`\n * }\n * ```\n * @param imageAsset\n */\n imageUrl?: (imageAsset: SanityImageAssetDocument) => string\n}\n\n/**\n * @public\n */\nexport interface MarkdownDefinition extends Omit<StringDefinition, 'type' | 'fields' | 'options'> {\n type: typeof markdownTypeName\n options?: MarkdownOptions\n}\n\ndeclare module '@sanity/types' {\n // makes type: 'markdown' narrow correctly when using defineType/defineField/defineArrayMember\n export interface IntrinsicDefinitions {\n markdown: MarkdownDefinition\n }\n}\n\nexport const markdownSchemaType = defineType({\n type: 'string',\n name: markdownTypeName,\n title: 'Markdown',\n components: {input: MarkdownInput},\n})\n","import {definePlugin, StringInputProps} from 'sanity'\nimport {markdownSchemaType} from './schema'\nimport {ReactElement} from 'react'\n\nexport interface MarkdownConfig {\n /**\n * When provided, will replace the default input component.\n *\n * Use this to customize MarkdownInput by wrapping it in a custom component,\n * and provide any custom props for https://github.com/RIP21/react-simplemde-editor#react-simplemde-easymde-markdown-editor\n * via the `reactMdeProps` prop.\n *\n * ### Example\n *\n * ```tsx\n * // CustomMarkdownInput.tsx\n * import { MarkdownInput, MarkdownInputProps } from 'sanity-plugin-markdown'\n *\n * export function CustomMarkdownInput(props) {\n * const reactMdeProps: MarkdownInputProps['reactMdeProps'] =\n * useMemo(() => {\n * return {\n * options: {\n * toolbar: ['bold', 'italic'],\n * // more options available, see:\n * // https://github.com/Ionaru/easy-markdown-editor#options-list\n * },\n * // more props available, see:\n * // https://github.com/RIP21/react-simplemde-editor#react-simplemde-easymde-markdown-editor\n * }\n * }, [])\n *\n * return <MarkdownInput {...props} reactMdeProps={reactMdeProps} />\n * }\n *\n * // studio.config.ts\n * markdownSchema({input: CustomMarkdownInput})\n * ```\n */\n input?: (props: StringInputProps) => ReactElement\n}\n\nexport const markdownSchema = definePlugin((config: MarkdownConfig | void) => {\n return {\n name: 'markdown-editor',\n schema: {\n types: [\n config && config.input\n ? {...markdownSchemaType, components: {input: config.input}}\n : markdownSchemaType,\n ],\n },\n }\n})\n"],"names":["MarkdownInputStyles","styled","Box","_templateObject","_taggedTemplateLiteral","_ref","theme","sanity","color","card","enabled","fg","_ref2","border","_ref3","_ref4","_ref5","selectable","primary","hovered","bg","_ref6","_ref7","_ref8","_ref9","SimpleMdeReact","lazy","useSimpleMdeReact","mounted","setMounted","useState","useEffect","requestAnimationFrame","defaultMdeTools","MarkdownInput","props","_a","value","onChange","elementProps","onBlur","onFocus","ref","reactMdeProps","options","mdeCustomOptions","schemaType","client","useClient","apiVersion","imageUrl","imageUpload","useCallback","file","onSuccess","onError","assets","upload","then","doc","concat","url","catch","e","console","error","message","mdeOptions","useMemo","autofocus","spellChecker","sideBySideFullscreen","uploadImage","imageUploadFunction","toolbar","status","handleChange","newValue","PatchEvent","from","set","unset","jsx","children","Suspense","fallback","padding","Text","spellCheck","markdownTypeName","markdownSchemaType","defineType","type","name","title","components","input","markdownSchema","definePlugin","config","schema","types"],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
|
|
3
|
+
import {Options} from 'easymde'
|
|
4
|
+
import {Plugin as Plugin_2} from 'sanity'
|
|
5
|
+
import {ReactElement} from 'react'
|
|
6
|
+
import {SanityImageAssetDocument} from '@sanity/client'
|
|
7
|
+
import type {SimpleMDEReactProps} from 'react-simplemde-editor'
|
|
8
|
+
import {StringDefinition} from 'sanity'
|
|
9
|
+
import {StringInputProps} from 'sanity'
|
|
10
|
+
|
|
11
|
+
export declare const defaultMdeTools: Options['toolbar']
|
|
12
|
+
|
|
13
|
+
export declare interface MarkdownConfig {
|
|
14
|
+
/**
|
|
15
|
+
* When provided, will replace the default input component.
|
|
16
|
+
*
|
|
17
|
+
* Use this to customize MarkdownInput by wrapping it in a custom component,
|
|
18
|
+
* and provide any custom props for https://github.com/RIP21/react-simplemde-editor#react-simplemde-easymde-markdown-editor
|
|
19
|
+
* via the `reactMdeProps` prop.
|
|
20
|
+
*
|
|
21
|
+
* ### Example
|
|
22
|
+
*
|
|
23
|
+
* ```tsx
|
|
24
|
+
* // CustomMarkdownInput.tsx
|
|
25
|
+
* import { MarkdownInput, MarkdownInputProps } from 'sanity-plugin-markdown'
|
|
26
|
+
*
|
|
27
|
+
* export function CustomMarkdownInput(props) {
|
|
28
|
+
* const reactMdeProps: MarkdownInputProps['reactMdeProps'] =
|
|
29
|
+
* useMemo(() => {
|
|
30
|
+
* return {
|
|
31
|
+
* options: {
|
|
32
|
+
* toolbar: ['bold', 'italic'],
|
|
33
|
+
* // more options available, see:
|
|
34
|
+
* // https://github.com/Ionaru/easy-markdown-editor#options-list
|
|
35
|
+
* },
|
|
36
|
+
* // more props available, see:
|
|
37
|
+
* // https://github.com/RIP21/react-simplemde-editor#react-simplemde-easymde-markdown-editor
|
|
38
|
+
* }
|
|
39
|
+
* }, [])
|
|
40
|
+
*
|
|
41
|
+
* return <MarkdownInput {...props} reactMdeProps={reactMdeProps} />
|
|
42
|
+
* }
|
|
43
|
+
*
|
|
44
|
+
* // studio.config.ts
|
|
45
|
+
* markdownSchema({input: CustomMarkdownInput})
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
input?: (props: StringInputProps) => ReactElement
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @public
|
|
53
|
+
*/
|
|
54
|
+
export declare interface MarkdownDefinition
|
|
55
|
+
extends Omit<StringDefinition, 'type' | 'fields' | 'options'> {
|
|
56
|
+
type: typeof markdownTypeName
|
|
57
|
+
options?: MarkdownOptions
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export declare function MarkdownInput(props: MarkdownInputProps): JSX.Element
|
|
61
|
+
|
|
62
|
+
export declare interface MarkdownInputProps extends StringInputProps {
|
|
63
|
+
/**
|
|
64
|
+
* These are passed along directly to
|
|
65
|
+
*
|
|
66
|
+
* Note: MarkdownInput sets certain reactMdeProps.options by default.
|
|
67
|
+
* These will be merged with any custom options.
|
|
68
|
+
* */
|
|
69
|
+
reactMdeProps?: Omit<SimpleMDEReactProps, 'value' | 'onChange'>
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
declare interface MarkdownOptions {
|
|
73
|
+
/**
|
|
74
|
+
* Used to create image url for any uploaded image.
|
|
75
|
+
* The function will be invoked whenever an image is pasted or dragged into the
|
|
76
|
+
* markdown editor, after upload completes.
|
|
77
|
+
*
|
|
78
|
+
* The default implementation uses
|
|
79
|
+
* ```js
|
|
80
|
+
* imageAsset => `${imageAsset.url}?w=450`
|
|
81
|
+
* ```
|
|
82
|
+
* ## Example
|
|
83
|
+
* ```js
|
|
84
|
+
* {
|
|
85
|
+
* imageUrl: imageAsset => `${imageAsset.url}?w=400&h=400`
|
|
86
|
+
* }
|
|
87
|
+
* ```
|
|
88
|
+
* @param imageAsset
|
|
89
|
+
*/
|
|
90
|
+
imageUrl?: (imageAsset: SanityImageAssetDocument) => string
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export declare const markdownSchema: Plugin_2<void | MarkdownConfig>
|
|
94
|
+
|
|
95
|
+
export declare const markdownSchemaType: {
|
|
96
|
+
type: 'string'
|
|
97
|
+
name: 'markdown'
|
|
98
|
+
} & Omit<StringDefinition, 'preview'>
|
|
99
|
+
|
|
100
|
+
declare const markdownTypeName: 'markdown'
|
|
101
|
+
|
|
102
|
+
export {}
|
|
103
|
+
|
|
104
|
+
declare module '@sanity/types' {
|
|
105
|
+
interface IntrinsicDefinitions {
|
|
106
|
+
markdown: MarkdownDefinition
|
|
107
|
+
}
|
|
108
|
+
}
|