mirror of
https://github.com/jxnblk/mdx-deck.git
synced 2024-11-26 00:35:02 +03:00
Merge pull request #337 from jxnblk/refactor-modes
Refactor to use hooks
This commit is contained in:
commit
c967aab936
@ -5,6 +5,11 @@
|
||||
- Refactor localStorage to use hooks #334
|
||||
- Refactor keyboard shortcuts #335
|
||||
- Refactor query string to use hooks #336
|
||||
- Refactor to use hooks #337
|
||||
- Adds `MDXDeckState` provider component
|
||||
- Fixes an issue with rerenders in Gatsby theme
|
||||
- Adjusts styles in grid mode
|
||||
- Refactors `useSteps` to use effect hook
|
||||
|
||||
## v2.2.3 2019-04-20
|
||||
|
||||
|
@ -57,8 +57,10 @@ import { Box } from '@rebass/emotion'
|
||||
```
|
||||
|
||||
<Notes>
|
||||
These are speaker notes
|
||||
|
||||
- These are speaker notes
|
||||
- And they won't be rendered in your slide
|
||||
|
||||
</Notes>
|
||||
|
||||
---
|
||||
|
@ -10,6 +10,9 @@
|
||||
"start": "yarn workspace @mdx-deck/docs start",
|
||||
"analyze-bundle": "yarn workspace @mdx-deck/docs start --webpack bundle-analyzer.config.js",
|
||||
"build": "yarn workspace @mdx-deck/docs build",
|
||||
"start-theme": "yarn workspace @mdx-deck/gatsby-theme start",
|
||||
"build-theme": "yarn workspace @mdx-deck/gatsby-theme build",
|
||||
"export": "yarn workspace @mdx-deck/export pdf",
|
||||
"test": "jest"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -21,6 +21,7 @@
|
||||
"devDependencies": {
|
||||
"react": "^16.8.3",
|
||||
"react-dom": "^16.8.3",
|
||||
"react-test-renderer": "^16.8.4"
|
||||
"react-test-renderer": "^16.8.4",
|
||||
"react-testing-library": "^6.1.2"
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,9 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import { Location, navigate } from '@reach/router'
|
||||
import Zoom from './Zoom'
|
||||
import Slide from './Slide'
|
||||
|
||||
const getIndex = ({ pathname }) => {
|
||||
return Number(pathname.split('/')[1] || 0)
|
||||
}
|
||||
|
||||
const withLocation = Component => props => (
|
||||
<Location
|
||||
children={({ location }) => (
|
||||
<Component {...props} location={location} index={getIndex(location)} />
|
||||
)}
|
||||
/>
|
||||
)
|
||||
|
||||
export const Grid = withLocation(props => {
|
||||
const { index, slides, modes, update, basepath } = props
|
||||
export const Grid = props => {
|
||||
const { index, slides, modes, update, goto } = props
|
||||
const activeThumb = React.createRef()
|
||||
|
||||
useEffect(() => {
|
||||
@ -49,18 +36,19 @@ export const Grid = withLocation(props => {
|
||||
key={i}
|
||||
role="link"
|
||||
onClick={e => {
|
||||
navigate(basepath + '/' + i)
|
||||
goto(i)
|
||||
update({ mode: modes.NORMAL })
|
||||
}}
|
||||
style={{
|
||||
display: 'block',
|
||||
width: '25vw',
|
||||
height: '25vh',
|
||||
padding: '2px',
|
||||
width: 'calc(25vw - 4px)',
|
||||
height: 'calc(25vh - 4px)',
|
||||
margin: '2px',
|
||||
overflow: 'hidden',
|
||||
color: 'inherit',
|
||||
textDecoration: 'none',
|
||||
cursor: 'pointer',
|
||||
outline: i === index ? '4px solid #0cf' : null,
|
||||
}}
|
||||
>
|
||||
<Zoom zoom={1 / 4}>
|
||||
@ -73,6 +61,6 @@ export const Grid = withLocation(props => {
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export default Grid
|
||||
|
@ -20,6 +20,7 @@ export const HeadProvider = ({ tags = [], children }) => {
|
||||
|
||||
// get head for all slides
|
||||
export const UserHead = ({ mdx }) =>
|
||||
!!mdx &&
|
||||
React.createElement(mdx, {
|
||||
components: {
|
||||
wrapper: props => {
|
||||
|
@ -69,21 +69,13 @@ const handleKeyDown = props => e => {
|
||||
}
|
||||
}
|
||||
|
||||
export const Keyboard = props => {
|
||||
export default props => {
|
||||
useEffect(() => {
|
||||
const handler = handleKeyDown(props)
|
||||
window.addEventListener('keydown', handler)
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handler)
|
||||
}
|
||||
}, [])
|
||||
}, [props.metadata])
|
||||
return false
|
||||
}
|
||||
|
||||
const noop = () => {}
|
||||
|
||||
Keyboard.defaultProps = {
|
||||
setState: noop,
|
||||
}
|
||||
|
||||
export default Keyboard
|
||||
|
@ -1,8 +1,10 @@
|
||||
import React from 'react'
|
||||
import React, { useContext, useReducer, useMemo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Router, globalHistory, navigate } from '@reach/router'
|
||||
import { Global } from '@emotion/core'
|
||||
import { Swipeable } from 'react-swipeable'
|
||||
import merge from 'lodash.merge'
|
||||
|
||||
import Provider from './Provider'
|
||||
import Slide from './Slide'
|
||||
import Presenter from './Presenter'
|
||||
@ -11,9 +13,10 @@ import Grid from './Grid'
|
||||
import Print from './Print'
|
||||
import GoogleFonts from './GoogleFonts'
|
||||
import Catch from './Catch'
|
||||
import QueryString from './QueryString'
|
||||
import Keyboard from './Keyboard'
|
||||
import Storage from './Storage'
|
||||
import QueryString from './QueryString'
|
||||
import Style from './Style'
|
||||
|
||||
const NORMAL = 'normal'
|
||||
const PRESENTER = 'presenter'
|
||||
@ -30,156 +33,152 @@ const modes = {
|
||||
|
||||
const BaseWrapper = props => <>{props.children}</>
|
||||
|
||||
export class MDXDeck extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
const getIndex = ({ basepath }) => {
|
||||
const { pathname } = globalHistory.location
|
||||
const root = pathname.replace(basepath, '')
|
||||
const n = Number(root.split('/')[1])
|
||||
const index = isNaN(n) ? 0 : n
|
||||
return index
|
||||
}
|
||||
|
||||
this.state = {
|
||||
slides: props.slides,
|
||||
step: 0,
|
||||
mode: NORMAL,
|
||||
update: fn => this.setState(fn),
|
||||
}
|
||||
const mergeState = (state, next) =>
|
||||
merge({}, state, typeof next === 'function' ? next(state) : next)
|
||||
const useState = init => useReducer(mergeState, init)
|
||||
|
||||
const getWrapper = mode => {
|
||||
switch (mode) {
|
||||
case PRESENTER:
|
||||
return Presenter
|
||||
case OVERVIEW:
|
||||
return Overview
|
||||
case GRID:
|
||||
return Grid
|
||||
default:
|
||||
return BaseWrapper
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
export const MDXDeckContext = React.createContext()
|
||||
|
||||
const useDeckState = () => {
|
||||
const context = useContext(MDXDeckContext)
|
||||
if (context) return context
|
||||
|
||||
const [state, setState] = useState({
|
||||
metadata: {},
|
||||
step: 0,
|
||||
mode: NORMAL,
|
||||
})
|
||||
|
||||
return {
|
||||
state,
|
||||
setState,
|
||||
}
|
||||
}
|
||||
|
||||
export const MDXDeckState = ({ children }) => {
|
||||
const context = useDeckState()
|
||||
return <MDXDeckContext.Provider value={context} children={children} />
|
||||
}
|
||||
|
||||
export const MDXDeck = props => {
|
||||
const { slides, basepath } = props
|
||||
const { state, setState } = useDeckState(MDXDeckContext)
|
||||
|
||||
const index = getIndex(props)
|
||||
|
||||
const getMeta = i => {
|
||||
return state.metadata[i] || {}
|
||||
}
|
||||
|
||||
getIndex = () => {
|
||||
const { basepath } = this.props
|
||||
const { pathname } = globalHistory.location
|
||||
const pagepath = pathname.replace(basepath, '')
|
||||
const n = Number(pagepath.split('/')[1])
|
||||
const index = isNaN(n) ? 0 : n
|
||||
return index
|
||||
const register = (index, meta) => {
|
||||
setState({
|
||||
metadata: {
|
||||
...state.metadata,
|
||||
[index]: {
|
||||
...state.metadata[index],
|
||||
...meta,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
getMeta = i => {
|
||||
const { slides } = this.state
|
||||
const { meta = {} } = slides[i] || {}
|
||||
return meta
|
||||
}
|
||||
|
||||
goto = i => {
|
||||
const { basepath } = this.props
|
||||
const current = this.getIndex()
|
||||
const reverse = i < current
|
||||
navigate(basepath + '/' + i)
|
||||
const meta = this.getMeta(i)
|
||||
this.setState({
|
||||
const goto = nextIndex => {
|
||||
const current = getIndex(props)
|
||||
const reverse = nextIndex < current
|
||||
const { search } = globalHistory.location
|
||||
navigate(basepath + '/' + nextIndex + search)
|
||||
const meta = getMeta(nextIndex)
|
||||
setState({
|
||||
step: reverse ? meta.steps || 0 : 0,
|
||||
})
|
||||
}
|
||||
|
||||
previous = () => {
|
||||
const { step } = this.state
|
||||
const index = this.getIndex()
|
||||
const meta = this.getMeta(index)
|
||||
if (meta.steps && step > 0) {
|
||||
this.setState(state => ({
|
||||
step: state.step - 1,
|
||||
}))
|
||||
const previous = () => {
|
||||
const current = getIndex(props)
|
||||
const meta = getMeta(current)
|
||||
if (meta.steps && state.step > 0) {
|
||||
setState({ step: state.step - 1 })
|
||||
} else {
|
||||
const previous = index - 1
|
||||
if (previous < 0) return
|
||||
this.goto(previous)
|
||||
const p = current - 1
|
||||
if (p < 0) return
|
||||
goto(p)
|
||||
}
|
||||
}
|
||||
|
||||
next = () => {
|
||||
const { slides, step } = this.state
|
||||
const index = this.getIndex()
|
||||
const meta = this.getMeta(index)
|
||||
if (meta.steps && step < meta.steps) {
|
||||
this.setState(state => ({
|
||||
step: state.step + 1,
|
||||
}))
|
||||
const next = () => {
|
||||
const current = getIndex(props)
|
||||
const meta = getMeta(current)
|
||||
if (meta.steps && state.step < meta.steps) {
|
||||
setState({ step: state.step + 1 })
|
||||
} else {
|
||||
const next = index + 1
|
||||
if (next > slides.length - 1) return
|
||||
this.goto(next)
|
||||
const n = current + 1
|
||||
if (n > slides.length - 1) return
|
||||
goto(n)
|
||||
}
|
||||
}
|
||||
|
||||
register = (index, meta) => {
|
||||
const { slides } = this.state
|
||||
const initialMeta = slides[index].meta || {}
|
||||
slides[index].meta = { ...initialMeta, ...meta }
|
||||
this.setState({ slides })
|
||||
const context = {
|
||||
...state,
|
||||
update: setState,
|
||||
register,
|
||||
modes,
|
||||
index,
|
||||
goto,
|
||||
previous,
|
||||
next,
|
||||
}
|
||||
|
||||
componentDidCatch(err) {
|
||||
console.error('componentDidCatch')
|
||||
console.error(err)
|
||||
}
|
||||
const [First] = slides
|
||||
const Wrapper = getWrapper(state.mode)
|
||||
|
||||
render() {
|
||||
const { basepath } = this.props
|
||||
const { pathname } = globalHistory.location
|
||||
const { slides } = this.state
|
||||
const pagepath = pathname.replace(basepath, '')
|
||||
const mode = pagepath === '/print' ? PRINT : this.state.mode
|
||||
const index = this.getIndex()
|
||||
const context = {
|
||||
...this.state,
|
||||
register: this.register,
|
||||
modes,
|
||||
previous: this.previous,
|
||||
next: this.next,
|
||||
}
|
||||
|
||||
const [FirstSlide] = slides
|
||||
|
||||
let Wrapper = BaseWrapper
|
||||
switch (mode) {
|
||||
case PRESENTER:
|
||||
Wrapper = Presenter
|
||||
break
|
||||
case OVERVIEW:
|
||||
Wrapper = Overview
|
||||
break
|
||||
case GRID:
|
||||
Wrapper = Grid
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
const style =
|
||||
mode !== modes.PRINT ? (
|
||||
<Global
|
||||
styles={{
|
||||
body: {
|
||||
overflow: 'hidden',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
) : null
|
||||
|
||||
return (
|
||||
<Provider {...this.props} {...this.state} mode={mode} index={index}>
|
||||
{style}
|
||||
<Catch>
|
||||
<QueryString {...this.state} modes={modes} index={index} />
|
||||
<Keyboard {...this.props} {...context} />
|
||||
<Storage {...this.state} goto={this.goto} index={index} />
|
||||
<GoogleFonts />
|
||||
<Wrapper {...this.props} {...this.state} modes={modes} index={index}>
|
||||
<Swipeable onSwipedRight={this.previous} onSwipedLeft={this.next}>
|
||||
<Router basepath={basepath}>
|
||||
<Slide path="/" index={0} context={context}>
|
||||
<FirstSlide path="/" />
|
||||
return (
|
||||
<Provider {...props} {...context}>
|
||||
<Catch>
|
||||
<Style {...context} />
|
||||
<Keyboard {...props} {...context} />
|
||||
<Storage {...context} />
|
||||
<QueryString {...context} />
|
||||
<GoogleFonts />
|
||||
<Wrapper {...props} {...context}>
|
||||
<Swipeable onSwipedRight={previous} onSwipedLeft={next}>
|
||||
<Router basepath={basepath}>
|
||||
<Slide path="/" index={0} context={context}>
|
||||
<First path="/" />
|
||||
</Slide>
|
||||
{slides.map((Component, i) => (
|
||||
<Slide key={i} path={i + '/*'} index={i} context={context}>
|
||||
<Component path={i + '/*'} />
|
||||
</Slide>
|
||||
{slides.map((Component, i) => (
|
||||
<Slide key={i} path={i + '/*'} index={i} {...context}>
|
||||
<Component path={i + '/*'} />
|
||||
</Slide>
|
||||
))}
|
||||
<Print path="print" {...this.props} />
|
||||
</Router>
|
||||
</Swipeable>
|
||||
</Wrapper>
|
||||
</Catch>
|
||||
</Provider>
|
||||
)
|
||||
}
|
||||
))}
|
||||
<Print path="print" {...props} />
|
||||
</Router>
|
||||
</Swipeable>
|
||||
</Wrapper>
|
||||
</Catch>
|
||||
</Provider>
|
||||
)
|
||||
}
|
||||
|
||||
MDXDeck.propTypes = {
|
||||
|
@ -1,25 +1,17 @@
|
||||
import React from 'react'
|
||||
import { withContext } from './context'
|
||||
import React, { useEffect } from 'react'
|
||||
import { useDeck } from './context'
|
||||
|
||||
export const Notes = withContext(
|
||||
class extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
const { context, children } = props
|
||||
if (
|
||||
!context ||
|
||||
typeof context.index === 'undefined' ||
|
||||
typeof context.register !== 'function'
|
||||
) {
|
||||
return
|
||||
}
|
||||
context.register(context.index, { notes: children })
|
||||
}
|
||||
export const Notes = props => {
|
||||
const context = useDeck()
|
||||
useEffect(() => {
|
||||
if (!context || !context.register) return
|
||||
if (typeof context.index === 'undefined') return
|
||||
context.register(context.index, {
|
||||
notes: props.children,
|
||||
})
|
||||
}, [])
|
||||
|
||||
render() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
export default Notes
|
||||
|
@ -1,13 +1,10 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import { navigate } from '@reach/router'
|
||||
import Zoom from './Zoom'
|
||||
import Slide from './Slide'
|
||||
import Pre from './Pre'
|
||||
|
||||
const query = '?mode=overview'
|
||||
|
||||
export const Overview = props => {
|
||||
const { index, slides, basepath } = props
|
||||
const { goto, index, slides } = props
|
||||
const activeThumb = React.createRef()
|
||||
|
||||
useEffect(() => {
|
||||
@ -44,7 +41,7 @@ export const Overview = props => {
|
||||
key={i}
|
||||
role="link"
|
||||
onClick={e => {
|
||||
navigate(basepath + '/' + i + query)
|
||||
goto(i)
|
||||
}}
|
||||
style={{
|
||||
display: 'block',
|
||||
|
@ -6,10 +6,10 @@ import Pre from './Pre'
|
||||
import Clock from './Clock'
|
||||
|
||||
export const Presenter = props => {
|
||||
const { slides, index } = props
|
||||
const { slides, metadata, index } = props
|
||||
const Current = slides[index]
|
||||
const Next = slides[index + 1]
|
||||
const { notes } = Current.meta || {}
|
||||
const { notes } = metadata[index] || {}
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -25,7 +25,7 @@ export default ({ mode, modes, update, index }) => {
|
||||
if (!search) return
|
||||
navigate(pathname)
|
||||
}
|
||||
}, [index, mode])
|
||||
}, [mode])
|
||||
|
||||
return false
|
||||
}
|
||||
|
@ -72,7 +72,6 @@ export const Slide = ({ index, context, ...props }) => (
|
||||
value={{
|
||||
index,
|
||||
...context,
|
||||
...props,
|
||||
}}
|
||||
>
|
||||
<Root {...props} />
|
||||
@ -80,7 +79,9 @@ export const Slide = ({ index, context, ...props }) => (
|
||||
)
|
||||
|
||||
Slide.defaultProps = {
|
||||
step: Infinity,
|
||||
context: {
|
||||
step: Infinity,
|
||||
},
|
||||
}
|
||||
|
||||
export default Slide
|
||||
|
@ -1,21 +1,10 @@
|
||||
import React from 'react'
|
||||
import { withContext } from './context'
|
||||
import { useDeck } from './context'
|
||||
import useSteps from './useSteps'
|
||||
|
||||
export const Steps = withContext(
|
||||
class extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
const { register, index } = props.context
|
||||
const { length } = props
|
||||
if (typeof register !== 'function') return
|
||||
register(index, { steps: length })
|
||||
}
|
||||
render() {
|
||||
const { context, render } = this.props
|
||||
const { step } = context
|
||||
return render({ step })
|
||||
}
|
||||
}
|
||||
)
|
||||
export const Steps = props => {
|
||||
const step = useSteps(props.length)
|
||||
return props.render({ step })
|
||||
}
|
||||
|
||||
export default Steps
|
||||
|
@ -1,15 +1,27 @@
|
||||
import { useEffect } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
const STORAGE_INDEX = 'mdx-slide'
|
||||
const STORAGE_STEP = 'mdx-step'
|
||||
|
||||
export const useLocalStorage = (handler, args = []) => {
|
||||
const [focused, setFocused] = useState(false)
|
||||
const handleFocus = () => {
|
||||
setFocused(true)
|
||||
}
|
||||
const handleBlur = () => {
|
||||
setFocused(false)
|
||||
}
|
||||
useEffect(() => {
|
||||
window.addEventListener('storage', handler)
|
||||
setFocused(document.hasFocus())
|
||||
if (!focused) window.addEventListener('storage', handler)
|
||||
window.addEventListener('focus', handleFocus)
|
||||
window.addEventListener('blur', handleBlur)
|
||||
return () => {
|
||||
window.removeEventListener('storage', handler)
|
||||
if (!focused) window.removeEventListener('storage', handler)
|
||||
window.removeEventListener('focus', handleFocus)
|
||||
window.removeEventListener('blur', handleBlur)
|
||||
}
|
||||
}, [...args])
|
||||
}, [focused, ...args])
|
||||
}
|
||||
|
||||
export const useSetStorage = (key, value) => {
|
||||
|
24
packages/components/src/Style.js
Normal file
24
packages/components/src/Style.js
Normal file
@ -0,0 +1,24 @@
|
||||
import React from 'react'
|
||||
import { globalHistory } from '@reach/router'
|
||||
import { Global } from '@emotion/core'
|
||||
|
||||
const isPrintPath = () => {
|
||||
const { pathname } = globalHistory.location
|
||||
const parts = pathname.split('/')
|
||||
const path = parts[parts.length - 1]
|
||||
return path === 'print'
|
||||
}
|
||||
|
||||
export default ({ mode, modes }) => {
|
||||
if (mode === modes.PRINT) return false
|
||||
if (isPrintPath()) return false
|
||||
return (
|
||||
<Global
|
||||
styles={{
|
||||
body: {
|
||||
overflow: 'hidden',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
35
packages/components/src/__tests__/MDXDeck.js
Normal file
35
packages/components/src/__tests__/MDXDeck.js
Normal file
@ -0,0 +1,35 @@
|
||||
import React, { useContext } from 'react'
|
||||
import { render, cleanup } from 'react-testing-library'
|
||||
import renderer from 'react-test-renderer'
|
||||
import { MDXDeckState, MDXDeckContext, MDXDeck } from '../MDXDeck'
|
||||
|
||||
afterEach(cleanup)
|
||||
|
||||
const slides = [() => <pre>one</pre>, () => <pre>two</pre>]
|
||||
|
||||
describe('MDXDeckState', () => {
|
||||
test('provides state', () => {
|
||||
let context
|
||||
const Consumer = props => {
|
||||
context = useContext(MDXDeckContext)
|
||||
return false
|
||||
}
|
||||
const deck = renderer.create(
|
||||
<MDXDeckState>
|
||||
<Consumer />
|
||||
</MDXDeckState>
|
||||
)
|
||||
expect(typeof context.state).toBe('object')
|
||||
expect(typeof context.state.metadata).toBe('object')
|
||||
expect(context.state.step).toBe(0)
|
||||
expect(context.state.mode).toBe('normal')
|
||||
expect(typeof context.setState).toBe('function')
|
||||
})
|
||||
|
||||
test.todo('setState updates state')
|
||||
})
|
||||
|
||||
test('renders', () => {
|
||||
const json = renderer.create(<MDXDeck slides={slides} />).toJSON()
|
||||
expect(json).toMatchSnapshot()
|
||||
})
|
@ -0,0 +1,33 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders 1`] = `
|
||||
<div>
|
||||
<div
|
||||
role="group"
|
||||
style={
|
||||
Object {
|
||||
"outline": "none",
|
||||
}
|
||||
}
|
||||
tabIndex="-1"
|
||||
>
|
||||
<div
|
||||
className="css-suf238-Root ekm8v3h0"
|
||||
>
|
||||
<div
|
||||
role="group"
|
||||
style={
|
||||
Object {
|
||||
"outline": "none",
|
||||
}
|
||||
}
|
||||
tabIndex="-1"
|
||||
>
|
||||
<pre>
|
||||
one
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
@ -1,11 +1,11 @@
|
||||
// slide context
|
||||
import React, { useContext } from 'react'
|
||||
|
||||
export const Context = React.createContext({})
|
||||
|
||||
export const withContext = Component => props => (
|
||||
<Context.Consumer
|
||||
children={context => <Component {...props} context={context} />}
|
||||
/>
|
||||
)
|
||||
|
||||
export const useDeck = () => useContext(Context)
|
||||
|
||||
export const withContext = Component => props => {
|
||||
const context = useDeck()
|
||||
return <Component {...props} context={context} />
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
export { MDXDeck } from './MDXDeck'
|
||||
export { MDXDeck, MDXDeckState } from './MDXDeck'
|
||||
export { Head } from './Head'
|
||||
export { Image } from './Image'
|
||||
export { Notes } from './Notes'
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { useContext, useMemo } from 'react'
|
||||
import { useContext, useEffect } from 'react'
|
||||
import { Context } from './context'
|
||||
|
||||
export default length => {
|
||||
const context = useContext(Context)
|
||||
const { register, index, step } = context
|
||||
useMemo(() => {
|
||||
useEffect(() => {
|
||||
if (typeof register !== 'function') return
|
||||
register(index, { steps: length })
|
||||
}, [length])
|
||||
|
@ -23,7 +23,8 @@ module.exports = async opts => {
|
||||
|
||||
switch (type) {
|
||||
case 'pdf':
|
||||
await page.goto(`http://localhost:${port}/print`, {
|
||||
const url = `http://localhost:${port}/print`
|
||||
await page.goto(url, {
|
||||
waitUntil: 'networkidle2',
|
||||
})
|
||||
await page.pdf({
|
||||
|
@ -8,8 +8,8 @@
|
||||
"mdx-deck-export": "./cli.js"
|
||||
},
|
||||
"scripts": {
|
||||
"pdf": "./cli.js pdf ../../docs/demo.mdx",
|
||||
"png": "./cli.js png ../../docs/demo.mdx"
|
||||
"pdf": "./cli.js pdf ../../docs/demo.mdx -d ../../docs/dist",
|
||||
"png": "./cli.js png ../../docs/demo.mdx -d ../../docs/dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"mdx-deck": "^2.2.3",
|
||||
|
1
packages/gatsby-theme/gatsby-browser.js
Normal file
1
packages/gatsby-theme/gatsby-browser.js
Normal file
@ -0,0 +1 @@
|
||||
export { wrapPageElement } from './src'
|
@ -1 +1,6 @@
|
||||
export default {}
|
||||
import React from 'react'
|
||||
import { MDXDeckState } from '@mdx-deck/components'
|
||||
|
||||
export const wrapPageElement = ({ props, element }) => (
|
||||
<MDXDeckState key={props.pageContext.basepath}>{element}</MDXDeckState>
|
||||
)
|
||||
|
@ -1,22 +1,17 @@
|
||||
import React from 'react'
|
||||
import { MDXProvider } from '@mdx-js/react'
|
||||
import { MDXDeck, splitSlides } from '@mdx-deck/components'
|
||||
import Root from './root'
|
||||
|
||||
const wrapper = page => props => (
|
||||
<MDXDeck
|
||||
{...splitSlides({ ...props })}
|
||||
basepath={page.pageContext.basepath}
|
||||
/>
|
||||
)
|
||||
const wrapper = props => <MDXDeck {...splitSlides({ ...props })} />
|
||||
|
||||
export default props => {
|
||||
const components = {
|
||||
wrapper: wrapper(props),
|
||||
}
|
||||
const components = {
|
||||
wrapper,
|
||||
}
|
||||
|
||||
export default ({ Component, ...props }) => {
|
||||
return (
|
||||
<Root>
|
||||
<MDXProvider components={components}>{props.children}</MDXProvider>
|
||||
<Component {...props} components={components} />
|
||||
</Root>
|
||||
)
|
||||
}
|
||||
|
@ -5,8 +5,9 @@ import Layout from '../layouts/deck'
|
||||
|
||||
export default props => {
|
||||
const { mdx } = props.data
|
||||
const children = <MDXRenderer children={mdx.code.body} />
|
||||
return <Layout {...props} children={children} />
|
||||
const Component = props => <MDXRenderer {...props} children={mdx.code.body} />
|
||||
|
||||
return <Layout Component={Component} basepath={props.pageContext.basepath} />
|
||||
}
|
||||
|
||||
export const query = graphql`
|
||||
|
32
yarn.lock
32
yarn.lock
@ -747,7 +747,7 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.12.0"
|
||||
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.2":
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.2":
|
||||
version "7.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.3.tgz#79888e452034223ad9609187a0ad1fe0d2ad4bdc"
|
||||
integrity sha512-9lsJwJLxDh/T3Q3SZszfWOTkk3pHbkmH+3KY+zwIDmsNlxsumuhS2TH3NIpktU4kNvfzy+k3eLT7aTJSPTo0OA==
|
||||
@ -1823,6 +1823,11 @@
|
||||
dependencies:
|
||||
any-observable "^0.3.0"
|
||||
|
||||
"@sheerun/mutationobserver-shim@^0.3.2":
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.2.tgz#8013f2af54a2b7d735f71560ff360d3a8176a87b"
|
||||
integrity sha512-vTCdPp/T/Q3oSqwHmZ5Kpa9oI7iLtGl3RQaA/NyLHikvcrPxACkkKVr/XzkSPJWXHRhKGzVvb0urJsbMlRxi1Q==
|
||||
|
||||
"@stefanprobst/lokijs@^1.5.6-b":
|
||||
version "1.5.6-b"
|
||||
resolved "https://registry.yarnpkg.com/@stefanprobst/lokijs/-/lokijs-1.5.6-b.tgz#6a36a86dbe132e702e6b15ffd3ce4139aebfe942"
|
||||
@ -5002,6 +5007,16 @@ dom-serializer@0, dom-serializer@~0.1.0:
|
||||
domelementtype "^1.3.0"
|
||||
entities "^1.1.1"
|
||||
|
||||
dom-testing-library@^3.19.0:
|
||||
version "3.19.3"
|
||||
resolved "https://registry.yarnpkg.com/dom-testing-library/-/dom-testing-library-3.19.3.tgz#fba399987be1bdd57b07c4bc3ef46c3c084b26d9"
|
||||
integrity sha512-oiI+oq91iO/Vpp+pt8PqfqLfBK074FH0eprhoFNvBCvJOk7vL4ozbe/yj/kEEGR6kiT4F3MAam19AX1fdGFjrA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.4"
|
||||
"@sheerun/mutationobserver-shim" "^0.3.2"
|
||||
pretty-format "^24.5.0"
|
||||
wait-for-expect "^1.1.0"
|
||||
|
||||
dom-walk@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018"
|
||||
@ -11470,7 +11485,7 @@ pretty-error@^2.1.1:
|
||||
renderkid "^2.0.1"
|
||||
utila "~0.4"
|
||||
|
||||
pretty-format@^24.7.0:
|
||||
pretty-format@^24.5.0, pretty-format@^24.7.0:
|
||||
version "24.7.0"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.7.0.tgz#d23106bc2edcd776079c2daa5da02bcb12ed0c10"
|
||||
integrity sha512-apen5cjf/U4dj7tHetpC7UEFCvtAgnNZnBDkfPv3fokzIqyOJckAG9OlAPC1BlFALnqT/lGB2tl9EJjlK6eCsA==
|
||||
@ -11901,6 +11916,14 @@ react-test-renderer@^16.8.4:
|
||||
react-is "^16.8.6"
|
||||
scheduler "^0.13.6"
|
||||
|
||||
react-testing-library@^6.1.2:
|
||||
version "6.1.2"
|
||||
resolved "https://registry.yarnpkg.com/react-testing-library/-/react-testing-library-6.1.2.tgz#f6bba6eeecedac736eb00b22b4c70bae04535a4f"
|
||||
integrity sha512-z69lhRDGe7u/NOjDCeFRoe1cB5ckJ4656n0tj/Fdcr6OoBUu7q9DBw0ftR7v5i3GRpdSWelnvl+feZFOyXyxwg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.4.2"
|
||||
dom-testing-library "^3.19.0"
|
||||
|
||||
react@^16.8.3, react@^16.8.6:
|
||||
version "16.8.6"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe"
|
||||
@ -14432,6 +14455,11 @@ w3c-hr-time@^1.0.1:
|
||||
dependencies:
|
||||
browser-process-hrtime "^0.1.2"
|
||||
|
||||
wait-for-expect@^1.1.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/wait-for-expect/-/wait-for-expect-1.1.1.tgz#9cd10e07d52810af9e0aaf509872e38f3c3d81ae"
|
||||
integrity sha512-vd9JOqqEcBbCDhARWhW85ecjaEcfBLuXgVBqatfS3iw6oU4kzAcs+sCNjF+TC9YHPImCW7ypsuQc+htscIAQCw==
|
||||
|
||||
walker@^1.0.7, walker@~1.0.5:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"
|
||||
|
Loading…
Reference in New Issue
Block a user