@walltowall/mainframe
v0.2.1
Published
A component for rendering dynamically resizeable React component in an iFrame.
Downloads
3
Readme
mainframe
Features
- Specify the width of your framed component to view it at specific breakpoints.
- Scales rendered frame via
transform
to appropariately size the rendered component in relation to its parent container and desired width. - Copies and syncs any parent
<head>
tags to the rendered<iframe>
to ensure parity between parent and container.
Installation
# Yarn
yarn add @walltowall/mainframe
# NPM
npm i @walltowall/mainframe --save
Usage
import { Mainframe } from 'mainframe'
const Example = () => {
return (
<Mainframe>
<div>Hello World!</div>
</Mainframe>
)
}
API
<Mainframe>
exposes a set of props to customize the rendering behavior of the
framed component.
targetWidth
The desired width to render your framed component at. Accepts any valid CSS unit
such as px
, rem
, %
, etc. targetWidth
is useful for triggering a
component's styles at specific breakpoints.
Dynamic scaling
<Mainframe>
will dynamically transform: scale()
itself based on the
specified targetWidth
in relation to its "expected width". For example, if
<Mainframe>
would have normally rendered at 800px
but targetWidth
is set
to 400px
, then the it will be given a transform: scale(2)
property as a
result. This scaling also applies for situations where targetWidth
is greater
than it's expected render width, resulting in a scale()
< 1.
By default, targetWidth
is set to 100%
.
To granularly control how this scaling is applied, please refer to the maxScale and minScale props.
<Mainframe targetWidth="360px">
<div>I'll be styled like a mobile device!</div>
</Mainframe>
wrappers
React component to wrap any framed components. Use this prop if your framed
components rely on any providers from redux
, the context api, etc.
const Provider = ({ children }) => <Provider>{children}</Provider>
// Provide a component directly:
<Mainframe wrappers={Provider}>
<div>I'm wrapped!</div>
</Mainframe>
// Or inline a function:
<Mainframe wrappers={({ children }) => <Provider>{children}</Provider>}>
<div>I'm wrapped!</div>
</Mainframe>
// Alternatively, just wrap your children:
<Mainframe wrappers={Provider}>
<Provider>
<div>I'm wrapped!</div>
</Provider>
</Mainframe>
minScale
Specify a minimum transform: scale()
value that <Mainframe>
must be greater
than.
For example, if minScale
is set to 0.5
, the underlying iFrame will never
have a scale value less than transform: scale(0.5)
.
⚠️ Overflows
Using the
minScale
prop with a largetargetWidth
is likely to cause your framed content to extend outside of its bounding container. Use with caution or alternatively use theconstrainToContainer
prop instead.
<Mainframe targetWidth="1600px" minScale={0.5}>
<div>I will always be more than scale .5!</div>
</Mainframe>
maxScale
Specify a maximum transform: scale()
value that <Mainframe>
must be less
than.
For example, if maxScale
is set to 2
, the underlying iFrame will never have
a scale value more than transform: scale(2)
.
<Mainframe targetWidth="320px" maxScale={2}>
<div>I will always be less than scale 2!</div>
</Mainframe>
constrainToContainer
If set to true
, the <Mainframe>
will be constrained to the height
and
width
of its immediate parent. Scaling will still be appropriately applied
based on targetWidth
and the container's size.
The rendered iFrame will also be centered horizontally and vertically inside of its container as needed.
<Mainframe targetWidth="320px" constrainToContainer={true}>
<div>I will adhere to my container's height and width!</div>
</Mainframe>
injectHead
React components/tags to inject into the <iframe>
's <head>
.
// Parent head:
<head>
<title>Parent</title>
</head>
<Mainframe
postHead={
<>
<title>Inject Head</title>
</>
}
>
<div>Inserted after!</div>
</Mainframe>
// Resulting <iFrame> <head>:
<head>
<title>Parent</title>
<title>Inject Head</title>
</head>
setHeadFn
Function to enable stateful access to the <head>
element of the rendered
iFrame. This is especially useful handy if children inside of <Mainframe>
are
styled-components
.
import { StyleSheetManager } from 'styled-components'
const Example = () => {
const [head, setHead] = useState()
return (
<Mainframe setHeadFn={setHead}>
{head && (
<StyleSheetManager target={head}>
<StyledComponent>I will have the correct styles!</StyledComponent>
</StyleSheetManager>
)}
</Mainframe>
)
}
src
If specified, the <Mainframe>
will attempt to display the content at the
provided URL like a plain <iframe>
. If you specify src
, you cannot
specify children
.
<Mainframe src="https://www.google.com" />
// Specifying children with src will throw:
<Mainframe src="https://www.google.com">
<div>This will error!</div>
</Mainframe>
onFrameLoad
Callback function that is fired when the rendered iframe fires its onload
callback.
<Mainframe onFrameLoad={() => console.log('Loaded!')} />
iFrameProps
Arbitrary props that are spread onto the underlying <iframe>
.
⚠️
style
propOverriding the
style
prop on the underlying<iframe>
will break the dynamic resizing functionality. If you need to add additional styles to the iFrame, useiFrameStyles
instead.
iFrameStyles
Arbitrary styles that are spread onto the iFrame's style
prop. Note that
overriding width
or height
here will likely break scaling functionality.
Gotchas
This package is reliant on the ResizeObserver
api to work properly.
By default, it includes a ponyfill via 'resize-observer-polyfill' to support older browsers.
License
MIT.