Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/markdown-vanilla-extract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"sanity-plugin-markdown": patch
---

Migrate styling from styled-components to vanilla-extract (zero-runtime CSS)
1 change: 1 addition & 0 deletions plugins/sanity-plugin-markdown/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ Then, make sure to add

```js
import 'easymde/dist/easymde.min.css'
import 'sanity-plugin-markdown/bundle.css'
```

to the top of `pages/_app.tsx`.
Expand Down
23 changes: 21 additions & 2 deletions plugins/sanity-plugin-markdown/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,26 @@
"exports": {
".": "./src/index.ts",
"./next": "./src/indexNext.ts",
"./bundle.css": {
"types": "./dist/bundle-css.d.ts",
"browser": "./dist/bundle.css",
"style": "./dist/bundle.css",
"node": "./dist/bundle-css.js",
"default": "./dist/bundle-css.js"
},
"./package.json": "./package.json"
},
"publishConfig": {
"exports": {
".": "./dist/index.js",
"./next": "./dist/next.js",
"./bundle.css": {
"types": "./dist/bundle-css.d.ts",
"browser": "./dist/bundle.css",
"style": "./dist/bundle.css",
"node": "./dist/bundle-css.js",
"default": "./dist/bundle-css.js"
},
"./package.json": "./package.json"
}
},
Expand All @@ -44,25 +58,30 @@
"dependencies": {
"@sanity/client": "catalog:",
"@sanity/ui": "catalog:",
"@vanilla-extract/dynamic": "catalog:",
"react-simplemde-editor": "^5.2.0"
},
"devDependencies": {
"@sanity/tsconfig": "catalog:",
"@sanity/tsdown-config": "catalog:",
"@sanity/vanilla-extract-vite-plugin": "catalog:",
"@types/node": "catalog:",
"@types/react": "catalog:",
"@types/react-dom": "catalog:",
"@vanilla-extract/css": "catalog:",
"babel-plugin-react-compiler": "catalog:",
"easymde": "^2.21.0",
"react": "catalog:",
"react-dom": "catalog:",
"sanity": "catalog:",
"styled-components": "catalog:",
"tsdown": "catalog:"
},
"peerDependencies": {
"easymde": "^2.18",
"react": "catalog:peer",
"sanity": "catalog:peer",
"styled-components": "catalog:peer"
"react-dom": "catalog:peer",
"sanity": "catalog:peer"
},
"engines": {
"node": ">=20.19 <22 || >=22.12"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import {createVar, globalStyle, style} from '@vanilla-extract/css'

export const fgVar = createVar()
export const borderVar = createVar()
export const bgVar = createVar()
export const selectionHoveredBgVar = createVar()

export const markdownInput = style({})

globalStyle(`${markdownInput} .CodeMirror.CodeMirror`, {
color: fgVar,
borderColor: borderVar,
backgroundColor: 'inherit',
})

globalStyle(`${markdownInput} .cm-s-easymde .CodeMirror-cursor`, {
borderColor: fgVar,
})

globalStyle(`${markdownInput} .editor-toolbar, ${markdownInput} .editor-preview-side`, {
borderColor: borderVar,
})

globalStyle(
`${markdownInput} .CodeMirror-focused .CodeMirror-selected.CodeMirror-selected.CodeMirror-selected`,
{
backgroundColor: selectionHoveredBgVar,
},
)

globalStyle(`${markdownInput} .CodeMirror-selected.CodeMirror-selected.CodeMirror-selected`, {
backgroundColor: bgVar,
})

globalStyle(`${markdownInput} .editor-toolbar > *`, {
color: fgVar,
})

globalStyle(
[
`${markdownInput} .editor-toolbar > .active`,
`${markdownInput} .editor-toolbar > button:hover`,
`${markdownInput} .editor-preview pre`,
`${markdownInput} .cm-s-easymde .cm-comment`,
].join(', '),
{
backgroundColor: bgVar,
},
)

globalStyle(`${markdownInput} .editor-preview`, {
backgroundColor: bgVar,
})

globalStyle(
[
`${markdownInput} .editor-preview h1`,
`${markdownInput} .editor-preview h2`,
`${markdownInput} .editor-preview h3`,
`${markdownInput} .editor-preview h4`,
`${markdownInput} .editor-preview h5`,
`${markdownInput} .editor-preview h6`,
].join(', '),
{
fontSize: 'revert',
},
)

globalStyle(
[`${markdownInput} .editor-preview ul`, `${markdownInput} .editor-preview li`].join(', '),
{
listStyle: 'revert',
padding: 'revert',
},
)

globalStyle(`${markdownInput} .editor-preview a`, {
textDecoration: 'revert',
})
93 changes: 31 additions & 62 deletions plugins/sanity-plugin-markdown/src/components/MarkdownInput.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// TODO: when upgrading to @sanity/ui@4 start using the new tokens
// oxlint-disable typescript/no-deprecated

import {Box, Text} from '@sanity/ui'
import {Box, Text, useTheme_v2} from '@sanity/ui'
import {assignInlineVars} from '@vanilla-extract/dynamic'
// `import type` (not an inline type specifier) so the bundle keeps no side-effect
// `import 'easymde'`, which would break SSR/Node (easymde touches `document` on load)
import type {Options as EasyMdeOptions} from 'easymde'
Expand All @@ -14,74 +12,45 @@ import {
useMemo,
useRef,
useState,
type ComponentProps,
type ReactNode,
} from 'react'
// dont import non-types here, it will break SSR on next
import type {SimpleMDEReactProps} from 'react-simplemde-editor'
import {PatchEvent, set, type StringInputProps, unset, useClient} from 'sanity'
import {styled} from 'styled-components'

import type {MarkdownOptions} from '../schema'

const SimpleMdeReact = lazy(() => import('react-simplemde-editor'))
import {bgVar, borderVar, fgVar, markdownInput, selectionHoveredBgVar} from './MarkdownInput.css'

const MarkdownInputStyles = styled(Box)`
& .CodeMirror.CodeMirror {
color: ${({theme}) => theme.sanity.color.card.enabled.fg};
border-color: ${({theme}) => theme.sanity.color.card.enabled.border};
background-color: inherit;
}

& .cm-s-easymde .CodeMirror-cursor {
border-color: ${({theme}) => theme.sanity.color.card.enabled.fg};
}

& .editor-toolbar,
.editor-preview-side {
border-color: ${({theme}) => theme.sanity.color.card.enabled.border};
}

& .CodeMirror-focused .CodeMirror-selected.CodeMirror-selected.CodeMirror-selected {
background-color: ${({theme}) => theme.sanity.color.selectable?.primary?.hovered?.bg};
}

& .CodeMirror-selected.CodeMirror-selected.CodeMirror-selected {
background-color: ${({theme}) => theme.sanity.color.card.enabled.bg};
}

& .editor-toolbar > * {
color: ${({theme}) => theme.sanity.color.card.enabled.fg};
}

& .editor-toolbar > .active,
.editor-toolbar > button:hover,
.editor-preview pre,
.cm-s-easymde .cm-comment {
background-color: ${({theme}) => theme.sanity.color.card.enabled.bg};
}

& .editor-preview {
background-color: ${({theme}) => theme.sanity.color.card.enabled.bg};

& h1,
h2,
h3,
h4,
h5,
h6 {
font-size: revert;
}
const SimpleMdeReact = lazy(() => import('react-simplemde-editor'))

& ul,
li {
list-style: revert;
padding: revert;
}
function MarkdownInputStyles({
className,
style,
children,
...props
}: ComponentProps<typeof Box> & {children?: ReactNode}) {
const {color} = useTheme_v2()

& a {
text-decoration: revert;
}
}
`
return (
<Box
{...props}
className={className ? `${markdownInput} ${className}` : markdownInput}
style={{
...assignInlineVars({
[fgVar]: color.fg,
[borderVar]: color.border,
[bgVar]: color.bg,
[selectionHoveredBgVar]: color.selectable.primary.hovered.bg,
}),
...style,
}}
>
{children}
</Box>
)
}
Comment thread
cursor[bot] marked this conversation as resolved.

export interface MarkdownInputProps extends StringInputProps {
/**
Expand Down
31 changes: 16 additions & 15 deletions plugins/sanity-plugin-markdown/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,20 @@ test('package exports', {timeout: 30_000}, async () => {
})

expect(manifest.exports).toMatchInlineSnapshot(`
{
".": {
"MarkdownInput": "function",
"defaultMdeTools": "object",
"markdownSchema": "function",
"markdownSchemaType": "object",
},
"./next": {
"MarkdownInput": "function",
"defaultMdeTools": "object",
"markdownSchema": "function",
"markdownSchemaType": "object",
},
}
`)
{
".": {
"MarkdownInput": "function",
"defaultMdeTools": "object",
"markdownSchema": "function",
"markdownSchemaType": "object",
},
"./bundle.css": {},
"./next": {
"MarkdownInput": "function",
"defaultMdeTools": "object",
"markdownSchema": "function",
"markdownSchemaType": "object",
},
}
`)
})
5 changes: 0 additions & 5 deletions plugins/sanity-plugin-markdown/src/typings.d.ts

This file was deleted.

2 changes: 1 addition & 1 deletion plugins/sanity-plugin-markdown/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"extends": ["@sanity/tsconfig/strictest"],
"include": ["**/*.ts", "**/*.tsx", "src/typings.d.ts"],
"include": ["**/*.ts", "**/*.tsx"],
"exclude": ["dist", "node_modules"]
}
42 changes: 34 additions & 8 deletions plugins/sanity-plugin-markdown/tsdown.config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,37 @@
import {defineConfig} from '@sanity/tsdown-config'
import type {UserConfig} from 'tsdown'
import type {TsdownPlugin, UserConfig} from 'tsdown'

export default defineConfig({
entry: {
index: './src/index.ts',
next: './src/indexNext.ts',
/**
* `vanillaExtract: true` injects `import "sanity-plugin-markdown/bundle.css"` into every entry
* that transitively uses `.css.ts` styles. The `/next` entry must stay CSS-import-free for
* Next.js `pages` (see README) — consumers import easymde + bundle.css in `_app.tsx` instead.
*/
const stripBundleCssFromNextEntry = {
name: 'strip-bundle-css-from-next-entry',
generateBundle(_options, bundle) {
const chunk = bundle['next.js']
if (chunk?.type !== 'chunk') return
chunk.code = chunk.code.replace(/^import ["']sanity-plugin-markdown\/bundle\.css["'];\n/, '')
},
styledComponents: true,
reactCompiler: true,
}) satisfies Promise<UserConfig>
} satisfies TsdownPlugin

async function createConfig(): Promise<UserConfig> {
const config = await defineConfig({
entry: {
index: './src/index.ts',
next: './src/indexNext.ts',
},
reactCompiler: true,
vanillaExtract: true,
})

return {
...config,
plugins: [
...(Array.isArray(config.plugins) ? config.plugins : []),
stripBundleCssFromNextEntry,
],
}
}

export default createConfig()
3 changes: 3 additions & 0 deletions plugins/sanity-plugin-markdown/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import {vanillaExtractPlugin} from '@sanity/vanilla-extract-vite-plugin'
import {defineConfig} from 'vitest/config'

export default defineConfig({
plugins: [vanillaExtractPlugin()],
test: {
setupFiles: ['@vanilla-extract/css/disableRuntimeStyles'],
server: {
deps: {
inline: ['vitest-package-exports'],
Expand Down
Loading
Loading