Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
robin-drexler committed Dec 4, 2024
1 parent df7691a commit 3ab831d
Show file tree
Hide file tree
Showing 15 changed files with 674 additions and 0 deletions.
11 changes: 11 additions & 0 deletions examples/remote-ui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Remote UI example

This example shows how to run legacy remote-ui on the remote side with remote-dom on the host using the legacy adapter layer.

## Running this example

From the root of the repository, run the following command:

```bash
pnpm run example:remote-ui
```
88 changes: 88 additions & 0 deletions examples/remote-ui/app/host/components.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import {type ComponentChildren} from 'preact';
import {forwardRef} from 'preact/compat';
import {useRef, useImperativeHandle} from 'preact/hooks';

import type {
ButtonProperties,
StackProperties,
TextProperties,
ModalMethods,
ModalProperties,
} from '../types.ts';

export function Text({
emphasis,
children,
}: {children?: ComponentChildren} & TextProperties) {
return (
<span
class={['Text', emphasis && 'Text--emphasis'].filter(Boolean).join(' ')}
>
{children}
</span>
);
}

export function Button({
onPress,
modal,
children,
}: {
children?: ComponentChildren;
modal?: ComponentChildren;
} & ButtonProperties) {
console.log('Button', {onPress, modal});
return (
<>
<button
class="Button"
type="button"
onClick={() =>
onPress?.() ?? document.querySelector('dialog')?.showModal()
}
>
{children}
</button>
{modal}
</>
);
}

export function Stack({
spacing,
children,
}: {children?: ComponentChildren} & StackProperties) {
return (
<div
class={['Stack', spacing && 'Stack--spacing'].filter(Boolean).join(' ')}
>
{children}
</div>
);
}

export const Modal = forwardRef<
ModalMethods,
{
children?: ComponentChildren;
primaryAction?: ComponentChildren;
} & ModalProperties
>(function Modal({children, primaryAction, onClose}, ref) {
const dialogRef = useRef<HTMLDialogElement>(null);

useImperativeHandle(ref, () => ({
open() {
dialogRef.current?.showModal();
},
close() {
dialogRef.current?.close();
},
}));

return (
<dialog ref={dialogRef} class="Modal" onClose={() => onClose?.()}>
<div class="Modal-Content">{children}</div>
{primaryAction && <div class="Modal-Actions">{primaryAction}</div>}
</dialog>
);
});
34 changes: 34 additions & 0 deletions examples/remote-ui/app/host/host.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {render} from 'preact';
import '@preact/signals';

import {
SignalRemoteReceiver,
RemoteRootRenderer,
RemoteFragmentRenderer,
createRemoteComponentRenderer,
} from '@remote-dom/preact/host';
import {adaptToLegacyRemoteChannel} from '@remote-dom/core/legacy';
import {createEndpoint, fromIframe, retain, release} from '@remote-ui/rpc';
import {Button, Modal, Stack, Text} from './components.tsx';

const components = new Map([
['Text', createRemoteComponentRenderer(Text)],
['Button', createRemoteComponentRenderer(Button)],
['Stack', createRemoteComponentRenderer(Stack)],
['Modal', createRemoteComponentRenderer(Modal)],
['remote-fragment', RemoteFragmentRenderer],
]);

const root = document.querySelector('#root')!;
const iframe = document.querySelector('#remote-iframe') as HTMLIFrameElement;
const endpoint = createEndpoint(fromIframe(iframe));

const receiver = new SignalRemoteReceiver({retain, release});
const channel = adaptToLegacyRemoteChannel(receiver.connection);

render(
<RemoteRootRenderer components={components} receiver={receiver} />,
root,
);

endpoint.call.render(channel);
17 changes: 17 additions & 0 deletions examples/remote-ui/app/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<link rel="icon" href="https://fav.farm/🛰️" />
<link rel="stylesheet" href="./style.css" />

<title>Getting started • Remote DOM</title>
</head>

<body>
<div id="root"></div>

<iframe id="remote-iframe" src="./remote/iframe.html" hidden></iframe>
<script type="module" src="./host/host.tsx"></script>
</body>
</html>
15 changes: 15 additions & 0 deletions examples/remote-ui/app/remote/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/** @jsxRuntime automatic */
/** @jsxImportSource react */

import {useState} from 'react';
import {Button, Stack, Text} from './components';

export function App() {
const [counter, setCounter] = useState(0);
return (
<Stack>
<Button onPress={() => setCounter(counter + 1)}>Update counter</Button>
<Text>Counter: {counter}</Text>
</Stack>
);
}
18 changes: 18 additions & 0 deletions examples/remote-ui/app/remote/components.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {createRemoteReactComponent} from '@remote-ui/react';
import {
ButtonProperties,
ModalProperties,
StackProperties,
TextProperties,
} from '../types';

export const Button = createRemoteReactComponent<'Button', ButtonProperties>(
'Button',
);
export const Text = createRemoteReactComponent<'Text', TextProperties>('Text');
export const Stack = createRemoteReactComponent<'Stack', StackProperties>(
'Stack',
);
export const Modal = createRemoteReactComponent<'Modal', ModalProperties>(
'Modal',
);
14 changes: 14 additions & 0 deletions examples/remote-ui/app/remote/iframe.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<link rel="icon" href="https://fav.farm/🛰️" />
<title>Getting started (remote) • Remote DOM</title>
</head>

<body>
<div id="root"></div>

<script type="module" src="./remote.tsx"></script>
</body>
</html>
21 changes: 21 additions & 0 deletions examples/remote-ui/app/remote/remote.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/** @jsxRuntime automatic */
/** @jsxImportSource react */
import {createEndpoint, fromInsideIframe, retain} from '@remote-ui/rpc';
import {createRoot, createRemoteRoot} from '@remote-ui/react';

import * as components from './components';
import {App} from './app';

const endpoint = createEndpoint(fromInsideIframe());
endpoint.expose({
render(channel) {
retain(channel);

const remoteRoot = createRemoteRoot(channel, {
components: Object.keys(components),
});

createRoot(remoteRoot).render(<App />);
remoteRoot.mount();
},
});
Loading

0 comments on commit 3ab831d

Please sign in to comment.