sanity-plugin-markdown 5.1.1 → 5.1.3

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/README.md CHANGED
@@ -1,6 +1,5 @@
1
1
  # sanity-plugin-markdown
2
2
 
3
- > This is a **Sanity Studio v3** plugin.
4
3
  > For the v2 version, please refer to the [v2-branch](https://github.com/sanity-io/sanity-plugin-markdown/tree/studio-v2).
5
4
 
6
5
  ## What is it?
@@ -96,11 +96,13 @@ function MarkdownInput(props) {
96
96
  const {
97
97
  value = "",
98
98
  onChange,
99
- elementProps: { onBlur, onFocus, ref },
99
+ elementProps: { onBlur, onFocus, ref: elementRef },
100
100
  reactMdeProps: { options: mdeCustomOptions, ...reactMdeProps } = {},
101
101
  schemaType,
102
102
  focused
103
- } = props, client = sanity.useClient({ apiVersion: "2022-01-01" }), { imageUrl } = schemaType.options ?? {}, imageUpload = react.useCallback(
103
+ } = props, client = sanity.useClient({ apiVersion: "2022-01-01" }), { imageUrl } = schemaType.options ?? {}, [shouldAutoFocus, setShouldAutoFocus] = react.useState(!1), ref = react.useRef(null);
104
+ react.useImperativeHandle(elementRef, () => ref.current);
105
+ const imageUpload = react.useCallback(
104
106
  (file, onSuccess, onError) => {
105
107
  client.assets.upload("image", file).then((doc) => onSuccess(imageUrl ? imageUrl(doc) : `${doc.url}?w=450`)).catch((e) => {
106
108
  console.error(e), onError(e.message);
@@ -115,8 +117,26 @@ function MarkdownInput(props) {
115
117
  toolbar: defaultMdeTools,
116
118
  status: !1,
117
119
  ...mdeCustomOptions,
118
- autofocus: focused
119
- }), [imageUpload, mdeCustomOptions, focused]), handleChange = react.useCallback(
120
+ autofocus: shouldAutoFocus
121
+ }), [imageUpload, mdeCustomOptions, shouldAutoFocus]);
122
+ react.useEffect(() => {
123
+ const node = ref.current;
124
+ if (node) {
125
+ if (focused && !shouldAutoFocus) {
126
+ const raf = requestAnimationFrame(
127
+ () => setShouldAutoFocus(!node.contains(document.activeElement))
128
+ );
129
+ return () => cancelAnimationFrame(raf);
130
+ }
131
+ if (!focused && shouldAutoFocus) {
132
+ const raf = requestAnimationFrame(
133
+ () => setShouldAutoFocus(node.contains(document.activeElement))
134
+ );
135
+ return () => cancelAnimationFrame(raf);
136
+ }
137
+ }
138
+ }, [focused, shouldAutoFocus]);
139
+ const handleChange = react.useCallback(
120
140
  (newValue) => {
121
141
  onChange(sanity.PatchEvent.from(newValue ? sanity.set(newValue) : sanity.unset()));
122
142
  },
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["../../src/components/MarkdownInputStyles.tsx","../../src/components/MarkdownInput.tsx","../../src/schema.ts","../../src/plugin.tsx"],"sourcesContent":["import {Box} from '@sanity/ui'\nimport {styled} from 'styled-components'\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 {type Options as EasyMdeOptions} from 'easymde'\nimport {lazy, 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 {Box, Text} from '@sanity/ui'\n\nconst SimpleMdeReact = lazy(() => import('react-simplemde-editor'))\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 focused,\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 spellChecker: false,\n sideBySideFullscreen: false,\n uploadImage: true,\n imageUploadFunction: imageUpload,\n toolbar: defaultMdeTools,\n status: false,\n ...mdeCustomOptions,\n autofocus: focused,\n }\n }, [imageUpload, mdeCustomOptions, focused])\n\n const handleChange = useCallback(\n (newValue: string) => {\n onChange(PatchEvent.from(newValue ? set(newValue) : unset()))\n },\n [onChange],\n )\n\n return (\n <MarkdownInputStyles>\n <Suspense fallback={fallback}>\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 </MarkdownInputStyles>\n )\n}\n\nconst fallback = (\n <Box padding={3}>\n <Text>Loading editor...</Text>\n </Box>\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":["styled","Box","lazy","useClient","useCallback","useMemo","PatchEvent","set","unset","jsx","Suspense","Text","defineType","definePlugin"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sources":["../../src/components/MarkdownInputStyles.tsx","../../src/components/MarkdownInput.tsx","../../src/schema.ts","../../src/plugin.tsx"],"sourcesContent":["import {Box} from '@sanity/ui'\nimport {styled} from 'styled-components'\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 {type Options as EasyMdeOptions} from 'easymde'\nimport {\n lazy,\n Suspense,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} 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 {Box, Text} from '@sanity/ui'\n\nconst SimpleMdeReact = lazy(() => import('react-simplemde-editor'))\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: elementRef},\n reactMdeProps: {options: mdeCustomOptions, ...reactMdeProps} = {},\n schemaType,\n focused,\n } = props\n const client = useClient({apiVersion: '2022-01-01'})\n const {imageUrl} = (schemaType.options as MarkdownOptions | undefined) ?? {}\n const [shouldAutoFocus, setShouldAutoFocus] = useState(false)\n const ref = useRef<HTMLDivElement>(null)\n\n // Forward ref to parent form state\n useImperativeHandle(elementRef, () => ref.current)\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 spellChecker: false,\n sideBySideFullscreen: false,\n uploadImage: true,\n imageUploadFunction: imageUpload,\n toolbar: defaultMdeTools,\n status: false,\n ...mdeCustomOptions,\n autofocus: shouldAutoFocus,\n }\n }, [imageUpload, mdeCustomOptions, shouldAutoFocus])\n\n // eslint-disable-next-line consistent-return\n useEffect(() => {\n const node = ref.current\n if (!node) return undefined\n\n if (focused && !shouldAutoFocus) {\n // Do not set autofocus if the field already has focus\n const raf = requestAnimationFrame(() =>\n setShouldAutoFocus(!node.contains(document.activeElement)),\n )\n return () => cancelAnimationFrame(raf)\n }\n\n if (!focused && shouldAutoFocus) {\n // If `focused` is false, and the current active focus is no longer within the editor, reset autofocus state\n const raf = requestAnimationFrame(() =>\n setShouldAutoFocus(node.contains(document.activeElement)),\n )\n return () => cancelAnimationFrame(raf)\n }\n }, [focused, shouldAutoFocus])\n\n const handleChange = useCallback(\n (newValue: string) => {\n onChange(PatchEvent.from(newValue ? set(newValue) : unset()))\n },\n [onChange],\n )\n\n return (\n <MarkdownInputStyles>\n <Suspense fallback={fallback}>\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 </MarkdownInputStyles>\n )\n}\n\nconst fallback = (\n <Box padding={3}>\n <Text>Loading editor...</Text>\n </Box>\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":["styled","Box","lazy","useClient","useState","useRef","useImperativeHandle","useCallback","useMemo","useEffect","PatchEvent","set","unset","jsx","Suspense","Text","defineType","definePlugin"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { useClient, PatchEvent, set, unset, defineType, definePlugin } from "sanity";
2
2
  import { jsx } from "react/jsx-runtime";
3
- import { lazy, useCallback, useMemo, Suspense } from "react";
3
+ import { lazy, useState, useRef, useImperativeHandle, useCallback, useMemo, useEffect, Suspense } from "react";
4
4
  import { Box, Text } from "@sanity/ui";
5
5
  import { styled } from "styled-components";
6
6
  const MarkdownInputStyles = styled(Box)`
@@ -80,11 +80,13 @@ function MarkdownInput(props) {
80
80
  const {
81
81
  value = "",
82
82
  onChange,
83
- elementProps: { onBlur, onFocus, ref },
83
+ elementProps: { onBlur, onFocus, ref: elementRef },
84
84
  reactMdeProps: { options: mdeCustomOptions, ...reactMdeProps } = {},
85
85
  schemaType,
86
86
  focused
87
- } = props, client = useClient({ apiVersion: "2022-01-01" }), { imageUrl } = schemaType.options ?? {}, imageUpload = useCallback(
87
+ } = props, client = useClient({ apiVersion: "2022-01-01" }), { imageUrl } = schemaType.options ?? {}, [shouldAutoFocus, setShouldAutoFocus] = useState(!1), ref = useRef(null);
88
+ useImperativeHandle(elementRef, () => ref.current);
89
+ const imageUpload = useCallback(
88
90
  (file, onSuccess, onError) => {
89
91
  client.assets.upload("image", file).then((doc) => onSuccess(imageUrl ? imageUrl(doc) : `${doc.url}?w=450`)).catch((e) => {
90
92
  console.error(e), onError(e.message);
@@ -99,8 +101,26 @@ function MarkdownInput(props) {
99
101
  toolbar: defaultMdeTools,
100
102
  status: !1,
101
103
  ...mdeCustomOptions,
102
- autofocus: focused
103
- }), [imageUpload, mdeCustomOptions, focused]), handleChange = useCallback(
104
+ autofocus: shouldAutoFocus
105
+ }), [imageUpload, mdeCustomOptions, shouldAutoFocus]);
106
+ useEffect(() => {
107
+ const node = ref.current;
108
+ if (node) {
109
+ if (focused && !shouldAutoFocus) {
110
+ const raf = requestAnimationFrame(
111
+ () => setShouldAutoFocus(!node.contains(document.activeElement))
112
+ );
113
+ return () => cancelAnimationFrame(raf);
114
+ }
115
+ if (!focused && shouldAutoFocus) {
116
+ const raf = requestAnimationFrame(
117
+ () => setShouldAutoFocus(node.contains(document.activeElement))
118
+ );
119
+ return () => cancelAnimationFrame(raf);
120
+ }
121
+ }
122
+ }, [focused, shouldAutoFocus]);
123
+ const handleChange = useCallback(
104
124
  (newValue) => {
105
125
  onChange(PatchEvent.from(newValue ? set(newValue) : unset()));
106
126
  },
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.mjs","sources":["../../src/components/MarkdownInputStyles.tsx","../../src/components/MarkdownInput.tsx","../../src/schema.ts","../../src/plugin.tsx"],"sourcesContent":["import {Box} from '@sanity/ui'\nimport {styled} from 'styled-components'\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 {type Options as EasyMdeOptions} from 'easymde'\nimport {lazy, 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 {Box, Text} from '@sanity/ui'\n\nconst SimpleMdeReact = lazy(() => import('react-simplemde-editor'))\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 focused,\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 spellChecker: false,\n sideBySideFullscreen: false,\n uploadImage: true,\n imageUploadFunction: imageUpload,\n toolbar: defaultMdeTools,\n status: false,\n ...mdeCustomOptions,\n autofocus: focused,\n }\n }, [imageUpload, mdeCustomOptions, focused])\n\n const handleChange = useCallback(\n (newValue: string) => {\n onChange(PatchEvent.from(newValue ? set(newValue) : unset()))\n },\n [onChange],\n )\n\n return (\n <MarkdownInputStyles>\n <Suspense fallback={fallback}>\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 </MarkdownInputStyles>\n )\n}\n\nconst fallback = (\n <Box padding={3}>\n <Text>Loading editor...</Text>\n </Box>\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":[],"mappings":";;;;;AAGa,MAAA,sBAAsB,OAAO,GAAG;AAAA;AAAA,aAEhC,CAAC,EAAC,MAAK,MAAM,MAAM,OAAO,MAAM,KAAK,QAAQ,EAAE;AAAA,oBACxC,CAAC,EAAC,MAAK,MAAM,MAAM,OAAO,MAAM,KAAK,QAAQ,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,oBAKnD,CAAC,EAAC,MAAK,MAAM,MAAM,OAAO,MAAM,KAAK,QAAQ,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA,oBAK/C,CAAC,EAAC,MAAK,MAAM,MAAM,OAAO,MAAM,KAAK,QAAQ,MAAM;AAAA;AAAA;AAAA;AAAA,wBAI/C,CAAC,EAAC,MAAW,MAAA,MAAM,OAAO,MAAM,YAAY,SAAS,SAAS,EAAE;AAAA;AAAA;AAAA;AAAA,wBAIhE,CAAC,EAAC,MAAK,MAAM,MAAM,OAAO,MAAM,KAAK,QAAQ,EAAE;AAAA;AAAA;AAAA;AAAA,aAI1D,CAAC,EAAC,MAAK,MAAM,MAAM,OAAO,MAAM,KAAK,QAAQ,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAOpC,CAAC,EAAC,MAAK,MAAM,MAAM,OAAO,MAAM,KAAK,QAAQ,EAAE;AAAA;AAAA;AAAA;AAAA,wBAI/C,CAAC,EAAC,MAAK,MAAM,MAAM,OAAO,MAAM,KAAK,QAAQ,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GC9BjE,iBAAiB,KAAK,MAAM,OAAO,wBAAwB,CAAC,GAYrD,kBAA6C;AAAA,EACxD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,cAAc,OAA2B;AACjD,QAAA;AAAA,IACJ,QAAQ;AAAA,IACR;AAAA,IACA,cAAc,EAAC,QAAQ,SAAS,IAAG;AAAA,IACnC,eAAe,EAAC,SAAS,kBAAkB,GAAG,kBAAiB,CAAC;AAAA,IAChE;AAAA,IACA;AAAA,MACE,OACE,SAAS,UAAU,EAAC,YAAY,aAAa,CAAA,GAC7C,EAAC,SAAa,IAAA,WAAW,WAA2C,IAEpE,cAAc;AAAA,IAClB,CAAC,MAAY,WAAkC,YAAqC;AAC3E,aAAA,OACJ,OAAO,SAAS,IAAI,EACpB,KAAK,CAAC,QAAQ,UAAU,WAAW,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,QAAQ,CAAC,EACtE,MAAM,CAAC,MAAM;AACZ,gBAAQ,MAAM,CAAC,GACf,QAAQ,EAAE,OAAO;AAAA,MAAA,CAClB;AAAA,IACL;AAAA,IACA,CAAC,QAAQ,QAAQ;AAAA,EAAA,GAGb,aAA6B,QAAQ,OAClC;AAAA,IACL,cAAc;AAAA,IACd,sBAAsB;AAAA,IACtB,aAAa;AAAA,IACb,qBAAqB;AAAA,IACrB,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,GAAG;AAAA,IACH,WAAW;AAAA,EAAA,IAEZ,CAAC,aAAa,kBAAkB,OAAO,CAAC,GAErC,eAAe;AAAA,IACnB,CAAC,aAAqB;AACX,eAAA,WAAW,KAAK,WAAW,IAAI,QAAQ,IAAI,MAAO,CAAA,CAAC;AAAA,IAC9D;AAAA,IACA,CAAC,QAAQ;AAAA,EAAA;AAGX,SACG,oBAAA,qBAAA,EACC,UAAC,oBAAA,UAAA,EAAS,UACR,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAG;AAAA,MACJ;AAAA,MACA;AAAA,MACA,UAAU;AAAA,MACV;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,YAAY;AAAA,IAAA;AAAA,EAAA,EAEhB,CAAA,EACF,CAAA;AAEJ;AAEA,MAAM,+BACH,KAAI,EAAA,SAAS,GACZ,UAAC,oBAAA,MAAA,EAAK,+BAAiB,EACzB,CAAA,GCpGW,mBAAmB,YAsCnB,qBAAqB,WAAW;AAAA,EAC3C,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,YAAY,EAAC,OAAO,cAAa;AACnC,CAAC,GCLY,iBAAiB,aAAa,CAAC,YACnC;AAAA,EACL,MAAM;AAAA,EACN,QAAQ;AAAA,IACN,OAAO;AAAA,MACL,UAAU,OAAO,QACb,EAAC,GAAG,oBAAoB,YAAY,EAAC,OAAO,OAAO,MAAK,EACxD,IAAA;AAAA,IACN;AAAA,EACF;AACF,EACD;"}
1
+ {"version":3,"file":"plugin.mjs","sources":["../../src/components/MarkdownInputStyles.tsx","../../src/components/MarkdownInput.tsx","../../src/schema.ts","../../src/plugin.tsx"],"sourcesContent":["import {Box} from '@sanity/ui'\nimport {styled} from 'styled-components'\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 {type Options as EasyMdeOptions} from 'easymde'\nimport {\n lazy,\n Suspense,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} 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 {Box, Text} from '@sanity/ui'\n\nconst SimpleMdeReact = lazy(() => import('react-simplemde-editor'))\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: elementRef},\n reactMdeProps: {options: mdeCustomOptions, ...reactMdeProps} = {},\n schemaType,\n focused,\n } = props\n const client = useClient({apiVersion: '2022-01-01'})\n const {imageUrl} = (schemaType.options as MarkdownOptions | undefined) ?? {}\n const [shouldAutoFocus, setShouldAutoFocus] = useState(false)\n const ref = useRef<HTMLDivElement>(null)\n\n // Forward ref to parent form state\n useImperativeHandle(elementRef, () => ref.current)\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 spellChecker: false,\n sideBySideFullscreen: false,\n uploadImage: true,\n imageUploadFunction: imageUpload,\n toolbar: defaultMdeTools,\n status: false,\n ...mdeCustomOptions,\n autofocus: shouldAutoFocus,\n }\n }, [imageUpload, mdeCustomOptions, shouldAutoFocus])\n\n // eslint-disable-next-line consistent-return\n useEffect(() => {\n const node = ref.current\n if (!node) return undefined\n\n if (focused && !shouldAutoFocus) {\n // Do not set autofocus if the field already has focus\n const raf = requestAnimationFrame(() =>\n setShouldAutoFocus(!node.contains(document.activeElement)),\n )\n return () => cancelAnimationFrame(raf)\n }\n\n if (!focused && shouldAutoFocus) {\n // If `focused` is false, and the current active focus is no longer within the editor, reset autofocus state\n const raf = requestAnimationFrame(() =>\n setShouldAutoFocus(node.contains(document.activeElement)),\n )\n return () => cancelAnimationFrame(raf)\n }\n }, [focused, shouldAutoFocus])\n\n const handleChange = useCallback(\n (newValue: string) => {\n onChange(PatchEvent.from(newValue ? set(newValue) : unset()))\n },\n [onChange],\n )\n\n return (\n <MarkdownInputStyles>\n <Suspense fallback={fallback}>\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 </MarkdownInputStyles>\n )\n}\n\nconst fallback = (\n <Box padding={3}>\n <Text>Loading editor...</Text>\n </Box>\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":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { useClient, PatchEvent, set, unset, defineType, definePlugin } from "sanity";
2
2
  import { jsx } from "react/jsx-runtime";
3
- import { lazy, useCallback, useMemo, Suspense } from "react";
3
+ import { lazy, useState, useRef, useImperativeHandle, useCallback, useMemo, useEffect, Suspense } from "react";
4
4
  import { Box, Text } from "@sanity/ui";
5
5
  import { styled } from "styled-components";
6
6
  const MarkdownInputStyles = styled(Box)`
@@ -80,11 +80,13 @@ function MarkdownInput(props) {
80
80
  const {
81
81
  value = "",
82
82
  onChange,
83
- elementProps: { onBlur, onFocus, ref },
83
+ elementProps: { onBlur, onFocus, ref: elementRef },
84
84
  reactMdeProps: { options: mdeCustomOptions, ...reactMdeProps } = {},
85
85
  schemaType,
86
86
  focused
87
- } = props, client = useClient({ apiVersion: "2022-01-01" }), { imageUrl } = schemaType.options ?? {}, imageUpload = useCallback(
87
+ } = props, client = useClient({ apiVersion: "2022-01-01" }), { imageUrl } = schemaType.options ?? {}, [shouldAutoFocus, setShouldAutoFocus] = useState(!1), ref = useRef(null);
88
+ useImperativeHandle(elementRef, () => ref.current);
89
+ const imageUpload = useCallback(
88
90
  (file, onSuccess, onError) => {
89
91
  client.assets.upload("image", file).then((doc) => onSuccess(imageUrl ? imageUrl(doc) : `${doc.url}?w=450`)).catch((e) => {
90
92
  console.error(e), onError(e.message);
@@ -99,8 +101,26 @@ function MarkdownInput(props) {
99
101
  toolbar: defaultMdeTools,
100
102
  status: !1,
101
103
  ...mdeCustomOptions,
102
- autofocus: focused
103
- }), [imageUpload, mdeCustomOptions, focused]), handleChange = useCallback(
104
+ autofocus: shouldAutoFocus
105
+ }), [imageUpload, mdeCustomOptions, shouldAutoFocus]);
106
+ useEffect(() => {
107
+ const node = ref.current;
108
+ if (node) {
109
+ if (focused && !shouldAutoFocus) {
110
+ const raf = requestAnimationFrame(
111
+ () => setShouldAutoFocus(!node.contains(document.activeElement))
112
+ );
113
+ return () => cancelAnimationFrame(raf);
114
+ }
115
+ if (!focused && shouldAutoFocus) {
116
+ const raf = requestAnimationFrame(
117
+ () => setShouldAutoFocus(node.contains(document.activeElement))
118
+ );
119
+ return () => cancelAnimationFrame(raf);
120
+ }
121
+ }
122
+ }, [focused, shouldAutoFocus]);
123
+ const handleChange = useCallback(
104
124
  (newValue) => {
105
125
  onChange(PatchEvent.from(newValue ? set(newValue) : unset()));
106
126
  },
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.esm.js","sources":["../../src/components/MarkdownInputStyles.tsx","../../src/components/MarkdownInput.tsx","../../src/schema.ts","../../src/plugin.tsx"],"sourcesContent":["import {Box} from '@sanity/ui'\nimport {styled} from 'styled-components'\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 {type Options as EasyMdeOptions} from 'easymde'\nimport {lazy, 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 {Box, Text} from '@sanity/ui'\n\nconst SimpleMdeReact = lazy(() => import('react-simplemde-editor'))\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 focused,\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 spellChecker: false,\n sideBySideFullscreen: false,\n uploadImage: true,\n imageUploadFunction: imageUpload,\n toolbar: defaultMdeTools,\n status: false,\n ...mdeCustomOptions,\n autofocus: focused,\n }\n }, [imageUpload, mdeCustomOptions, focused])\n\n const handleChange = useCallback(\n (newValue: string) => {\n onChange(PatchEvent.from(newValue ? set(newValue) : unset()))\n },\n [onChange],\n )\n\n return (\n <MarkdownInputStyles>\n <Suspense fallback={fallback}>\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 </MarkdownInputStyles>\n )\n}\n\nconst fallback = (\n <Box padding={3}>\n <Text>Loading editor...</Text>\n </Box>\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":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin.esm.js","sources":["../../src/components/MarkdownInputStyles.tsx","../../src/components/MarkdownInput.tsx","../../src/schema.ts","../../src/plugin.tsx"],"sourcesContent":["import {Box} from '@sanity/ui'\nimport {styled} from 'styled-components'\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 {type Options as EasyMdeOptions} from 'easymde'\nimport {\n lazy,\n Suspense,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} 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 {Box, Text} from '@sanity/ui'\n\nconst SimpleMdeReact = lazy(() => import('react-simplemde-editor'))\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: elementRef},\n reactMdeProps: {options: mdeCustomOptions, ...reactMdeProps} = {},\n schemaType,\n focused,\n } = props\n const client = useClient({apiVersion: '2022-01-01'})\n const {imageUrl} = (schemaType.options as MarkdownOptions | undefined) ?? {}\n const [shouldAutoFocus, setShouldAutoFocus] = useState(false)\n const ref = useRef<HTMLDivElement>(null)\n\n // Forward ref to parent form state\n useImperativeHandle(elementRef, () => ref.current)\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 spellChecker: false,\n sideBySideFullscreen: false,\n uploadImage: true,\n imageUploadFunction: imageUpload,\n toolbar: defaultMdeTools,\n status: false,\n ...mdeCustomOptions,\n autofocus: shouldAutoFocus,\n }\n }, [imageUpload, mdeCustomOptions, shouldAutoFocus])\n\n // eslint-disable-next-line consistent-return\n useEffect(() => {\n const node = ref.current\n if (!node) return undefined\n\n if (focused && !shouldAutoFocus) {\n // Do not set autofocus if the field already has focus\n const raf = requestAnimationFrame(() =>\n setShouldAutoFocus(!node.contains(document.activeElement)),\n )\n return () => cancelAnimationFrame(raf)\n }\n\n if (!focused && shouldAutoFocus) {\n // If `focused` is false, and the current active focus is no longer within the editor, reset autofocus state\n const raf = requestAnimationFrame(() =>\n setShouldAutoFocus(node.contains(document.activeElement)),\n )\n return () => cancelAnimationFrame(raf)\n }\n }, [focused, shouldAutoFocus])\n\n const handleChange = useCallback(\n (newValue: string) => {\n onChange(PatchEvent.from(newValue ? set(newValue) : unset()))\n },\n [onChange],\n )\n\n return (\n <MarkdownInputStyles>\n <Suspense fallback={fallback}>\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 </MarkdownInputStyles>\n )\n}\n\nconst fallback = (\n <Box padding={3}>\n <Text>Loading editor...</Text>\n </Box>\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":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sanity-plugin-markdown",
3
- "version": "5.1.1",
3
+ "version": "5.1.3",
4
4
  "description": "Markdown fields in Sanity Studio. Supports Github flavored Markdown and image uploads.",
5
5
  "keywords": [
6
6
  "sanity",
@@ -64,7 +64,7 @@
64
64
  "browserslist": "extends @sanity/browserslist-config",
65
65
  "prettier": "@sanity/prettier-config",
66
66
  "dependencies": {
67
- "@sanity/incompatible-plugin": "^1.0.4",
67
+ "@sanity/incompatible-plugin": "^1.0.5",
68
68
  "@sanity/ui": "^2.8.9",
69
69
  "react-simplemde-editor": "^5.2.0"
70
70
  },
@@ -75,6 +75,7 @@
75
75
  "@sanity/plugin-kit": "^4.0.18",
76
76
  "@sanity/prettier-config": "^1.0.3",
77
77
  "@sanity/semantic-release-preset": "^2.0.5",
78
+ "@sanity/vision": "^4.1.1",
78
79
  "@types/react": "^18.3.5",
79
80
  "@typescript-eslint/eslint-plugin": "^5.62.0",
80
81
  "@typescript-eslint/parser": "^5.62.0",
@@ -92,14 +93,14 @@
92
93
  "react": "^18.3.1",
93
94
  "react-dom": "^18.3.1",
94
95
  "react-is": "^18.3.1",
95
- "sanity": "^3.57.1",
96
- "styled-components": "^6.1.13",
96
+ "sanity": "^4.1.1",
97
+ "styled-components": "^6.1.19",
97
98
  "typescript": "5.5.4"
98
99
  },
99
100
  "peerDependencies": {
100
101
  "easymde": "^2.18",
101
102
  "react": "^18.3 || ^19",
102
- "sanity": "^3.23",
103
+ "sanity": "^3.23 || ^4.0.0-0",
103
104
  "styled-components": "^6.1"
104
105
  },
105
106
  "engines": {
@@ -1,5 +1,14 @@
1
1
  import {type Options as EasyMdeOptions} from 'easymde'
2
- import {lazy, Suspense, useCallback, useMemo} from 'react'
2
+ import {
3
+ lazy,
4
+ Suspense,
5
+ useCallback,
6
+ useEffect,
7
+ useImperativeHandle,
8
+ useMemo,
9
+ useRef,
10
+ useState,
11
+ } from 'react'
3
12
  // dont import non-types here, it will break SSR on next
4
13
  import type {SimpleMDEReactProps} from 'react-simplemde-editor'
5
14
  import {PatchEvent, set, StringInputProps, unset, useClient} from 'sanity'
@@ -40,13 +49,18 @@ export function MarkdownInput(props: MarkdownInputProps) {
40
49
  const {
41
50
  value = '',
42
51
  onChange,
43
- elementProps: {onBlur, onFocus, ref},
52
+ elementProps: {onBlur, onFocus, ref: elementRef},
44
53
  reactMdeProps: {options: mdeCustomOptions, ...reactMdeProps} = {},
45
54
  schemaType,
46
55
  focused,
47
56
  } = props
48
57
  const client = useClient({apiVersion: '2022-01-01'})
49
58
  const {imageUrl} = (schemaType.options as MarkdownOptions | undefined) ?? {}
59
+ const [shouldAutoFocus, setShouldAutoFocus] = useState(false)
60
+ const ref = useRef<HTMLDivElement>(null)
61
+
62
+ // Forward ref to parent form state
63
+ useImperativeHandle(elementRef, () => ref.current)
50
64
 
51
65
  const imageUpload = useCallback(
52
66
  (file: File, onSuccess: (url: string) => void, onError: (error: string) => void) => {
@@ -70,9 +84,31 @@ export function MarkdownInput(props: MarkdownInputProps) {
70
84
  toolbar: defaultMdeTools,
71
85
  status: false,
72
86
  ...mdeCustomOptions,
73
- autofocus: focused,
87
+ autofocus: shouldAutoFocus,
88
+ }
89
+ }, [imageUpload, mdeCustomOptions, shouldAutoFocus])
90
+
91
+ // eslint-disable-next-line consistent-return
92
+ useEffect(() => {
93
+ const node = ref.current
94
+ if (!node) return undefined
95
+
96
+ if (focused && !shouldAutoFocus) {
97
+ // Do not set autofocus if the field already has focus
98
+ const raf = requestAnimationFrame(() =>
99
+ setShouldAutoFocus(!node.contains(document.activeElement)),
100
+ )
101
+ return () => cancelAnimationFrame(raf)
102
+ }
103
+
104
+ if (!focused && shouldAutoFocus) {
105
+ // If `focused` is false, and the current active focus is no longer within the editor, reset autofocus state
106
+ const raf = requestAnimationFrame(() =>
107
+ setShouldAutoFocus(node.contains(document.activeElement)),
108
+ )
109
+ return () => cancelAnimationFrame(raf)
74
110
  }
75
- }, [imageUpload, mdeCustomOptions, focused])
111
+ }, [focused, shouldAutoFocus])
76
112
 
77
113
  const handleChange = useCallback(
78
114
  (newValue: string) => {
@@ -0,0 +1,6 @@
1
+ import {type Theme} from '@sanity/ui/theme'
2
+
3
+ declare module 'styled-components' {
4
+ // eslint-disable-next-line no-unused-vars
5
+ interface DefaultTheme extends Theme {}
6
+ }