Create a component definition, which will be loaded in both the parent and child windows.
A tag-name for the component, used for:
- Loading the correct component in the child window or frame
- Generating framework drivers
- Logging
tag: 'my-component-tag'
The full url that will be loaded when your component is rendered, or a function returning the url.
This must include a protocol (http:, https:, or about:); it cannot be scheme-relative.
url: 'https://www.my-site.com/mycomponent'
url: ({ props }) => {
return (props.env === 'development')
? 'http://dev.my-site.com/mycomponent'
: 'https://www.my-site.com/mycomponent';
}
The dimensions for your component, in css-style units, with support for px
or %
.
dimensions: {
width: '300px',
height: '200px'
}
dimensions: {
width: '80%',
height: '90%'
}
A mapping of prop name to prop settings. Used to do run-time validation and prop normalization.
props: {
onLogin: {
type: 'function'
},
prefilledEmail: {
type: 'string',
required: false
}
}
-
type
string
The data-type expected for the prop
'string'
'number'
'boolean'
'object'
'function'
'array'
-
required
boolean
Whether or not the prop is mandatory. Defaults to
true
.onLogin: { type: 'function', required: false }
-
default
({ props }) => value
A function returning the default value for the prop, if none is passed
email: { type: 'string', required: false, default: function() { return 'a@b.com'; } }
-
validate
({ value, props }) => void
A function to validate the passed value. Should throw an appropriate error if invalid.
email: { type: 'string', validate: function({ value, props }) { if (!value.match(/^.+@.+\..+$/)) { throw new TypeError(`Expected email to be valid format`); } } }
-
queryParam
boolean | string | (value) => string
Should a prop be passed in the url.
email: { type: 'string', queryParam: true // ?email=foo@bar.com }
If a string is set, this specifies the url param name which will be used.
email: { type: 'string', queryParam: 'user-email' // ?user-email=foo@bar.com }
If a function is set, this is called to determine the url param which should be used.
email: { type: 'string', queryParam: function({ value }) { if (value.indexOf('@foo.com') !== -1) { return 'foo-email'; // ?foo-email=person@foo.com } else { return 'generic-email'; // ?generic-email=person@whatever.com } } }
-
value
({ props }) => value
The value for the prop, if it should be statically defined at component creation time
userAgent: { type: 'string', value() { return window.navigator.userAgent; } }
-
decorate
({ value, props }) => value
A function used to decorate the prop at render-time. Called with the value of the prop, should return the new value.
onLogin: { type: 'function', decorate(original) { return function() { console.log('User logged in!'); return original.apply(this, arguments); }; } }
-
serialization
string
If
json
, the prop will be JSON stringified before being inserted into the urluser: { type: 'object', serialization: 'json' // ?user={"name":"Zippy","age":34} }
If
dotify
the prop will be converted to dot-notation.user: { type: 'object', serialization: 'dotify' // ?user.name=Zippy&user.age=34 }
If
base64
, the prop will be JSON stringified then base64 encoded before being inserted into the urluser: { type: 'object', serialization: 'base64' // ?user=eyJuYW1lIjoiWmlwcHkiLCJhZ2UiOjM0fQ== }
-
alias
string
An aliased name for the prop
onLogin: { type: 'function', alias: 'onUserLogin' }
A function which should return a DOM element, rendered on the parent page and containing the iframe element (or rendered behind the popup window).
zoid will pass opts.frame
and opts.prerenderFrame
to this function, which is a pre-generated element your component will be rendered into. These must be inserted somewhere into the DOM element you return, for frame-based components
The opts
parameter is the same as the parameter used in prerenderTemplate
Best used with jsx-pragmatic. You can use babel with a /* @jsx node */
comment, to transpile the jsx down to regular javascript.
/* @jsx node */
import { node, dom } from 'jsx-pragmatic';
var MyLoginZoidComponent = zoid.create({
tag: 'my-login',
url: 'https://www.mysite.com/login',
containerTemplate: function({ uid, doc, frame, prerenderFrame }) {
return (
<div id={ uid } class="container">
<style>
{`
#${ uid }.container {
border: 5px solid red;
}
`}
</style>
<node el={ frame } />
<node el={ prerenderFrame } />
</div>
).render(dom({ doc }));
}
});
As with React, you are also free to skip using JSX and just use node
from jsx-pragmatic
directly:
import { node, dom } from 'jsx-pragmatic';
var MyLoginZoidComponent = zoid.create({
tag: 'my-login',
url: 'https://www.mysite.com/login',
containerTemplate: function containerTemplate({ uid, doc, frame, prerenderFrame }) {
return node('div', { id: uid, class: 'container' },
node('style', null, `
#${ uid }.container {
border: 5px solid red;
}
`),
node('node', { el: frame }),
node('node', { el: prerenderFrame })
).render(dom({ doc }));
}
});
Since containerTemplate
requires a DOM element to be returned, you're also free to manually create the element hierarchy using built-in browser methods like doc.createElement
:
import { node, dom } from 'jsx-pragmatic';
var MyLoginZoidComponent = zoid.create({
tag: 'my-login',
url: 'https://www.mysite.com/login',
containerTemplate: function containerTemplate({ doc, uid, frame, prerenderFrame }) {
let container = doc.createElement('div');
container.id = uid;
container.appendChild(frame);
container.appendChild(prerenderFrame);
return container;
}
});
If no containerTemplate
function is defined, then a default is used. The default template can be found here.
A function which should return a DOM element, rendered in place of the iframe element, or inside the popup window, as it loads.
Useful if you want to display a loading spinner or pre-render some content as the component loads.
Best used with jsx-pragmatic. You can use babel with a /* @jsx node */
comment, to transpile the jsx down to regular javascript.
/* @jsx node */
import { node, dom } from 'jsx-pragmatic';
var MyLoginZoidComponent = zoid.create({
tag: 'my-login',
url: 'https://www.mysite.com/login',
prerenderTemplate: function({ doc }) {
return (
<p>
Please wait while the component loads...
</p>
).render(dom({ doc }));
}
});
As with React, you are also free to skip using JSX and just use node
directly:
import { node, dom } from 'jsx-pragmatic';
var MyLoginZoidComponent = zoid.create({
tag: 'my-login',
url: 'https://www.mysite.com/login',
prerenderTemplate: function containerTemplate({ doc }) {
return node('p', null, `
Please wait while the component loads...
`).render(dom({ doc }));
}
});
Since prerenderTemplate
only requires a DOM element, you're also free to manually create the element hierarchy using built-in browser methods like doc.createElement
.
Note: if you're using document
method, you must use the doc
passed to prerenderTemplate
, so the element is created using the target document of the new iframe or popup window, not the document of the parent page. This is essential for browser compatibility.
import { node, dom } from 'jsx-pragmatic';
var MyLoginZoidComponent = zoid.create({
tag: 'my-login',
url: 'https://www.mysite.com/login',
prerenderTemplate: function containerTemplate({ doc }) {
const p = doc.createElement('p');
p.innerText = 'Please wait while the component loads...';
return p;
}
});
Data automatically passed to containerTemplate
and prerenderTemplate
, used to help render and customize the template.
uid
: Unique id automatically generated by zoid on render, unique to the instantiation of the given componentprops
: Props passed to the component inrender()
doc
: The appropriate document used to render dom elementscontainer
: The element into which the generated element will be inserteddimensions
: The dimensions for the componenttag
: Tag name of the componentcontext
: Context type of the component (iframe
orpopup
)frame
: Frame element that will be rendered into. Only applies tocontainerTemplate
when rendering an iframeprerenderFrame
: Frame element that will be pre-rendered into. Only applies tocontainerTemplate
when rendering an iframe usingprerenderTemplate
close
: Close the component. Useful if you want to render a close button outside the componentfocus
: Focus the component. Valid for popup components only. Useful if you want a clickable background overlay to re-focus the popup window.event
: Object that can be used to listen for the following events:RENDER
,RENDERED
,DISPLAY
,ERROR
,CLOSED
,PROPS
,RESIZE
In the containerTemplate
and prerenderFunctions
, it is possible to attach functions that fire at events in the zoid lifecycle:
event.on(EVENT.RENDERED, () => {
prerenderFrame.classList.remove(CLASS.VISIBLE);
prerenderFrame.classList.add(CLASS.INVISIBLE);
frame.classList.remove(CLASS.INVISIBLE);
frame.classList.add(CLASS.VISIBLE);
setTimeout(() => {
destroyElement(prerenderFrame);
}, 1);
});
Makes the iframe resize automatically when the child window size changes.
autoResize: {
width: false,
height: true,
}
Note that by default it matches the body
element of your content.
You can override this setting by specifying a custom selector as an element
property.
autoResize: {
width: false,
height: true,
element: '.my-selector',
}
Recommended to only use autoResize for height. Width has some strange effects, especially when scroll bars are present.
A string, array of strings or reqular expresions to be used to validate parent domain. If parent domain doesn't match any item, communication from child to parent will be prevented. The default value is '*' which match any domain.
allowedParentDomains: [
"http://localhost",
/^http:\/\/www\.mydomain\.com$/
]
A string, or map of env to strings, for the domain which will be loaded in the iframe or popup.
Only required if the domain which will be rendered is different to the domain specified in the url
setting - for example, if the original url does a 302 redirect to a different domain or subdomain.
url: 'https://foo.com/login',
domain: 'https://subdomain.foo.com'
Determines which should be picked by default when render()
is called. Defaults to iframe
.
defaultContext: 'popup'
Function which is passed all of the props at once and may validate them. Useful for validating inter-dependant props.
validate: function({ props }) {
if (props.name === 'Batman' && props.strength < 10) {
throw new Error(`Batman must have at least 10 strength`);
}
}
The url or a function returning the url for a post-robot bridge. Will be automatically loaded in a hidden iframe when a popup component is rendered, to allow communication between the parent window and the popup in IE/Edge.
This is only necessary if you are creating a popup component which needs to run in IE and/or Edge.
bridgeUrl: 'https://foo.com/bridge'
bridgeUrl: ({ props }) => {
return (props.env === 'development')
? 'http://foo.dev/bridge'
: 'https://foo.com/bridge';
}
Render the component to the given container element.
Object containing all of the props required by the given component
Element selector, or element, into which the component should be rendered.
Defaults to document.body
.
The context to render to. Defaults to defaultContext
, or if defaultContext
is not set, iframe
.
Equivalent to Component().render()
but allows rendering to a remote window. For example, a child component may render a new component to the parent page.
- The component must have been registered on the target window
- The component must be rendered from within the iframe of an existing component
- The component being rendered must have the same domain as the component initiating the render
The target window to which the component should be rendered. Ordinarily this will be window.parent
.
Object containing all of the props required by the given component
Element selector, or element, into which the component should be rendered.
Defaults to document.body
.
The context to render to. Defaults to defaultContext
, or if defaultContext
is not set, iframe
.
Register a component with your framework of choice, so it can be rendered natively in your app.
let MyReactZoidComponent = MyZoidComponent.driver('react', {
React: React,
ReactDOM: ReactDOM
});
render() {
return (
<MyReactZoidComponent foo="bar" />
);
}
MyZoidComponent.driver('angular', angular);`
<my-zoid foo="bar">
@ng.core.NgModule({
imports: [
ng.platformBrowser.BrowserModule,
MyZoidComponent.driver('angular2', ng.core)
]
});
<my-zoid [props]="{ foo: 'bar' }"></my-zoid>
import Component from '@glimmer/component';
export default MyZoidComponent.driver('glimmer', Component);
<my-zoid @foo={{bar}}></my-zoid>
Vue.component('app', {
components: {
'my-zoid': MyZoidComponent.driver('vue')
}
}
<my-zoid :foo="bar" />