-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(channels): Add channels package and app examples (#57)
* feat(channels): add channels package * feat(apps): add example channels pages * fix(channels): flush buffer on connect
- Loading branch information
Showing
20 changed files
with
922 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
'use client' | ||
|
||
import Link from 'next/link' | ||
import { | ||
studioTheme, | ||
ThemeProvider, | ||
Box, | ||
Button, | ||
Card, | ||
Code, | ||
Flex, | ||
Heading, | ||
Text, | ||
} from '@sanity/ui' | ||
import { type ChannelReturns, type Connection, createChannel } from 'channels' | ||
import { useEffect, useState } from 'react' | ||
|
||
function ChannelDisplay({ clientId }: { clientId: string }) { | ||
const [log, setLog] = useState<any[]>([]) | ||
const [connections, setConnections] = useState<Connection[]>([]) | ||
const [channel, setChannel] = useState<ChannelReturns>() | ||
|
||
useEffect(() => { | ||
const channel = createChannel({ | ||
id: clientId, | ||
connections: [ | ||
{ | ||
target: parent, | ||
id: 'parent', | ||
}, | ||
], | ||
handle(type, data) { | ||
setLog((l) => [{ ...data, type }, ...l]) | ||
}, | ||
onConnect: (added) => setConnections((cs) => [...cs, added]), | ||
onDisconnect: (removed) => | ||
setConnections((cs) => | ||
cs.filter((c) => c.id === removed.id && c.target === removed.target), | ||
), | ||
}) | ||
|
||
setChannel(channel) | ||
return () => { | ||
setConnections([]) | ||
setLog([]) | ||
channel.disconnect() | ||
} | ||
}, [clientId]) | ||
|
||
const sendMessage = () => { | ||
channel?.send('child/event', { from: clientId }) | ||
} | ||
|
||
return !channel ? ( | ||
<Card flex={1} padding={4}> | ||
<Text>Loading...</Text> | ||
</Card> | ||
) : ( | ||
<Card flex={1} overflow={'auto'}> | ||
<Card borderBottom> | ||
<Flex justify={'space-between'} align={'center'} padding={3}> | ||
<Heading as="h1" size={1}> | ||
Channel ({channel?.inFrame ? 'in iFrame' : 'outside iFrame'}) | ||
</Heading> | ||
|
||
{channel.inFrame ? ( | ||
<Flex gap={2} align={'center'}> | ||
<Text size={0}>{connections.length} Connections</Text> | ||
<Button | ||
fontSize={1} | ||
mode="ghost" | ||
padding={3} | ||
text="Clear" | ||
onClick={() => setLog([])} | ||
disabled={!log.length} | ||
/> | ||
<Button | ||
fontSize={1} | ||
mode="default" | ||
padding={3} | ||
text="Send" | ||
tone="positive" | ||
onClick={sendMessage} | ||
/> | ||
</Flex> | ||
) : ( | ||
<Link href="/channels/"> | ||
<Button | ||
fontSize={1} | ||
mode="ghost" | ||
padding={3} | ||
text="Go to Parent" | ||
/> | ||
</Link> | ||
)} | ||
</Flex> | ||
</Card> | ||
<Box padding={3}> | ||
<Card padding={4} tone="primary" radius={3} overflow={'hidden'}> | ||
<Code language="json" size={1}> | ||
{JSON.stringify(log, null, 2)} | ||
</Code> | ||
</Card> | ||
</Box> | ||
</Card> | ||
) | ||
} | ||
|
||
export default function ChildPage() { | ||
return ( | ||
<ThemeProvider theme={studioTheme} tone="transparent"> | ||
<Flex direction={'column'} className="h-screen"> | ||
<ChannelDisplay clientId={'overlays'} /> | ||
<Card flex={1} borderTop> | ||
<ChannelDisplay clientId={'store'} /> | ||
</Card> | ||
</Flex> | ||
</ThemeProvider> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
'use client' | ||
|
||
import { studioTheme, ThemeProvider } from '@sanity/ui' | ||
import { Button, Box, Card, Code, Flex, Heading, Text } from '@sanity/ui' | ||
import { type Connection, type ChannelReturns, createChannel } from 'channels' | ||
import { forwardRef, useEffect, useRef, useState } from 'react' | ||
|
||
const IFrame = forwardRef<HTMLIFrameElement, { src: string }>(function IFrame( | ||
{ src }, | ||
ref, | ||
) { | ||
return ( | ||
<Card flex={1} borderRight> | ||
<iframe className="h-full w-full bg-white" src={src} ref={ref} /> | ||
</Card> | ||
) | ||
}) | ||
|
||
export default function ParentPage() { | ||
const [log, setLog] = useState<any[]>([]) | ||
const [connections, setConnections] = useState<Connection[]>([]) | ||
const frameOne = useRef<HTMLIFrameElement>(null) | ||
const frameTwo = useRef<HTMLIFrameElement>(null) | ||
const [channel, setChannel] = useState<ChannelReturns>() | ||
|
||
useEffect(() => { | ||
const targetOne = frameOne.current?.contentWindow | ||
const targetTwo = frameTwo.current?.contentWindow | ||
if (!targetOne || !targetTwo) return | ||
const channel = createChannel({ | ||
connections: [ | ||
{ | ||
target: targetOne, | ||
id: 'overlays', | ||
}, | ||
{ | ||
target: targetOne, | ||
id: 'store', | ||
}, | ||
{ | ||
target: targetTwo, | ||
id: 'overlays', | ||
}, | ||
{ | ||
target: targetTwo, | ||
id: 'store', | ||
}, | ||
], | ||
id: 'parent', | ||
handle(type, data) { | ||
setLog((l) => [{ ...data, type }, ...l]) | ||
}, | ||
onConnect: (added) => { | ||
setConnections((cs) => [...cs, added]) | ||
}, | ||
onDisconnect: (removed) => { | ||
setConnections((cs) => | ||
cs.filter((c) => c.id === removed.id && c.target === removed.target), | ||
) | ||
}, | ||
}) | ||
setChannel(channel) | ||
|
||
return () => { | ||
channel.disconnect() | ||
setLog([]) | ||
} | ||
}, []) | ||
|
||
const sendMessage = async () => { | ||
console.log('Send!') | ||
const value = await channel?.send('parent/event', { | ||
foo: 'bar', | ||
}) | ||
console.log('Done!', value) | ||
} | ||
|
||
return ( | ||
<ThemeProvider theme={studioTheme} tone="transparent"> | ||
<Flex justify={'space-evenly'} className={'h-screen'}> | ||
<Flex flex={1} justify={'space-evenly'} direction={'column'}> | ||
<IFrame ref={frameOne} src="/channels/child" /> | ||
<IFrame ref={frameTwo} src="/channels/child" /> | ||
</Flex> | ||
<Card flex={1} overflow="auto"> | ||
<Card borderBottom> | ||
<Flex justify={'space-between'} align={'center'} padding={3}> | ||
<Heading as="h1" size={1}> | ||
Composer | ||
</Heading> | ||
<Flex gap={2} align={'center'}> | ||
<Text size={0}>{connections.length} Connections</Text> | ||
<Button | ||
fontSize={1} | ||
mode="ghost" | ||
padding={3} | ||
text="Clear" | ||
onClick={() => setLog([])} | ||
disabled={!log.length} | ||
/> | ||
<Button | ||
fontSize={1} | ||
mode="default" | ||
padding={3} | ||
text="Send" | ||
tone="primary" | ||
onClick={sendMessage} | ||
/> | ||
</Flex> | ||
</Flex> | ||
</Card> | ||
<Box padding={3}> | ||
<Card padding={4} tone="positive" radius={3} overflow={'hidden'}> | ||
<Code language="json" size={1}> | ||
{JSON.stringify(log, null, 2)} | ||
</Code> | ||
</Card> | ||
</Box> | ||
</Card> | ||
</Flex> | ||
</ThemeProvider> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
<template> | ||
<div class="h-full w-full bg-white p-8"> | ||
<div v-if="channel" class="flex items-center justify-between"> | ||
<h1 class="text-lg font-bold">Channel</h1> | ||
<button | ||
v-if="channel.inFrame" | ||
class="rounded bg-purple-500 p-2 leading-none text-white" | ||
type="button" | ||
@click.prevent="sendMessage" | ||
> | ||
Send | ||
</button> | ||
<RouterLink | ||
v-else | ||
class="rounded bg-purple-500 p-2 leading-none text-white" | ||
to="/channels/parent" | ||
> | ||
Go to Parent | ||
</RouterLink> | ||
</div> | ||
<div v-else>Loading...</div> | ||
<div v-if="channel" class="mt-4 rounded-lg bg-green-200 p-4"> | ||
<pre class="text-xs">{{ log }}</pre> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
import { type ChannelReturns, createChannel } from 'channels' | ||
const log = ref<any[]>([]) | ||
const channel = ref<ChannelReturns | undefined>() | ||
onMounted(() => { | ||
channel.value = createChannel({ | ||
id: 'child', | ||
connections: [ | ||
{ | ||
target: parent, | ||
id: 'parent', | ||
}, | ||
], | ||
handle(type, data) { | ||
log.value.unshift({ ...data, type }) | ||
}, | ||
}) | ||
}) | ||
onUnmounted(() => { | ||
channel.value?.disconnect() | ||
}) | ||
const sendMessage = () => { | ||
channel.value?.send('child/event', { | ||
datetime: new Date().toISOString(), | ||
}) | ||
} | ||
</script> | ||
|
||
<style lang="postcss"></style> |
Oops, something went wrong.
0145396
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
visual-editing-svelte – ./apps/svelte
visual-editing-svelte-git-main.sanity.build
visual-editing-svelte.sanity.build