├── .gitignore
├── LICENSE.txt
├── README.md
├── demo.jpg
├── lerna.json
├── package.json
├── packages
├── demo
│ ├── .babelrc
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── LICENSE.txt
│ ├── README.md
│ ├── package.json
│ └── src
│ │ ├── App.js
│ │ ├── default.md
│ │ ├── index.css
│ │ ├── index.html
│ │ ├── index.js
│ │ ├── mdx
│ │ └── Grid.js
│ │ └── serviceWorker.js
└── editor
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── LICENSE.txt
│ ├── README.md
│ ├── package.json
│ └── src
│ ├── Toolbar.js
│ └── index.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | lerna-debug.log
3 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Benedikt Rötsch
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MDX Live Editor
2 |
3 | > Extensible mdx editor to edit mdx and preview live in your browser.
4 |
5 | * Based on [EasyMDE](https://github.com/Ionaru/easy-markdown-editor) and [MDX Runtime](https://mdxjs.com/advanced/runtime/)
6 |
7 | [](https://axe312ger.github.io/mdx-live-editor/)
8 |
9 | ## Goals
10 |
11 | * Live preview of MDX
12 | * Flawless editing through good UX
13 | * Guiding the non-technical user
14 | * Standalone lib with embeddability to any web based system
15 |
16 | # Development
17 |
18 | This repository is a [monorepo](https://trunkbaseddevelopment.com/monorepos/) managed using [Lerna](https://lerna.js.org/). This means there are multiple [packages](https://github.com/axe312ger/mdx-live-editor/tree/packages) managed in this codebase, even though we publish them to NPM as separate packages.
19 |
20 | ## Requirements
21 |
22 | * [yarn](https://yarnpkg.com/en/docs/install)
23 |
24 | ## Install dependencies
25 | ```
26 | lerna bootstrap
27 | ```
28 |
--------------------------------------------------------------------------------
/demo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/axe312ger/mdx-live-editor/0b92471f701e39e4d0cf3414cb304ac10f37b2c0/demo.jpg
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": ["packages/*"],
3 | "version": "independent",
4 | "npmClient": "yarn",
5 | "useWorkspaces": true
6 | }
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mdx-live",
3 | "private": true,
4 | "scripts": {
5 | "build": "lerna run build",
6 | "publish": "lerna version --no-push --conventional-commits && lerna publish from-git"
7 | },
8 | "devDependencies": {
9 | "lerna": "^3.13.3"
10 | },
11 | "workspaces": [
12 | "packages/*"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/packages/demo/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | "@babel/plugin-proposal-class-properties",
4 | [
5 | "@axe312/babel-plugin-inline-import",
6 | {
7 | "extensions": [".md"]
8 | }
9 | ]
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/packages/demo/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | .cache
3 |
4 | # Created by https://www.gitignore.io/api/node,linux,macos,windows,visualstudiocode
5 | # Edit at https://www.gitignore.io/?templates=node,linux,macos,windows,visualstudiocode
6 |
7 | ### Linux ###
8 | *~
9 |
10 | # temporary files which can be created if a process still has a handle open of a deleted file
11 | .fuse_hidden*
12 |
13 | # KDE directory preferences
14 | .directory
15 |
16 | # Linux trash folder which might appear on any partition or disk
17 | .Trash-*
18 |
19 | # .nfs files are created when an open file is removed but is still being accessed
20 | .nfs*
21 |
22 | ### macOS ###
23 | # General
24 | .DS_Store
25 | .AppleDouble
26 | .LSOverride
27 |
28 | # Icon must end with two \r
29 | Icon
30 |
31 | # Thumbnails
32 | ._*
33 |
34 | # Files that might appear in the root of a volume
35 | .DocumentRevisions-V100
36 | .fseventsd
37 | .Spotlight-V100
38 | .TemporaryItems
39 | .Trashes
40 | .VolumeIcon.icns
41 | .com.apple.timemachine.donotpresent
42 |
43 | # Directories potentially created on remote AFP share
44 | .AppleDB
45 | .AppleDesktop
46 | Network Trash Folder
47 | Temporary Items
48 | .apdisk
49 |
50 | ### Node ###
51 | # Logs
52 | logs
53 | *.log
54 | npm-debug.log*
55 | yarn-debug.log*
56 | yarn-error.log*
57 | lerna-debug.log*
58 |
59 | # Diagnostic reports (https://nodejs.org/api/report.html)
60 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
61 |
62 | # Runtime data
63 | pids
64 | *.pid
65 | *.seed
66 | *.pid.lock
67 |
68 | # Directory for instrumented libs generated by jscoverage/JSCover
69 | lib-cov
70 |
71 | # Coverage directory used by tools like istanbul
72 | coverage
73 |
74 | # nyc test coverage
75 | .nyc_output
76 |
77 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
78 | .grunt
79 |
80 | # Bower dependency directory (https://bower.io/)
81 | bower_components
82 |
83 | # node-waf configuration
84 | .lock-wscript
85 |
86 | # Compiled binary addons (https://nodejs.org/api/addons.html)
87 | build/Release
88 |
89 | # Dependency directories
90 | node_modules/
91 | jspm_packages/
92 |
93 | # TypeScript v1 declaration files
94 | typings/
95 |
96 | # Optional npm cache directory
97 | .npm
98 |
99 | # Optional eslint cache
100 | .eslintcache
101 |
102 | # Optional REPL history
103 | .node_repl_history
104 |
105 | # Output of 'npm pack'
106 | *.tgz
107 |
108 | # Yarn Integrity file
109 | .yarn-integrity
110 |
111 | # dotenv environment variables file
112 | .env
113 | .env.test
114 |
115 | # parcel-bundler cache (https://parceljs.org/)
116 | .cache
117 |
118 | # next.js build output
119 | .next
120 |
121 | # nuxt.js build output
122 | .nuxt
123 |
124 | # vuepress build output
125 | .vuepress/dist
126 |
127 | # Serverless directories
128 | .serverless/
129 |
130 | # FuseBox cache
131 | .fusebox/
132 |
133 | # DynamoDB Local files
134 | .dynamodb/
135 |
136 | ### VisualStudioCode ###
137 | .vscode/*
138 | !.vscode/settings.json
139 | !.vscode/tasks.json
140 | !.vscode/launch.json
141 | !.vscode/extensions.json
142 |
143 | ### VisualStudioCode Patch ###
144 | # Ignore all local history of files
145 | .history
146 |
147 | ### Windows ###
148 | # Windows thumbnail cache files
149 | Thumbs.db
150 | ehthumbs.db
151 | ehthumbs_vista.db
152 |
153 | # Dump file
154 | *.stackdump
155 |
156 | # Folder config file
157 | [Dd]esktop.ini
158 |
159 | # Recycle Bin used on file shares
160 | $RECYCLE.BIN/
161 |
162 | # Windows Installer files
163 | *.cab
164 | *.msi
165 | *.msix
166 | *.msm
167 | *.msp
168 |
169 | # Windows shortcuts
170 | *.lnk
171 |
172 | # End of https://www.gitignore.io/api/node,linux,macos,windows,visualstudiocode
173 |
--------------------------------------------------------------------------------
/packages/demo/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [0.0.9](https://github.com/axe312ger/mdx-live-editor/compare/@mdx-live/demo@0.0.8...@mdx-live/demo@0.0.9) (2019-04-18)
7 |
8 |
9 | ### Bug Fixes
10 |
11 | * **demo:** improve styling while loading ([19ea0db](https://github.com/axe312ger/mdx-live-editor/commit/19ea0db))
12 | * **grid:** use proper icon ([bab8644](https://github.com/axe312ger/mdx-live-editor/commit/bab8644))
13 |
14 |
15 |
16 |
17 |
18 | ## [0.0.8](https://github.com/axe312ger/mdx-live-editor/compare/@mdx-live/demo@0.0.7...@mdx-live/demo@0.0.8) (2019-04-18)
19 |
20 | **Note:** Version bump only for package @mdx-live/demo
21 |
22 |
23 |
24 |
25 |
26 | ## [0.0.7](https://github.com/axe312ger/mdx-live-editor/compare/@mdx-live/demo@0.0.6...@mdx-live/demo@0.0.7) (2019-04-18)
27 |
28 | **Note:** Version bump only for package @mdx-live/demo
29 |
30 |
31 |
32 |
33 |
34 | ## [0.0.2](https://github.com/axe312ger/mdx-live-editor/compare/@mdx-live/demo@0.0.2...@mdx-live/demo@0.0.2) (2019-04-18)
35 |
--------------------------------------------------------------------------------
/packages/demo/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Benedikt Rötsch
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/demo/README.md:
--------------------------------------------------------------------------------
1 | # MDX Live Editor Preview
2 |
3 | [](https://axe312ger.github.io/mdx-live-editor/)
4 |
5 | ## Available Scripts
6 |
7 | ### `npm start`
8 |
9 | Run development server with live-reload.
10 |
11 | ### `npm run build`
12 |
13 | Build production ready static version of this demo.
14 |
15 | ### `npm run analyze`
16 |
17 | Analyze bundle size of last production build.
18 |
19 | ### `npm run deploy`
20 |
21 | Deploy demo to GitHub pages.
22 |
--------------------------------------------------------------------------------
/packages/demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@mdx-live/demo",
3 | "description": "See here https://axe312ger.github.io/mdx-live-editor/",
4 | "version": "0.0.9",
5 | "private": true,
6 | "homepage": "https://axe312ger.github.io/mdx-live-editor/",
7 | "dependencies": {
8 | "@axe312/easymde": "^2.7.1",
9 | "@mdx-live/editor": "^0.0.5",
10 | "prop-types": "^15.7.2",
11 | "react": "^16.8.6",
12 | "react-dom": "^16.8.6",
13 | "styled-components": "^4.2.0"
14 | },
15 | "devDependencies": {
16 | "@axe312/babel-plugin-inline-import": "^4.0.0",
17 | "@babel/core": "^7.4.3",
18 | "@babel/plugin-proposal-class-properties": "^7.4.0",
19 | "gh-pages": "^2.0.1",
20 | "source-map-explorer": "^1.8.0"
21 | },
22 | "scripts": {
23 | "analyze": "source-map-explorer 'dist/*.js'",
24 | "dev": "parcel src/index.html",
25 | "build": "parcel build src/index.html",
26 | "deploy": "npm run build && gh-pages -d build"
27 | },
28 | "browserslist": [
29 | ">0.2%",
30 | "not dead",
31 | "not ie <= 11",
32 | "not op_mini all"
33 | ],
34 | "gitHead": "d33cf9119e9ca9493c309cc7f4fbd898e80b1c96"
35 | }
36 |
--------------------------------------------------------------------------------
/packages/demo/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef, useState } from 'react'
2 |
3 | import mdxLiveEditor from '@mdx-live/editor'
4 | import styled from 'styled-components'
5 | import '@axe312/easymde/dist/easymde.min.css'
6 |
7 | import Grid from './mdx/Grid'
8 | import defaultMarkdownValue from './default.md'
9 |
10 | const Textarea = styled.textarea`
11 | min-width: 100vw;
12 | min-height: 100vh;
13 | `
14 |
15 | const components = [
16 | {
17 | tagname: 'Grid',
18 | component: Grid,
19 | title: 'Grid',
20 | description: 'Display content next to each other',
21 | icon: 'grip-horizontal',
22 | demo: `
23 |
24 |
25 |
26 | `
27 | }
28 | ]
29 |
30 | const replacements = {
31 | h1: ({ children, ...props }) => (
32 |
33 | {children}
34 |
35 | )
36 | }
37 |
38 | export default function App() {
39 | const editorRef = useRef(null)
40 | const [editor, setEditor] = useState(null)
41 |
42 | useEffect(() => {
43 | if (!editor) {
44 | setEditor(
45 | mdxLiveEditor({
46 | components,
47 | replacements,
48 | easymde: { element: editorRef.current }
49 | })
50 | )
51 | }
52 | })
53 |
54 | return (
55 |
56 | )
57 | }
58 |
--------------------------------------------------------------------------------
/packages/demo/src/default.md:
--------------------------------------------------------------------------------
1 | # MDX Live Editor
2 |
3 | * Based on [EasyMDE](https://github.com/Ionaru/easy-markdown-editor) and [MDX Runtime](https://mdxjs.com/advanced/runtime/)
4 |
5 | ## Example Component
6 |
7 | Displays any content next to each other. Works best with 🐈
8 |
9 |
10 |
11 | 
12 |
13 |
14 |
15 | 
16 |
17 | ### Any content
18 |
19 | Just wrap a grid column with a div or a provided custom component
20 |
21 |
22 |
23 | 
24 |
25 |
26 |
27 | ## Just some demo content
28 |
29 | Lorem markdownum accepere habeto Hellespontus mater sidus **ab pollice**! Non
30 | ante natalis metuendus, litore arma ambiguo adspicit matres gravis mollem
31 | trabibus procorum, manu. Erat arguitur. Patrios in habitat moenibus labra
32 | membraque heros mille somnus perempto genitor promittit ramis, suspiratibus
33 | gratia Arctos. Me nec.
34 |
35 | Ignis Ulixes penatigero utramque gente exstante. Novis Capitolia o nubibus
36 | simul, retia facta *Phaethon littera*; quod! Et hoc caelum mutatus et linguae
37 | studiisque anhelis [tenet](http://erat.com/arida).
38 |
39 | device(bitmap_web_wi - activexBsodVideo);
40 | if (clip) {
41 | openSoftwareHypermedia(serverModem);
42 | systemPaperRefresh.ataPoint(4, adwareCard);
43 | } else {
44 | barUnc /= 510214 * iscsiDataE;
45 | http = rt;
46 | richRosetta -= gpu.remoteWeb(packet_access, cd_tweak_expansion) +
47 | heuristic * cable;
48 | }
49 | piconet(asp_windows_drive - 933919, 4);
50 |
51 | [Ferro deponere](http://www.iovis-potentia.org/ora.aspx) caluere ne Thescelus
52 | nemus vultus relatis fictos sub abstulit? **Spectent proles**, diu tulit, quid
53 | est; lumina illa cognoscenti mensae processit nescio! Spuma imitamine Io grande
54 | acerno, heu edidit turbarat nomenque verbisque coniunx, adeunt! Quis dare cursu,
55 | tantum boumque, infirmis.
56 |
57 | ## Robora et possim nec natum iusta
58 |
59 | Capillis secreta terga, adsidua numquam: Atridae sanguis, micant omnia,
60 | concipias secreta signatum **spectans diffusum**? Tantum Romuleae pavens
61 | clamavit erat insequitur fameque petis nec tui. Alii orbem Dianae, tibi tectus
62 | cadunt occidit medioque, ad consedit. Omne tulit vires post robore poplite. Est
63 | Cycno parte rex *socerum* cumque fusus excussit, sic quam similisque, ignes
64 | [vota](http://qualem-quae.com/somnus.html), et nec.
65 |
66 | if (5) {
67 | linuxDomainBalancing += domain;
68 | nanometer.windowsCodeHorizontal(3);
69 | ebookIcmpPum /= e / -3 + multimedia;
70 | } else {
71 | realityCookieJava += ddrRwExcel(warmUsername, ocrPeripheral);
72 | asp_right *= directory.file(partition_pad + tftp_duplex, 5,
73 | rawDesktopSyn);
74 | }
75 | if (table / command_cold >= slaSpeakersInbox) {
76 | degaussSync(property_radcab, vector, soapThread.ansi.web(
77 | video_printer_tiger));
78 | archie_design = spamMetalOsi;
79 | } else {
80 | subdirectoryXml += ppm(streaming_rw) + certificate;
81 | ivr.and.file(lifo);
82 | commerce_disk_transistor += supply(bitDegauss);
83 | }
84 | var textAsciiSystem = 3;
85 | cellAix.plain(kibibyteSsid(drag, macUltra), phreaking);
86 | hardOsdDll.leafModelInterpreter -= 5 - outputLogicIp * system * jfs;
87 |
88 | Auras eget Amphitrite procul numeroque dumque illi unius capillos fertur:
89 | inserit agros minas. Quoque glaebis loquiturque furori in Orphea, se non
90 | ignipedum tendens aere umbra sumpto, *saucius*. Pone loco draconis morsu
91 | festumque referre ille simul adstitit et Coeranon? **Prospicientis graves**
92 | nomen, sanguineae annos fratre regina, per tutae spectari aether anne, ad?
93 |
94 | > Nate pollice noctis [quam](http://ea.io/), natantia est expulit puerilibus,
95 | > ora! Diemque tale mittentis inque pugnantem turpius, alte qui terraeque sentit
96 | > gaudere bisque, inulta. Me ego cum est *tacui* laqueoque: nutrix ventoque:
97 | > postquam: est primoque viasque terris. Quamquam foedera est lumen cicatrix vix
98 | > mensam vivacis in [iubet](http://proceresmeruit.org/), et iacit sacrarunt.
99 |
100 | Dum more saecula ab rotarum isdem ille relinquunt admovit prolem. Quae pectora
101 | reperta, aut fugis gratia tabellas paterno, illa excidit? Sanguinis *in* pavida
102 | si cupit respicit aris membra pedibusque cruorem veluti sub certe quam parentis,
103 | vulnere spatiantes oculi adstitit.
104 |
--------------------------------------------------------------------------------
/packages/demo/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
5 | -webkit-font-smoothing: antialiased;
6 | -moz-osx-font-smoothing: grayscale;
7 | }
8 |
9 | code {
10 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
11 | }
12 |
--------------------------------------------------------------------------------
/packages/demo/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/packages/demo/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 | import * as serviceWorker from './serviceWorker';
5 |
6 | import './index.css'
7 |
8 | ReactDOM.render(, document.getElementById('root'));
9 |
10 | // If you want your app to work offline and load faster, you can change
11 | // unregister() to register() below. Note this comes with some pitfalls.
12 | // Learn more about service workers: https://bit.ly/CRA-PWA
13 | serviceWorker.unregister();
14 |
--------------------------------------------------------------------------------
/packages/demo/src/mdx/Grid.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import propTypes from 'prop-types'
3 | import styled from 'styled-components'
4 |
5 | const ActualGrid = styled.div`
6 | display: flex;
7 | justify-content: space-between;
8 | flex-wrap: wrap;
9 |
10 | & > * {
11 | flex: 1 0 200px;
12 | padding: 1rem;
13 | margin-bottom: 0;
14 | padding-bottom: 0;
15 | }
16 |
17 | & img {
18 | width: 100%;
19 | }
20 | `
21 |
22 | export default class Grid extends React.PureComponent {
23 | static propTypes = {
24 | children: propTypes.node.isRequired
25 | }
26 | render() {
27 | const { children } = this.props
28 | return {children}
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/packages/demo/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.1/8 is considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl)
104 | .then(response => {
105 | // Ensure service worker exists, and that we really are getting a JS file.
106 | const contentType = response.headers.get('content-type');
107 | if (
108 | response.status === 404 ||
109 | (contentType != null && contentType.indexOf('javascript') === -1)
110 | ) {
111 | // No service worker found. Probably a different app. Reload the page.
112 | navigator.serviceWorker.ready.then(registration => {
113 | registration.unregister().then(() => {
114 | window.location.reload();
115 | });
116 | });
117 | } else {
118 | // Service worker found. Proceed as normal.
119 | registerValidSW(swUrl, config);
120 | }
121 | })
122 | .catch(() => {
123 | console.log(
124 | 'No internet connection found. App is running in offline mode.'
125 | );
126 | });
127 | }
128 |
129 | export function unregister() {
130 | if ('serviceWorker' in navigator) {
131 | navigator.serviceWorker.ready.then(registration => {
132 | registration.unregister();
133 | });
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/packages/editor/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 |
--------------------------------------------------------------------------------
/packages/editor/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [0.0.5](https://github.com/axe312ger/mdx-live-editor/compare/@mdx-live/editor@0.0.4...@mdx-live/editor@0.0.5) (2019-04-18)
7 |
8 | **Note:** Version bump only for package @mdx-live/editor
9 |
10 |
11 |
12 |
13 |
14 | ## [0.0.2](https://github.com/axe312ger/mdx-live-editor/compare/@mdx-live/editor@0.0.2...@mdx-live/editor@0.0.2) (2019-04-18)
15 |
--------------------------------------------------------------------------------
/packages/editor/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Benedikt Rötsch
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/editor/README.md:
--------------------------------------------------------------------------------
1 | # MDX live editor - editor
2 |
3 | ## Usage
4 |
5 | ```js
6 | import editor from '@mdx-live/editor'
7 | import Grid from './mdx/Grid'
8 |
9 | const config = {
10 | // Your custom MDX components
11 | components: [
12 | {
13 | tagname: 'Grid',
14 | component: Grid,
15 | title: 'Grid',
16 | description: 'Display content next to each other',
17 | icon: 'columns',
18 | demo: `
19 |
20 |
21 |
22 | `
23 | }
24 | ],
25 |
26 | // Overwrite markdown elements
27 | replacements: {
28 | h1: ({ children, ...props }) => (
29 |
30 | {children}
31 |
32 | )
33 | },
34 | easymde: {
35 | // See https://github.com/Ionaru/easy-markdown-editor#configuration for available options
36 | }
37 | }
38 |
39 | const mdxLive = editor(config)
40 | ```
41 |
42 | ## configuration
43 |
44 | By default, the first found `` will be used to inject the editor. See [easyMDE config](#config-easymde) if you want to embed it in a specific one.
45 |
46 | ### `config.components`
47 |
48 | Your custom mdx components. Components configuration structure:
49 |
50 | ```js
51 | {
52 | // JSX tagname for editor embedding
53 | tagname: 'Grid',
54 |
55 | // Actual component to render
56 | component: Grid,
57 |
58 | // Title for toolbar
59 | title: 'Grid',
60 |
61 | // Description for help
62 | description: 'Display content next to each other',
63 |
64 | // Icon for toolbar
65 | icon: 'columns',
66 |
67 | // Demo code snippet for help
68 | demo: `
69 |
70 |
71 |
72 | `
73 | }
74 | ```
75 |
76 | ### `config.replacements`
77 |
78 | Replace default markdown components with your own. Config see [MDX runtime](https://mdxjs.com/advanced/runtime)
79 |
80 | ### `config.easymde`
81 |
82 | Config see [easyMDE](https://github.com/Ionaru/easy-markdown-editor#configuration)
83 |
84 | #### Define textarea to inject the editor
85 |
86 | Pass a reference to your textarea via `config.easymde.element`
87 |
88 | ```html
89 |
90 | ```
91 |
92 | ```js
93 | const textarea = document.getElementById('editor')
94 |
95 | const mdxLive = editor({ easymde: { element: textarea } })
96 | ```
97 |
--------------------------------------------------------------------------------
/packages/editor/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@mdx-live/editor",
3 | "version": "0.0.5",
4 | "description": "Extensible mdx editor with live preview",
5 | "source": "src/index.js",
6 | "main": "dist/index.js",
7 | "unpkg": "dist/index.umd.js",
8 | "scripts": {
9 | "build": "microbundle --jsx React.createElement",
10 | "dev": "microbundle watch --jsx React.createElement"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/axe312ger/mdx-live-editor.git"
15 | },
16 | "keywords": [
17 | "mdx"
18 | ],
19 | "author": "Benedikt Rötsch ",
20 | "license": "MIT",
21 | "bugs": {
22 | "url": "https://github.com/axe312ger/mdx-live-editor/issues"
23 | },
24 | "homepage": "https://github.com/axe312ger/mdx-live-editor#readme",
25 | "dependencies": {
26 | "@axe312/easymde": "^2.7.1",
27 | "@mdx-js/runtime": "^0.20.3",
28 | "react": "^16.8.6",
29 | "react-dom": "^16.8.6"
30 | },
31 | "devDependencies": {
32 | "microbundle": "^0.11.0"
33 | },
34 | "gitHead": "5e4048e47277c2981612b61bc7f2c6b51b0eedb1"
35 | }
36 |
--------------------------------------------------------------------------------
/packages/editor/src/Toolbar.js:
--------------------------------------------------------------------------------
1 | const tagsToReplace = {
2 | '&': '&',
3 | '<': '<',
4 | '>': '>'
5 | }
6 |
7 | function encode(str) {
8 | return str.replace(/[&<>]/g, tag => tagsToReplace[tag] || tag)
9 | }
10 |
11 | export default function toolbar({ toolbar = null, components = [] }) {
12 | const mdxToolbar = components.map(({ title, icon, tagname }) => ({
13 | name: 'custom',
14 | action: function customFunction(editor) {
15 | const selection = editor.codemirror.doc.getSelection()
16 | editor.codemirror.doc.replaceSelection(
17 | `<${tagname}>\n\n${selection}\n\n${tagname}>`
18 | )
19 | },
20 | className: `fa fa-${icon}`,
21 | title
22 | }))
23 | const mdxHelpButton = {
24 | name: 'custom',
25 | action: function customFunction(editor) {
26 | const helpWindow = document.querySelector('.editor-preview-active-side')
27 |
28 | if (!helpWindow) {
29 | return
30 | }
31 | helpWindow.innerHTML = components
32 | .map(
33 | ({ title, description, demo }) =>
34 | `${title}
${description}
${encode(
35 | demo
36 | )}
`
37 | )
38 | .join('
')
39 | },
40 | className: `fa fa-question-circle`,
41 | title: 'Help'
42 | }
43 |
44 | return [
45 | ...(Array.isArray(toolbar)
46 | ? toolbar
47 | : [
48 | 'heading-1',
49 | 'heading-2',
50 | 'heading-3',
51 | '|',
52 | 'bold',
53 | 'italic',
54 | 'link',
55 | 'image',
56 | '|',
57 | 'quote',
58 | 'unordered-list',
59 | 'ordered-list',
60 | '|',
61 | 'preview',
62 | 'side-by-side',
63 | 'fullscreen',
64 | '|'
65 | ]),
66 | ...mdxToolbar,
67 | mdxHelpButton
68 | ]
69 | }
70 |
--------------------------------------------------------------------------------
/packages/editor/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import EasyMDE from '@axe312/easymde'
4 | import { renderToStaticMarkup } from 'react-dom/server'
5 | import MDX from '@mdx-js/runtime'
6 |
7 | import Toolbar from './Toolbar'
8 |
9 | export default function editor({
10 | components = [],
11 | replacements = {},
12 | toolbar = null,
13 | easymde: easymdeConfig = {}
14 | }) {
15 | const scope = components.reduce(
16 | (scope, { tagname, component }) => ({
17 | ...scope,
18 | [tagname]: component
19 | }),
20 | {}
21 | )
22 |
23 | const config = {
24 | ...{
25 | autoDownloadFontAwesome: true,
26 | forceSync: true,
27 | autofocus: true,
28 | indentWithTabs: false,
29 | spellChecker: false
30 | },
31 | ...easymdeConfig
32 | }
33 |
34 | const easymde = new EasyMDE({
35 | ...config,
36 | previewRender: plainText => {
37 | try {
38 | return renderToStaticMarkup(
39 |
40 | {plainText}
41 |
42 | )
43 | } catch (err) {
44 | console.error(err)
45 | return renderToStaticMarkup(
46 |
47 |
{err.name}
48 |
{err.message}
49 |
50 | )
51 | }
52 | },
53 | toolbar: Toolbar({ components, toolbar })
54 | })
55 | easymde.toggleSideBySide()
56 |
57 | return easymde
58 | }
59 |
--------------------------------------------------------------------------------