Skip to content

Commit

Permalink
feat!: Migrate to wrapPageElement Gatsby API
Browse files Browse the repository at this point in the history
* Rewrite `ReplaceComponentRenderer` to functional component

BREAKING CHANGE: Removes support for `replaceComponentRenderer` API from Gatsby v2.
  • Loading branch information
decanTyme committed Apr 9, 2022
1 parent f3af8fe commit 59f163a
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 155 deletions.
6 changes: 2 additions & 4 deletions gatsby-browser.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
const {
default: replaceComponentRenderer,
} = require('./dist/replaceComponentRenderer')
const { default: wrapPageElement } = require('./dist/PageElementWrapper')
const { default: shouldUpdateScroll } = require('./dist/shouldUpdateScroll')
const { default: onClientEntry } = require('./dist/onClientEntry')

exports.onClientEntry = onClientEntry
exports.replaceComponentRenderer = replaceComponentRenderer
exports.wrapPageElement = wrapPageElement
exports.shouldUpdateScroll = shouldUpdateScroll
6 changes: 2 additions & 4 deletions src/ModalRoutingContext.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import React from 'react'

export const defaultValue = {
const ModalRoutingContext = React.createContext({
isModal: false,
closeTo: null,
}

const ModalRoutingContext = React.createContext(defaultValue)
})

export default ModalRoutingContext
133 changes: 133 additions & 0 deletions src/PageElementWrapper.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { navigate } from 'gatsby'
import React from 'react'
import Modal from 'react-modal'
import ModalRoutingContext from './ModalRoutingContext'

const withoutPrefix = (path) => {
const prefix =
typeof __BASE_PATH__ !== `undefined` ? __BASE_PATH__ : __PATH_PREFIX__

return path.slice(prefix ? prefix.length : 0)
}

const element = {}

function PageElementWrapper({ props, opts }) {
const modalContentRef = React.useRef(null)
const [state, setState] = React.useState({
prevProps: null,
lastModalProps: null,
props: null,
pathname: null,
})

const handleRequestClose = () => {
navigate(withoutPrefix(state.prevProps.location.pathname), {
state: {
noScroll: true,
},
})
}

React.useEffect(() => {
if (
state.prevProps?.location.pathname !== props.location.pathname &&
props.location.state.modal &&
modalContentRef.current
) {
modalContentRef.current.scrollTop = 0
}
})

if (state.pathname !== props?.location.pathname) {
setState({
pathname: props?.location.pathname,
props,
...(state.props?.location.state.modal
? {
// Old page was a modal, keep track so we
// can render the contents while closing
lastModalProps: state.props,
}
: {
// Old page was not a modal, keep track so
// we can render the contents under modals
prevProps: state.props,
}),
})
}

const isModal = state.prevProps && props.location.state.modal

const resources = isModal
? state.prevProps.pageResources
: props.pageResources

// The page is the previous path if this is a modal,
// otherwise it's the current path
element.page = React.createElement(resources.component, {
...(isModal ? state.prevProps : props),
key: resources.page.path,
})

if (isModal) {
// Rendering the current page as a modal,
// so create an element with the page contents
element.modal = React.createElement(props.pageResources.component, {
...props,
key: props?.pageResources.page.path,
})
} else if (state.lastModalProps) {
// Not rendering the current page as a modal, but we may
// be in the process of animating the old modal content
// to close, so render the last modal content we have cached
element.modal = React.createElement(
state.lastModalProps.pageResources.component,
{
...state.lastModalProps,
key: state.lastModalProps.pageResources.page.path,
}
)
}

const modalValues = React.useMemo(
() => ({
modal: isModal,
closeTo: state.prevProps
? withoutPrefix(state.prevProps.location.pathname)
: '/',
}),
[isModal, state.prevProps]
)

return (
<>
{element.page}

<Modal
onRequestClose={handleRequestClose}
contentRef={(node) => {
modalContentRef.current = node
}}
{...opts?.modalProps}
isOpen={Boolean(isModal)}
>
{element.modal ? (
<React.Fragment key={props?.location.key}>
<ModalRoutingContext.Provider value={modalValues}>
{element.modal}
</ModalRoutingContext.Provider>
</React.Fragment>
) : null}
</Modal>
</>
)
}

const wrapPageElement = (context, opts) =>
React.createElement(PageElementWrapper, {
...context,
opts,
})

export default wrapPageElement
2 changes: 1 addition & 1 deletion src/onClientEntry.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Modal from 'react-modal'

const onClientEntry = (_args, opts = {}) => {
const onClientEntry = (_, opts) => {
const { appElement = `#___gatsby` } = opts
Modal.setAppElement(appElement)
}
Expand Down
146 changes: 0 additions & 146 deletions src/replaceComponentRenderer.js

This file was deleted.

0 comments on commit 59f163a

Please sign in to comment.