diff --git a/examples/with-draft-js/.gitignore b/examples/with-draft-js/.gitignore deleted file mode 100644 index fd3dbb571a12a..0000000000000 --- a/examples/with-draft-js/.gitignore +++ /dev/null @@ -1,36 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js -.yarn/install-state.gz - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local env files -.env*.local - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts diff --git a/examples/with-draft-js/README.md b/examples/with-draft-js/README.md deleted file mode 100644 index 79a1f2bb6a6ae..0000000000000 --- a/examples/with-draft-js/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# DraftJS Medium editor inspiration - -Have you ever wanted to have an editor like medium.com in your Next.js app? DraftJS is available for SSR, but some plugins like the toolbar are using `window`, which does not work when doing SSR. - -This example aims to provide a fully customizable example of the famous medium editor with DraftJS. The goal was to get it as customizable as possible, and fully working with Next.js without using the react-no-ssr package. - -## Deploy your own - -Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example) or preview live with [StackBlitz](https://stackblitz.com/github/vercel/next.js/tree/canary/examples/with-draft-js) - -[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-draft-js&project-name=with-draft-js&repository-name=with-draft-js) - -## How to use - -Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example: - -```bash -npx create-next-app --example with-draft-js with-draft-js-app -``` - -```bash -yarn create next-app --example with-draft-js with-draft-js-app -``` - -```bash -pnpm create next-app --example with-draft-js with-draft-js-app -``` - -Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). diff --git a/examples/with-draft-js/package.json b/examples/with-draft-js/package.json deleted file mode 100644 index 53c82f07b2871..0000000000000 --- a/examples/with-draft-js/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "private": true, - "scripts": { - "dev": "next", - "build": "next build", - "start": "next start" - }, - "dependencies": { - "draft-js": "^0.11.5", - "next": "latest", - "react": "^18.2.0", - "react-dom": "^18.2.0" - } -} diff --git a/examples/with-draft-js/pages/index.js b/examples/with-draft-js/pages/index.js deleted file mode 100644 index 987d2ac469376..0000000000000 --- a/examples/with-draft-js/pages/index.js +++ /dev/null @@ -1,345 +0,0 @@ -import { Component } from "react"; -import { - Editor, - EditorState, - RichUtils, - convertToRaw, - convertFromRaw, -} from "draft-js"; - -const initialData = { - blocks: [ - { - key: "16d0k", - text: "You can edit this text.", - type: "unstyled", - depth: 0, - inlineStyleRanges: [{ offset: 0, length: 23, style: "BOLD" }], - entityRanges: [], - data: {}, - }, - { - key: "98peq", - text: "", - type: "unstyled", - depth: 0, - inlineStyleRanges: [], - entityRanges: [], - data: {}, - }, - { - key: "ecmnc", - text: "Luke Skywalker has vanished. In his absence, the sinister FIRST ORDER has risen from the ashes of the Empire and will not rest until Skywalker, the last Jedi, has been destroyed.", - type: "unstyled", - depth: 0, - inlineStyleRanges: [ - { offset: 0, length: 14, style: "BOLD" }, - { offset: 133, length: 9, style: "BOLD" }, - ], - entityRanges: [], - data: {}, - }, - { - key: "fe2gn", - text: "", - type: "unstyled", - depth: 0, - inlineStyleRanges: [], - entityRanges: [], - data: {}, - }, - { - key: "4481k", - text: "With the support of the REPUBLIC, General Leia Organa leads a brave RESISTANCE. She is desperate to find her brother Luke and gain his help in restoring peace and justice to the galaxy.", - type: "unstyled", - depth: 0, - inlineStyleRanges: [ - { offset: 34, length: 19, style: "BOLD" }, - { offset: 117, length: 4, style: "BOLD" }, - { offset: 68, length: 10, style: "ANYCUSTOMSTYLE" }, - ], - entityRanges: [], - data: {}, - }, - ], - entityMap: {}, -}; - -// Custom overrides for each style -const styleMap = { - CODE: { - backgroundColor: "rgba(0, 0, 0, 0.05)", - fontFamily: '"Inconsolata", "Menlo", "Consolas", monospace', - fontSize: 16, - padding: 4, - }, - BOLD: { - color: "#395296", - fontWeight: "bold", - }, - ANYCUSTOMSTYLE: { - color: "#00e400", - }, -}; - -export default class App extends Component { - constructor(props) { - super(props); - this.state = { - editorState: EditorState.createWithContent(convertFromRaw(initialData)), - showToolbar: false, - windowWidth: 0, - toolbarMeasures: { - w: 0, - h: 0, - }, - selectionMeasures: { - w: 0, - h: 0, - }, - selectionCoordinates: { - x: 0, - y: 0, - }, - toolbarCoordinates: { - x: 0, - y: 0, - }, - showRawData: false, - }; - - this.focus = () => this.editor.focus(); - this.onChange = (editorState) => this.setState({ editorState }); - } - - onClickEditor = () => { - this.focus(); - this.checkSelectedText(); - }; - - // 1- Check if some text is selected - checkSelectedText = () => { - if (typeof window !== "undefined") { - const text = window.getSelection().toString(); - if (text !== "") { - // 1-a Define the selection coordinates - this.setSelectionXY(); - } else { - // Hide the toolbar if nothing is selected - this.setState({ - showToolbar: false, - }); - } - } - }; - - // 2- Identify the selection coordinates - setSelectionXY = () => { - var r = window.getSelection().getRangeAt(0).getBoundingClientRect(); - var relative = document.body.parentNode.getBoundingClientRect(); - // 2-a Set the selection coordinates in the state - this.setState( - { - selectionCoordinates: r, - windowWidth: relative.width, - selectionMeasures: { - w: r.width, - h: r.height, - }, - }, - () => this.showToolbar(), - ); - }; - - // 3- Show the toolbar - showToolbar = () => { - this.setState( - { - showToolbar: true, - }, - () => this.measureToolbar(), - ); - }; - - // 4- The toolbar was hidden until now - measureToolbar = () => { - // 4-a Define the toolbar width and height, as it is now visible - this.setState( - { - toolbarMeasures: { - w: this.elemWidth, - h: this.elemHeight, - }, - }, - () => this.setToolbarXY(), - ); - }; - - // 5- Now that we have all measures, define toolbar coordinates - setToolbarXY = () => { - let coordinates = {}; - - const { - selectionMeasures, - selectionCoordinates, - toolbarMeasures, - windowWidth, - } = this.state; - - const hiddenTop = selectionCoordinates.y < toolbarMeasures.h; - const hiddenRight = - windowWidth - selectionCoordinates.x < toolbarMeasures.w / 2; - const hiddenLeft = selectionCoordinates.x < toolbarMeasures.w / 2; - - const normalX = - selectionCoordinates.x - toolbarMeasures.w / 2 + selectionMeasures.w / 2; - const normalY = selectionCoordinates.y - toolbarMeasures.h; - - const invertedY = selectionCoordinates.y + selectionMeasures.h; - const moveXToLeft = windowWidth - toolbarMeasures.w; - const moveXToRight = 0; - - coordinates = { - x: normalX, - y: normalY, - }; - - if (hiddenTop) { - coordinates.y = invertedY; - } - - if (hiddenRight) { - coordinates.x = moveXToLeft; - } - - if (hiddenLeft) { - coordinates.x = moveXToRight; - } - - this.setState({ - toolbarCoordinates: coordinates, - }); - }; - - handleKeyCommand = (command) => { - const { editorState } = this.state; - const newState = RichUtils.handleKeyCommand(editorState, command); - if (newState) { - this.onChange(newState); - return true; - } - return false; - }; - - toggleToolbar = (inlineStyle) => { - this.onChange( - RichUtils.toggleInlineStyle(this.state.editorState, inlineStyle), - ); - }; - - render() { - const { editorState } = this.state; - // Make sure we're not on the ssr - if (typeof window !== "undefined") { - // Let's stick the toolbar to the selection - // when the window is resized - window.addEventListener("resize", this.checkSelectedText); - } - - const toolbarStyle = { - display: this.state.showToolbar ? "block" : "none", - backgroundColor: "black", - color: "white", - position: "absolute", - left: this.state.toolbarCoordinates.x, - top: this.state.toolbarCoordinates.y, - zIndex: 999, - padding: 10, - }; - return ( -
-
{ - this.elemWidth = elem ? elem.clientWidth : 0; - this.elemHeight = elem ? elem.clientHeight : 0; - }} - style={toolbarStyle} - > - -
-
- { - this.editor = element; - }} - /> -
-
- -
- {this.state.showRawData && - JSON.stringify(convertToRaw(editorState.getCurrentContent()))} -
-
- ); - } -} - -class ToolbarButton extends Component { - constructor() { - super(); - this.onToggle = (e) => { - e.preventDefault(); - this.props.onToggle(this.props.style); - }; - } - - render() { - const buttonStyle = { - padding: 10, - }; - return ( - - {this.props.label} - - ); - } -} - -var toolbarItems = [ - { label: "Bold", style: "BOLD" }, - { label: "Italic", style: "ITALIC" }, - { label: "Underline", style: "UNDERLINE" }, - { label: "Code", style: "CODE" }, - { label: "Surprise", style: "ANYCUSTOMSTYLE" }, -]; - -const ToolBar = (props) => { - var currentStyle = props.editorState.getCurrentInlineStyle(); - return ( -
- {toolbarItems.map((toolbarItem) => ( - - ))} -
- ); -};