Skip to content

Commit

Permalink
Initial documentation pass
Browse files Browse the repository at this point in the history
  • Loading branch information
lemonmade committed Nov 14, 2023
1 parent e74d8df commit 8e1fad4
Show file tree
Hide file tree
Showing 9 changed files with 1,099 additions and 3,017 deletions.
5 changes: 5 additions & 0 deletions .changeset/slow-geese-reflect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@remote-dom/core': patch
---

Add `root` option to `DOMRemoteReceiver`
229 changes: 198 additions & 31 deletions README.md

Large diffs are not rendered by default.

Empty file.
62 changes: 62 additions & 0 deletions examples/minimal-iframes/app/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<!DOCTYPE html>
<html>
<body>
<div id="root"></div>

<iframe id="remote-iframe" src="/remote.html" hidden></iframe>

<script type="module">
class UIBanner extends HTMLElement {
connectedCallback() {
// We will allow you to pass a `tone` attribute to the element, which
// styles the banner according to our design system. We’ll see how to
// use this in the remote environment in the next step.
const tone = this.getAttribute('tone') ?? this.tone ?? 'neutral';

const root = this.attachShadow({mode: 'open'});

// We render a <slot> where we want the element’s children to go.
root.innerHTML = `
<style>
.Banner {
padding: 1rem;
border-radius: 0.4rem;
background-color: lightgray;
border: 1px solid gray;
}
.Banner--warning {
background-color: #fff6de;
border-color: #f5dab1;
}
</style>
<div class="Banner Banner--${tone}"><slot></slot></div>
`;
}
}

customElements.define('ui-banner', UIBanner);
</script>

<script type="module">
import {DOMRemoteReceiver} from '@remote-dom/core/receiver';

const root = document.querySelector('#root');
const iframe = document.querySelector('#remote-iframe');

// In earlier examples, we did not pass any arguments, which allows the DOM
// receiver to mirror any element it receives. By passing the `elements` option,
// we are restricting the allowed elements to only the ones we list, which in this
// case means only our `ui-banner` element can be rendered.
const receiver = new DOMRemoteReceiver({
elements: ['ui-banner'],
});
receiver.connect(root);

window.addEventListener('message', ({source, data}) => {
if (source !== iframe.contentWindow) return;
receiver.receive(data);
});
</script>
</body>
</html>
54 changes: 54 additions & 0 deletions examples/minimal-iframes/app/remote.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<!DOCTYPE html>
<html>
<body>
<div id="root">
<ui-banner>This page was rendered 0 seconds ago.</ui-banner>
</div>

<script type="module">
import {RemoteElement} from '@remote-dom/core/elements';

class UIBanner extends RemoteElement {
// For full details on defining remote elements, see the documentation
// for `@remote-dom/core/elements`:
// https://github.com/Shopify/remote-ui/tree/main/packages/core/
static get remoteProperties() {
return {
tone: {type: String},
};
}
}

customElements.define('ui-banner', UIBanner);
</script>

<script type="module">
import {RemoteMutationObserver} from '@remote-dom/core/elements';

const root = document.querySelector('#root');
const banner = root.querySelector('ui-banner');
const initialContent = banner.textContent;

let count = 0;

setInterval(() => {
count += 1;

banner.textContent = initialContent.replace(
'0 seconds',
`${count} second${count === 1 ? '' : 's'}`,
);

if (count === 10) {
banner.setAttribute('tone', 'warning');
}
}, 1000);

const observer = new RemoteMutationObserver((mutations) => {
window.parent.postMessage(mutations, '*');
});

observer.observe(root);
</script>
</body>
</html>
11 changes: 11 additions & 0 deletions examples/minimal-iframes/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "example-minimal-iframes",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "vite"
},
"dependencies": {
"@remote-dom/core": "workspace:*"
}
}
8 changes: 8 additions & 0 deletions examples/minimal-iframes/vite.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {defineConfig} from 'vite';

export default defineConfig({
root: './app',
resolve: {
conditions: ['quilt:source'],
},
});
9 changes: 7 additions & 2 deletions packages/core/source/receiver/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type {RemoteNodeSerialization} from '../types.ts';
import type {RemoteReceiverOptions} from './shared.ts';

export class DOMRemoteReceiver {
readonly root: DocumentFragment | Element = document.createDocumentFragment();
readonly root: DocumentFragment | Element;
readonly receive: RemoteMutationCallback;

get callback() {
Expand All @@ -23,9 +23,14 @@ export class DOMRemoteReceiver {

private readonly attached = new Map<string, Node>();

constructor({retain, release}: RemoteReceiverOptions = {}) {
constructor({
root = document.createDocumentFragment(),
retain,
release,
}: RemoteReceiverOptions & {root?: DocumentFragment | Element} = {}) {
const {attached} = this;

this.root = root;
this.receive = createRemoteMutationCallback({
insertChild: (id, child, index) => {
const parent = id === ROOT_ID ? this.root : attached.get(id)!;
Expand Down
Loading

0 comments on commit 8e1fad4

Please sign in to comment.