├── src ├── index.ts ├── types.ts └── components │ ├── live-editor.tsx │ └── live-code.tsx ├── .markdownlintrc ├── netlify.toml ├── .vscode ├── settings.json └── extensions.json ├── .prettierrc ├── example ├── theme.js ├── README.md ├── package.json ├── external-file.js └── deck.mdx ├── tslint.json ├── tsconfig.json ├── .circleci └── config.yml ├── package.json ├── .gitignore ├── LICENSE.md └── README.md /src/index.ts: -------------------------------------------------------------------------------- 1 | export { LiveCode } from './components/live-code'; 2 | -------------------------------------------------------------------------------- /.markdownlintrc: -------------------------------------------------------------------------------- 1 | { 2 | "default": true, 3 | "line_length": false 4 | } -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | base = "example/" 3 | command = "yarn build" 4 | publish = "example/dist/" -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib", 3 | "editor.tabSize": 2 4 | } 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "semi": true, 4 | "useTabs": true, 5 | "trailingComma": "all" 6 | } 7 | -------------------------------------------------------------------------------- /example/theme.js: -------------------------------------------------------------------------------- 1 | import { yellow as theme } from 'mdx-deck/themes'; 2 | 3 | export default { 4 | ...theme, 5 | }; 6 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint-react", "tslint-config-prettier"], 3 | "linterOptions": { 4 | "exclude": ["node_modules/**/*.ts"] 5 | }, 6 | "rules": { 7 | "interface-name": false, 8 | "member-access": [false], 9 | "ordered-imports": [false], 10 | "no-console": [true], 11 | "no-var-requires": true, 12 | "jsx-boolean-value": false 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Type helpers 3 | */ 4 | export type Omit = Pick>; 5 | // OmitRef is used to fix weird TypeScript errors surrounding the 'ref' prop ¯\_(ツ)_/¯ 6 | export type OmitRef = Pick>; 7 | 8 | export type GetComponentProps = T extends 9 | | React.ComponentType 10 | | React.Component 11 | ? P 12 | : never; 13 | //usage: GetComponentProps 14 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. 3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 4 | 5 | // List of extensions which should be recommended for users of this workspace. 6 | "recommendations": [ 7 | "eg2.tslint", 8 | "esbenp.prettier-vscode", 9 | "silvenon.mdx", 10 | "wix.vscode-import-cost", 11 | "formulahendry.auto-rename-tag", 12 | "vector-of-bool.gitflow" 13 | ], 14 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace. 15 | "unwantedRecommendations": [] 16 | } 17 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # mdx-deck basic template 2 | 3 | This was generated with [mdx-deck][]'s `npm init deck` command. 4 | 5 | ## Development 6 | 7 | To run the presentation deck in development mode: 8 | 9 | ```sh 10 | npm start 11 | ``` 12 | 13 | Edit the [`deck.mdx`](deck.mdx) file to get started. 14 | 15 | ## Exporting 16 | 17 | To build the presentation deck as static HTML: 18 | 19 | ```sh 20 | npm run build 21 | ``` 22 | 23 | To export a PDF: 24 | 25 | ```sh 26 | npm run pdf 27 | ``` 28 | 29 | To export an image of the title slide: 30 | 31 | ```sh 32 | npm run image 33 | ``` 34 | 35 | For more documentation see the [mdx-deck][] repo. 36 | 37 | [mdx-deck]: https://github.com/jxnblk/mdx-deck 38 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mdx-deck-live-code-example", 3 | "version": "1.0.0", 4 | "description": "An example of using the mdx-deck-live-code module in an mdx-deck", 5 | "scripts": { 6 | "start": "mdx-deck deck.mdx", 7 | "build": "mdx-deck build deck.mdx", 8 | "pdf": "mdx-deck pdf deck.mdx", 9 | "image": "mdx-deck screenshot deck.mdx", 10 | "help": "mdx-deck" 11 | }, 12 | "dependencies": { 13 | "mdx-deck-live-code": "^0.1.0" 14 | }, 15 | "devDependencies": { 16 | "mdx-deck": "^1.8.2", 17 | "raw-loader": "^1.0.0" 18 | }, 19 | "author": "Jeppe Reinhold (https://reinhold.is)", 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/JReinhold/mdx-deck-live-code.git" 23 | }, 24 | "license": "NoHarm-draft", 25 | "private": false 26 | } 27 | -------------------------------------------------------------------------------- /example/external-file.js: -------------------------------------------------------------------------------- 1 |
2 | You can reference external files as code, instead of defining the code inline. 3 |
    4 |
  1. 5 | Install the raw-loader package 6 |
  2. 7 |
      8 |
    • 9 | npm install raw-loader 10 |
    • 11 |
    12 |
  3. 13 | Use the raw-loader in the LiveCode component 14 |
  4. 15 |
  5. 16 | Example: 17 |
    18 | 				{``}
    23 | 			
    24 |
  6. 25 |
  7. 26 | BONUS 27 |
      28 |
    • This also makes formatting with Prettier easier
    • 29 |
    • 30 | ... and makes it possible to have empty lines in the code, which 31 | usually is not possible when writing the code inline 32 |
    • 33 |
    34 |
  8. 35 |
36 |
; 37 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */, 4 | "module": "es6" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, 5 | "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, 6 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, 7 | "jsx": "react" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */, 8 | 9 | "declaration": true /* Generates corresponding '.d.ts' file. */, 10 | "declarationMap": true /* Generates a sourcemap for each corresponding '.d.ts' file. */, 11 | "sourceMap": true /* Generates corresponding '.map' file. */, 12 | "outDir": "./dist" /* Redirect output structure to the directory. */, 13 | 14 | "strict": true /* Enable all strict type-checking options. */, 15 | "noUnusedLocals": true /* Report errors on unused locals. */, 16 | "skipLibCheck": true // don't typecheck libraries, silences a weird type error in react-live 17 | }, 18 | "include": ["src/**/*"], 19 | "exclude": ["node_modules"] 20 | } 21 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | docker: 5 | - image: circleci/node:10 6 | working_directory: ~/repo 7 | steps: 8 | - checkout 9 | 10 | # Install and cache yarn dependencies 11 | - restore_cache: 12 | keys: 13 | - dependencies-{{ checksum "yarn.lock" }} 14 | # fallback to using the latest cache if no exact match is found 15 | - dependencies- 16 | - run: 17 | name: Install Depencendies 18 | command: | 19 | yarn install 20 | - save_cache: 21 | paths: 22 | - node_modules 23 | key: dependencies-{{ checksum "yarn.lock" }} 24 | 25 | # Following steps are the same as "yarn ok" in pacakge.json 26 | - run: 27 | name: Typecheck 28 | command: | 29 | yarn typecheck 30 | - run: 31 | name: Lint 32 | command: | 33 | yarn lint 34 | - run: 35 | name: Check Format 36 | command: | 37 | yarn format:ci 38 | 39 | - restore_cache: 40 | keys: 41 | - build-caches 42 | - run: 43 | name: Build Source 44 | command: | 45 | yarn build 46 | - save_cache: 47 | paths: 48 | - .rts2_cache_cjs 49 | - .rts2_cache_es 50 | - .rts2_cache_umd 51 | key: build-caches 52 | 53 | # Install and cache yarn dependencies for the example project 54 | - restore_cache: 55 | keys: 56 | - example-dependencies-{{ checksum "example/yarn.lock" }} 57 | # fallback to using the latest cache if no exact match is found 58 | - example-dependencies- 59 | - run: 60 | name: 'Example: Install Depencendies' 61 | working_directory: ./example 62 | command: | 63 | yarn install 64 | - save_cache: 65 | paths: 66 | - example/node_modules 67 | key: example-dependencies-{{ checksum "example/yarn.lock" }} 68 | 69 | - run: 70 | name: 'Example: Build' 71 | working_directory: ./example 72 | command: | 73 | yarn build 74 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mdx-deck-live-code", 3 | "version": "1.0.1", 4 | "main": "dist/index.js", 5 | "umd:main": "dist/index.umd.js", 6 | "module": "dist/index.es.js", 7 | "source": "src/index.ts", 8 | "types": "dist/index.d.ts", 9 | "files": [ 10 | "./dist" 11 | ], 12 | "scripts": { 13 | "dev": "microbundle watch", 14 | "build": "microbundle build", 15 | "example": "cd example && npm start", 16 | "start": "npm-run-all --parallel dev example", 17 | "setup-dev": "yarn install && yarn link && cd example && yarn install && yarn link mdx-deck-live-code", 18 | "format": "prettier --write '{src/**/*.{ts,tsx},README.md}'", 19 | "format:ci": "prettier --list-different '{src/**/*.{ts,tsx},README.md}'", 20 | "lint": "npm-run-all --parallel lint:**", 21 | "lint:src": "tslint --project tsconfig.json --config tslint.json", 22 | "lint:readme": "markdownlint README.md", 23 | "typecheck": "tsc --noEmit", 24 | "ok": "yarn typecheck && yarn lint && yarn format:ci && yarn build", 25 | "prepublishOnly": "yarn ok" 26 | }, 27 | "dependencies": { 28 | "react-live": "^1.11.0" 29 | }, 30 | "devDependencies": { 31 | "@types/react": "^16.4.16", 32 | "@types/styled-components": "^4.0.1", 33 | "husky": "^1.1.1", 34 | "markdownlint-cli": "^0.13.0", 35 | "microbundle": "^0.9.0", 36 | "npm-run-all": "^4.1.3", 37 | "prettier": "^1.14.3", 38 | "pretty-quick": "^1.7.0", 39 | "styled-components": "^4.1.3", 40 | "tslint": "^5.11.0", 41 | "tslint-config-prettier": "^1.15.0", 42 | "tslint-react": "^3.6.0", 43 | "typescript": "^3.1.1" 44 | }, 45 | "peerDependencies": { 46 | "mdx-deck": "^1.7.7", 47 | "react": ">=15.0.0", 48 | "styled-components": ">=3.0.0" 49 | }, 50 | "husky": { 51 | "hooks": { 52 | "pre-commit": "pretty-quick --staged" 53 | } 54 | }, 55 | "author": "Jeppe Reinhold (https://reinhold.is)", 56 | "homepage": "https://github.com/JReinhold/mdx-deck-live-code#readme", 57 | "repository": { 58 | "type": "git", 59 | "url": "https://github.com/JReinhold/mdx-deck-live-code.git" 60 | }, 61 | "bugs": { 62 | "url": "https://github.com/JReinhold/mdx-deck-live-code/issues" 63 | }, 64 | "license": "NoHarm-draft", 65 | "description": "A component for mdx-deck for live coding directly in your slides. 🤯", 66 | "keywords": [ 67 | "mdx", 68 | "mdx-deck", 69 | "slides", 70 | "react", 71 | "reactjs", 72 | "code", 73 | "live", 74 | "edit", 75 | "playground" 76 | ] 77 | } 78 | -------------------------------------------------------------------------------- /src/components/live-editor.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | LiveEditor as BaseLiveEditor, 4 | LiveEditorProps as BaseLiveEditorProps, 5 | } from 'react-live'; 6 | import styled from 'styled-components'; 7 | 8 | const isMacLike = 9 | typeof window !== 'undefined' && 10 | 'navigator' in window && 11 | /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform); 12 | 13 | interface LiveEditorState { 14 | focusEditor: boolean; 15 | } 16 | export interface LiveEditorProps extends BaseLiveEditorProps {} 17 | /** 18 | * A wrapper around the default LiveEditor from react-live 19 | * Fixes focus state problems where mdx-deck and react-live don't get along 20 | * maybe not needed when this PR is merged: 21 | * https://github.com/FormidableLabs/react-live/pull/77 22 | * 23 | * Passes all valid params down to the LiveEditor from react-live 24 | */ 25 | export class LiveEditor extends React.PureComponent< 26 | LiveEditorProps, 27 | LiveEditorState 28 | > { 29 | state = { focusEditor: true }; 30 | 31 | focusEditor = () => { 32 | this.setState({ focusEditor: true }); 33 | }; 34 | blurEditor = () => { 35 | this.setState({ focusEditor: false }); 36 | }; 37 | 38 | /** 39 | * remove focus from editor when user presses one of: 40 | * - Escape 41 | * - CTRL + M (Windows and Linux) 42 | * - CTRL + SHIFT + M (Mac) 43 | * Mimicks Monaco edtor: 44 | * https://github.com/Microsoft/monaco-editor/wiki/Monaco-Editor-Accessibility-Guide#tab-trapping 45 | */ 46 | blurOnKeyCombo: React.KeyboardEventHandler = event => { 47 | if ( 48 | event.key === 'Escape' || 49 | (event.key === 'M' && 50 | event.ctrlKey && 51 | (isMacLike ? event.shiftKey : true)) 52 | ) { 53 | this.blurEditor(); 54 | } 55 | }; 56 | 57 | render() { 58 | const { focusEditor } = this.state; 59 | const { className, ...props } = this.props; 60 | 61 | return ( 62 |
69 | 70 |
71 | ); 72 | } 73 | } 74 | 75 | // add extra spacing at the bottom to make sure errors don't obscure code 76 | const StyledBaseLiveEditor = styled(BaseLiveEditor)` 77 | height: 100%; 78 | max-height: 100vh; 79 | overflow: auto; 80 | font-size: 0.7em; 81 | width: 100%; 82 | padding-bottom: 5rem !important; 83 | ${props => props.theme.liveCode && props.theme.liveCode.editor}; 84 | `; 85 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ---------------- 2 | # Project specific ignores 3 | # ---------------- 4 | 5 | # build results 6 | dist 7 | # microbundle chaches 8 | .rts2_cache_* 9 | 10 | # ---------------- 11 | # Generated by gitignore.io 12 | # ---------------- 13 | 14 | # Created by https://www.gitignore.io/api/node,macos,windows,visualstudiocode 15 | 16 | ### macOS ### 17 | # General 18 | .DS_Store 19 | .AppleDouble 20 | .LSOverride 21 | 22 | # Icon must end with two \r 23 | Icon 24 | 25 | # Thumbnails 26 | ._* 27 | 28 | # Files that might appear in the root of a volume 29 | .DocumentRevisions-V100 30 | .fseventsd 31 | .Spotlight-V100 32 | .TemporaryItems 33 | .Trashes 34 | .VolumeIcon.icns 35 | .com.apple.timemachine.donotpresent 36 | 37 | # Directories potentially created on remote AFP share 38 | .AppleDB 39 | .AppleDesktop 40 | Network Trash Folder 41 | Temporary Items 42 | .apdisk 43 | 44 | ### Node ### 45 | # Logs 46 | logs 47 | *.log 48 | npm-debug.log* 49 | yarn-debug.log* 50 | yarn-error.log* 51 | 52 | # Runtime data 53 | pids 54 | *.pid 55 | *.seed 56 | *.pid.lock 57 | 58 | # Directory for instrumented libs generated by jscoverage/JSCover 59 | lib-cov 60 | 61 | # Coverage directory used by tools like istanbul 62 | coverage 63 | 64 | # nyc test coverage 65 | .nyc_output 66 | 67 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 68 | .grunt 69 | 70 | # Bower dependency directory (https://bower.io/) 71 | bower_components 72 | 73 | # node-waf configuration 74 | .lock-wscript 75 | 76 | # Compiled binary addons (https://nodejs.org/api/addons.html) 77 | build/Release 78 | 79 | # Dependency directories 80 | node_modules/ 81 | jspm_packages/ 82 | 83 | # TypeScript v1 declaration files 84 | typings/ 85 | 86 | # Optional npm cache directory 87 | .npm 88 | 89 | # Optional eslint cache 90 | .eslintcache 91 | 92 | # Optional REPL history 93 | .node_repl_history 94 | 95 | # Output of 'npm pack' 96 | *.tgz 97 | 98 | # Yarn Integrity file 99 | .yarn-integrity 100 | 101 | # dotenv environment variables file 102 | .env 103 | 104 | # parcel-bundler cache (https://parceljs.org/) 105 | .cache 106 | 107 | # next.js build output 108 | .next 109 | 110 | # nuxt.js build output 111 | .nuxt 112 | 113 | # vuepress build output 114 | .vuepress/dist 115 | 116 | # Serverless directories 117 | .serverless 118 | 119 | ### VisualStudioCode ### 120 | .vscode/* 121 | !.vscode/settings.json 122 | !.vscode/tasks.json 123 | !.vscode/launch.json 124 | !.vscode/extensions.json 125 | 126 | ### Windows ### 127 | # Windows thumbnail cache files 128 | Thumbs.db 129 | ehthumbs.db 130 | ehthumbs_vista.db 131 | 132 | # Dump file 133 | *.stackdump 134 | 135 | # Folder config file 136 | [Dd]esktop.ini 137 | 138 | # Recycle Bin used on file shares 139 | $RECYCLE.BIN/ 140 | 141 | # Windows Installer files 142 | *.cab 143 | *.msi 144 | *.msix 145 | *.msm 146 | *.msp 147 | 148 | # Windows shortcuts 149 | *.lnk 150 | 151 | 152 | # End of https://www.gitignore.io/api/node,macos,windows,visualstudiocode -------------------------------------------------------------------------------- /src/components/live-code.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | LiveProvider, 4 | LiveError, 5 | LiveProviderProps, 6 | LivePreview, 7 | } from 'react-live'; 8 | import styled, { withTheme } from 'styled-components'; 9 | import { LiveEditor, LiveEditorProps } from './live-editor'; 10 | import { OmitRef } from '../types'; 11 | 12 | interface Props { 13 | code?: string; 14 | title?: string; 15 | size?: Size; 16 | errors?: boolean; 17 | providerProps?: OmitRef; 18 | editorProps?: OmitRef; 19 | previewProps?: OmitRef>; 20 | errorProps?: OmitRef>; 21 | } 22 | type Size = 'small' | 'medium' | 'large' | 'fullscreen'; 23 | 24 | /** 25 | * A high level component to quickly add live coding abilities 26 | */ 27 | const LiveCodeBase: React.SFC = ({ 28 | code, 29 | size = 'medium', 30 | errors = true, 31 | providerProps, 32 | title, 33 | editorProps, 34 | previewProps, 35 | errorProps, 36 | }) => { 37 | return ( 38 | 39 | 40 | {title && !(size === 'fullscreen') &&

{title}

} 41 | 42 | 43 | 44 | {errors && } 45 | 46 |
47 |
48 | ); 49 | }; 50 | 51 | export const LiveCode = withTheme(LiveCodeBase); 52 | 53 | const LiveDeck = styled.div<{ size: Size }>` 54 | display: flex; 55 | flex-direction: column; 56 | justify-content: center; 57 | align-items: center; 58 | padding: ${({ size }) => (size === 'fullscreen' ? '0' : '1em')}; 59 | ${({ size }) => { 60 | switch (size) { 61 | case 'small': 62 | return 'width: 60vw; height: 70vh'; 63 | case 'medium': 64 | return 'width: 80vw; height: 90vh'; 65 | case 'large': 66 | case 'fullscreen': 67 | return 'width: 100vw; height: 100vh;'; 68 | } 69 | }}; 70 | `; 71 | 72 | // prettier-ignore 73 | const LiveContainer = styled.div<{ size: Size }>` 74 | width: 100%; 75 | height: 100%; 76 | display: flex; 77 | position: relative; 78 | 79 | ${({size}) => size !== 'fullscreen' && 80 | `box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.5); 81 | border-radius: 0.25rem;` 82 | } 83 | ${props => props.theme.liveCode && props.theme.liveCode.container} 84 | `; 85 | 86 | const StyledLivePreview = styled(LivePreview)` 87 | width: 50%; 88 | background: white; 89 | ${props => props.theme.liveCode && props.theme.liveCode.preview}; 90 | `; 91 | 92 | const StyledLiveEditor = styled(LiveEditor)` 93 | width: 50%; 94 | ${props => props.theme.liveCode && props.theme.liveCode.editor}; 95 | `; 96 | 97 | const StyledLiveError = styled(LiveError)` 98 | position: absolute; 99 | bottom: 0; 100 | width: 100%; 101 | padding: 0.125em; 102 | background: #280000; 103 | border: 2px solid #5c0000; 104 | color #ff8080; 105 | font-family: monospace; 106 | font-size: 0.75em; 107 | height: 5rem; 108 | overflow-y: auto; 109 | resize: vertical; 110 | ${props => props.theme.liveCode && props.theme.liveCode.error} 111 | `; 112 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Do No Harm License 2 | 3 | **Preamble** 4 | 5 | Most software today is developed with little to no thought of how it will be used, or the consequences for our society and planet. 6 | 7 | As software developers, we engineer the infrastructure of the 21st century. We recognise that our infrastructure has great power to shape the world and the lives of those we share it with, and we choose to consciously take responsibility for the social and environmental impacts of what we build. 8 | 9 | We envisage a world free from injustice, inequality, and the reckless destruction of lives and our planet. We reject slavery in all its forms, whether by force, indebtedness, or by algorithms that hack human vulnerabilities. We seek a world where humankind is at peace with our neighbours, nature, and ourselves. We want our work to enrich the physical, mental and spiritual wellbeing of all society. 10 | 11 | We build software to further this vision of a just world, or at the very least, to not put that vision further from reach. 12 | 13 | **Terms** 14 | 15 | _Copyright_ (c) _(year)_ _(owner)_. All rights reserved. 16 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 17 | 18 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 19 | 20 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 21 | 22 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 23 | 24 | 4. This software must not be used by any organisation, website, product or service that: 25 | 26 | a) lobbies for, promotes, or derives a majority of income from actions that support or contribute to: 27 | 28 | - sex trafficking 29 | - human trafficking 30 | - slavery 31 | - indentured servitude 32 | - gambling 33 | - tobacco 34 | - adversely addictive behaviours 35 | - nuclear energy 36 | - warfare 37 | - weapons manufacturing 38 | - war crimes 39 | - violence (except when required to protect public safety) 40 | - burning of forests 41 | - deforestation 42 | - hate speech or discrimination based on age, gender, gender identity, race, sexuality, religion, nationality 43 | 44 | b) lobbies against, or derives a majority of income from actions that discourage or frustrate: 45 | 46 | - peace 47 | - access to the rights set out in the Universal Declaration of Human Rights and the Convention on the Rights of the Child 48 | - peaceful assembly and association (including worker associations) 49 | - a safe environment or action to curtail the use of fossil fuels or prevent climate change 50 | - democratic processes 51 | 52 | 5. All redistribution of source code or binary form, including any modifications must be under these terms. You must inform recipients that the code is governed by these conditions, and how they can obtain a copy of this license. You may not attempt to alter the conditions of who may/may not use this software. 53 | 54 | We define: 55 | 56 | **Forests** to be 0.5 or more hectares of trees that were either planted more than 50 years ago or were not planted by humans or human made equipment. 57 | 58 | **Deforestation** to be the clearing, burning or destruction of 0.5 or more hectares of forests within a 1 year period. 59 | 60 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 61 | 62 | **Attribution** 63 | 64 | Do No Harm License [Contributor Covenant][homepage], (pre 1.0), 65 | available at https://github.com/raisely/NoHarm 66 | 67 | [homepage]: https://github.com/raisely/NoHarm 68 | -------------------------------------------------------------------------------- /example/deck.mdx: -------------------------------------------------------------------------------- 1 | import { Head } from 'mdx-deck'; 2 | export { default as theme } from './theme'; 3 | import { LiveCode } from 'mdx-deck-live-code'; 4 | 5 | 6 | mdx-deck-live-code demo 7 | 8 | 9 | # [mdx-deck-live-code](https://github.com/jreinhold/mdx-deck-live-code) Demonstration 🤯 10 | 11 | Live code JSX and Javascript with previews, directly in your slides 12 | 13 | --- 14 | 15 | 19 | 20 | --- 21 | 22 | 27 | 28 | --- 29 | 30 | 35 | 36 | --- 37 | 38 | 43 | 44 | --- 45 | 46 | 47 | 48 | --- 49 | 50 | You can style your {""} 53 | individually per slide, 54 | targeting each element directly: 55 |
{\`\`}
69 | `} 70 | size="large" 71 | previewProps={{ 72 | style: { textAlign: 'left', padding: '0.5em', fontSize: '0.7em' }, 73 | }} 74 | editorProps={{ style: { fontSize: '0.5em', background: '#001628' } }} 75 | /> 76 | 77 | --- 78 | 79 | Or you can use the global mdx-deck theme: 81 |
{\`export default {
 82 |   ...theme,
 83 |   liveCode: {
 84 |     container: {
 85 |       // container styles
 86 |     },
 87 |     editor: {
 88 |       // editor styles
 89 |     },
 90 |     preview: {
 91 |       // preview styles
 92 |     },
 93 |     error: {
 94 |       // error styles
 95 |     }
 96 |   }
 97 | };\`}
98 | `} 99 | size="fullscreen" 100 | previewProps={{ 101 | style: { textAlign: 'left', padding: '0.5em', fontSize: '0.7em' }, 102 | }} 103 | editorProps={{ style: { fontSize: '0.5em' } }} 104 | /> 105 | 106 | --- 107 | 108 | 112 |

While in the editor, use either one of the key combos

113 |
    114 |
  • 115 | ESC 116 |
  • 117 |
  • 118 | CTRL + M (Windows and Linux) 119 |
  • 120 |
  • 121 | CTRL + SHIFT + M (Mac) 122 |
  • 123 |
124 | To unfocus the editor, and navigate the deck again 125 | `} 126 | size="large" 127 | previewProps={{ 128 | style: { textAlign: 'left', padding: '0.5em', fontSize: '0.7em' }, 129 | }} 130 | editorProps={{ style: { fontSize: '0.5em', background: '#001628' } }} 131 | /> 132 | 133 | --- 134 | 135 | { 138 | const componentType = "Functional Component"; 139 | return (

Hi, I'm a {componentType}!

) 140 | }`} 141 | editorProps={{ style: { fontSize: '0.5em', background: '#001628' } }} 142 | /> 143 | 144 | --- 145 | 146 | 157 |

158 | This is a {this.state.value} component! 159 |

160 | this.setState({value: e.target.value}) 163 | } 164 | value={this.state.value} 165 | /> 166 | 167 | ); 168 | } 169 | }`} 170 | size="large" 171 | editorProps={{ style: { fontSize: '0.5em', background: '#001628' } }} 172 | /> 173 | 174 | --- 175 | 176 | ( 181 |

182 | {sayWhaaat} {toWhooo} 183 |

184 | ); 185 | render(GreetDaPeeps);`} 186 | providerProps={{ noInline: true }} 187 | editorProps={{ style: { fontSize: '0.5em', background: '#001628' } }} 188 | /> 189 | 190 | --- 191 | 192 | 198 | 199 | --- 200 | 201 | # 🙋‍♀️ 202 | 203 | ### See more at the [mdx-deck-live-code repository](https://github.com/jreinhold/mdx-deck-live-code) 204 | 205 | By [@DrReinhold](https://twitter.com/drreinhold) 206 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mdx-deck-live-code 🤯 [reinhold.is/live-coding-in-slides](https://reinhold.is/live-coding-in-slides) 2 | 3 | 4 | 5 | A component for [mdx-deck](https://github.com/jxnblk/mdx-deck) for live coding directly in your slides. 🤯 6 | 7 | ![Build Status](https://img.shields.io/circleci/project/github/JReinhold/mdx-deck-live-code/master.svg?style=flat-square) 8 | [![Version](https://img.shields.io/npm/v/mdx-deck-live-code.svg?style=flat-square)](https://www.npmjs.com/package/mdx-deck-live-code) 9 | ![Dependency Status](https://img.shields.io/librariesio/github/jreinhold/mdx-deck-live-code.svg?style=flat-square) 10 | 11 | ```bash 12 | npm install --save-dev mdx-deck-live-code 13 | ``` 14 | 15 | - ⚛️ Live edit and render React components or other JavaScript directly in slides - **no window switching necessary** 16 | - ↕️ Supports 17 | [different](https://reinhold.is/live-coding-in-slides/#2) 18 | [sizes](https://reinhold.is/live-coding-in-slides/#3) 19 | [out of](https://reinhold.is/live-coding-in-slides/#4) 20 | [the box](https://reinhold.is/live-coding-in-slides/#5) 21 | - 🖼 Start live edits with a blank canvas - or with some code pre-filled 22 | - 🎨 Fully supports custom styles - either [directly on the individual components](https://reinhold.is/live-coding-in-slides/#6) or [using the global theme](https://reinhold.is/live-coding-in-slides/#7) 23 | - 👏 ... and [everything else](https://reinhold.is/live-coding-in-slides/#11) [react-live](https://github.com/FormidableLabs/react-live) does! 24 | 25 | > Follow [@DrReinhold](https://twitter.com/DrReinhold) for updates 26 | 27 | ⚠️ This library is ONLY intended to work with your [mdx-deck](https://github.com/jxnblk/mdx-deck) slides. It doesn't magically add live coding abilities to your PowerPoint or Keynote slides, even though that would be pretty slick. 28 | 29 | ## [🎭 Check out a live demo here](https://reinhold.is/live-coding-in-slides) 30 | 31 | The code for demo is located in the [`/example`](/example) directory. 32 | 33 | ## 🐣 Getting started 34 | 35 | Import the `LiveCode` component at the top of your `deck.mdx` file (or in a slide if you're only using it once). 36 | 37 | ```js 38 | import { LiveCode } from 'mdx-deck-live-code'; 39 | ``` 40 | 41 | Use the `` component as a top-level component in a slide 42 | 43 | ```jsx 44 | --- 45 | 50 | --- 51 | ``` 52 | 53 | ## 🐓 Usage 54 | 55 | The `` is intended to be used as its own slide. 56 | It supports the following props: 57 | 58 | | Prop | Type | Default | Description | 59 | | ------------- | ------------------------------------------------------ | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | 60 | | `code` | string | | The initial code that is pre-filled in the editor and preview. See [Importing code from external files](#-importing-code-from-external-files) on advanced usage. | 61 | | `title` | string | | Title of the slide, shown in the top. Is not shown if `size` is set to `fullscreen` | 62 | | `size` | `'small'` \| `'medium'` \| `'large'` \| `'fullscreen'` | `'medium'` | The size of the live code component, relative to the viewport size. | 63 | | errors | boolean | `true` | Whether the error panel at the bottom should be shown or not on parse errors | 64 | | providerProps | object | | Any additional props to pass to the [`` component](https://github.com/FormidableLabs/react-live#liveprovider-) | 65 | | editorProps | object | | Any additional props to pass to the [`` component](https://github.com/FormidableLabs/react-live#liveeditor-) | 66 | | previewProps | object | | Any additional props to pass to the [`` component](https://github.com/FormidableLabs/react-live#livepreview-) | 67 | | errorProps | object | | Any additional props to pass to the [`` component](https://github.com/FormidableLabs/react-live#liveerror-) | 68 | 69 | Under the hood this `` uses [react-live](https://github.com/FormidableLabs/react-live), So if you want to get super fancy, take a look at the [react-live API](https://github.com/FormidableLabs/react-live#api). 70 | 71 | See the [example `deck.mdx`](/example/deck.mdx) for examples on using the different features. 72 | 73 | ### ⤴ Importing code from external files 74 | 75 | Your `deck.mdx` file can become quite a mess if you intend to have large chunks of code in your `code` props. Luckily the `raw-loader` library is supported out-of-the-box, so you can declare the code in external files, instead of writing it as an inline string. 76 | 77 | To do that, first install the raw-loader package. 78 | 79 | ```bash 80 | npm install --save-dev raw-loader 81 | ``` 82 | 83 | Then, in the `code` prop, reference another file using the `require('!raw-loader!PATH-TO-FILE')`-syntax. 84 | 85 | ```jsx 86 | 87 | ``` 88 | 89 | ## ⚠️ Current issues 90 | 91 | - Editing the code currently doesn't sync between the presenter and observer instances. Therefore **you need to edit the code in the observer window, if you want your audience to see it**❗️❗️❗️ 92 | - The carret often becomes invisible, if it is moved outside the non-scrolled area. Still investigating, help wanted. 93 | 94 | ## 🙏 Related / Credits 95 | 96 | - [mdx-deck](https://github.com/jxnblk/mdx-deck) by the incredible [Brent Jackson](https://jxnblk.com/) 97 | - [react-live](https://github.com/FormidableLabs/react-live) which this library uses internally, by the astonishing [Formidable Labs](https://formidable.com/) 98 | - [CodeSurfer](https://github.com/pomber/code-surfer) (React component for scrolling, zooming and highlighting _static_ code) which inspired this library, by the fantastic [Rodrigo Pombo](https://twitter.com/pomber) 99 | - [mdx-code](https://github.com/pranaygp/mdx-code) - (Similar to this library it delivers a JS playground using RunKit), by the marvelous [Pranay Prakash](https://twitter.com/pranaygp) 100 | - [Component Playground in Spectacle](https://github.com/FormidableLabs/spectacle#component-playground) which is similar to this library, but for [slides built with Spectacle](https://github.com/FormidableLabs/spectacle) instead of mdx-deck slides. Also by the astonishing [Formidable Labs](https://formidable.com/) 101 | 102 | ## 🤝 Contributing 103 | 104 | Ideas and feedback are ALWAYS welcome, just submit an issue. 105 | Pull Requests are also very welcome, but **please always make PRs into the `next` branch** 106 | 107 | The library is built using [TypeScript](https://www.typescriptlang.org), bundled with [Microbundle](https://github.com/developit/microbundle), formatted with [Prettier](https://prettier.io/), linted with [TSLint](https://palantir.github.io/tslint/) and [markdownlint](https://github.com/DavidAnson/markdownlint), packaged with [yarn](https://yarnpkg.com), hosted on [Netlify](https://www.netlify.com/) and developed with love ❤️ and sweat 💦. 108 | 109 | 1. `yarn dev` starts the TypeScript building of the library. 110 | 2. `yarn example` starts the demo in the `example/` folder. 111 | 3. I recommend that you use the example to test your changes, as that contains all the relevant use cases of the library. To do that, run `yarn setup-dev`, which takes care of installing and linking the necessary dependencies. 112 | 4. Then run `yarn start` to start the development transpiler and the example in watch mode concurrently. 113 | 5. Submit awesome PRs. 114 | 115 | ## 📝 License 116 | 117 | Released under the [Do No Harm License (draft)](https://github.com/raisely/NoHarm) 118 | 119 | By [@DrReinhold](https://twitter.com/DrReinhold) 120 | --------------------------------------------------------------------------------