[Docs] Update with-slate example (#39639)
## Changelog - Migrated `with-slate` example to typescript - Updated dependencies to latest stable versions - Added api route to demonstrate saving of `editorState` ## Documentation / Examples - [x] Make sure the linting passes by running `pnpm lint` - [x] The examples guidelines are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples)
This commit is contained in:
parent
7a93093332
commit
3d3938b793
6 changed files with 114 additions and 25 deletions
|
@ -7,10 +7,15 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"next": "latest",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"slate": "^0.76.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"slate": "^0.82.0",
|
||||
"slate-history": "0.66.0",
|
||||
"slate-react": "^0.76.1"
|
||||
"slate-react": "^0.82.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "18.7.5",
|
||||
"@types/react": "18.0.17",
|
||||
"typescript": "4.7.4"
|
||||
}
|
||||
}
|
||||
|
|
20
examples/with-slate/pages/api/editor-state.ts
Normal file
20
examples/with-slate/pages/api/editor-state.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
export default async function handleEditorStateChange(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
if (req.method !== 'POST') {
|
||||
return res
|
||||
.setHeader('Allow', ['POST'])
|
||||
.status(405)
|
||||
.end(`Method ${req.method} Not Allowed`)
|
||||
}
|
||||
|
||||
const editorState = JSON.parse(req.body)
|
||||
console.log('TODO: Save editorState on the server', editorState)
|
||||
|
||||
res.json({
|
||||
status: 'ok',
|
||||
})
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
import { useState } from 'react'
|
||||
import { createEditor } from 'slate'
|
||||
import { Slate, Editable, withReact } from 'slate-react'
|
||||
import { withHistory } from 'slate-history'
|
||||
|
||||
export default function IndexPage() {
|
||||
const [editor] = useState(() => withReact(withHistory(createEditor())), [])
|
||||
const [value, setValue] = useState([
|
||||
{
|
||||
children: [
|
||||
{ text: 'This is editable plain text, just like a <textarea>!' },
|
||||
],
|
||||
},
|
||||
])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={setValue}>
|
||||
<Editable placeholder="Enter some plain text..." />
|
||||
</Slate>
|
||||
)
|
||||
}
|
51
examples/with-slate/pages/index.tsx
Normal file
51
examples/with-slate/pages/index.tsx
Normal file
|
@ -0,0 +1,51 @@
|
|||
import { useState } from 'react'
|
||||
import { createEditor, Descendant } from 'slate'
|
||||
import { Slate, Editable, withReact } from 'slate-react'
|
||||
import { withHistory } from 'slate-history'
|
||||
import { InferGetServerSidePropsType } from 'next'
|
||||
|
||||
export async function getServerSideProps() {
|
||||
return {
|
||||
props: {
|
||||
editorState: [
|
||||
{
|
||||
children: [
|
||||
{ text: 'This is editable plain text, just like a <textarea>!' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async function saveEditorState(edtorState: Descendant[]) {
|
||||
const response = await fetch('/api/editor-state', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(edtorState),
|
||||
})
|
||||
return response.json()
|
||||
}
|
||||
|
||||
export default function IndexPage({
|
||||
editorState,
|
||||
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
|
||||
const [editor] = useState(() => withReact(withHistory(createEditor())))
|
||||
return (
|
||||
<Slate
|
||||
editor={editor}
|
||||
value={editorState}
|
||||
onChange={async (value) => {
|
||||
const isAstChange = editor.operations.some(
|
||||
(op) => 'set_selection' !== op.type
|
||||
)
|
||||
if (isAstChange) {
|
||||
// You might want to debounce the following call!
|
||||
const responseData = await saveEditorState(value)
|
||||
console.log('Send editor state to the server', responseData)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Editable placeholder="Enter some plain text..." />
|
||||
</Slate>
|
||||
)
|
||||
}
|
20
examples/with-slate/tsconfig.json
Normal file
20
examples/with-slate/tsconfig.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"incremental": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve"
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
14
examples/with-slate/types/slate.d.ts
vendored
Normal file
14
examples/with-slate/types/slate.d.ts
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { BaseEditor } from 'slate'
|
||||
import { ReactEditor } from 'slate-react'
|
||||
import { HistoryEditor } from 'slate-history'
|
||||
|
||||
type CustomElement = { type?: 'paragraph'; children: CustomText[] }
|
||||
type CustomText = { text: string; bold?: true }
|
||||
|
||||
declare module 'slate' {
|
||||
interface CustomTypes {
|
||||
Editor: BaseEditor & ReactEditor & HistoryEditor
|
||||
Element: CustomElement
|
||||
Text: CustomText
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue