Skip to content

Commit

Permalink
feat: synchornize variant state with iframe
Browse files Browse the repository at this point in the history
  • Loading branch information
Akryum committed Feb 12, 2022
1 parent 16df34a commit 9d5b969
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 3 deletions.
59 changes: 59 additions & 0 deletions examples/vue3/src/components/State.story.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<script lang="ts" setup>
function initState () {
return {
count: 0,
}
}
</script>

<template>
<Story
title="State"
>
<Variant
title="default"
:init-state="initState"
>
<template #default="{ state }">
<h1>State</h1>
<div>
<pre>{{ state }}</pre>
<input
v-model.number="state.count"
type="number"
>
</div>
</template>

<template #controls="{ state }">
<div class="controls">
<button @click="state.count--">
-1
</button>
<button @click="state.count++">
+1
</button>
<span>{{ state.count }}</span>
</div>
</template>
</Variant>
</Story>
</template>

<style scoped>
.controls {
margin: 12px;
display: flex;
align-items: center;
}
.controls > :not(:first-child) {
margin-left: 12px;
}
button {
padding: 6px;
border-radius: 4px;
cursor: pointer;
}
</style>
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
<script lang="ts" setup>
import { PropType } from 'vue'
import { useEventListener } from '@vueuse/core'
import { PropType, ref, watch, toRaw } from 'vue'
import { Story, Variant } from '../types'
import { STATE_SYNC } from '../util/const.js'
import BaseSplitPane from './base/BaseSplitPane.vue'
defineProps({
const props = defineProps({
variant: {
type: Object as PropType<Variant>,
required: true,
Expand All @@ -14,6 +16,30 @@ defineProps({
required: true,
},
})
const iframe = ref<HTMLIFrameElement>()
function syncState () {
if (iframe.value) {
iframe.value.contentWindow.postMessage({
type: STATE_SYNC,
state: toRaw(props.variant.state),
})
}
}
watch(() => props.variant.state, () => {
syncState()
}, {
deep: true,
immediate: true,
})
useEventListener(window, 'message', (event) => {
if (event.data.type === STATE_SYNC) {
Object.assign(props.variant.state, event.data.state)
}
})
</script>

<template>
Expand All @@ -28,8 +54,10 @@ defineProps({
<template #first>
<div class="htw-p-4 htw-h-full htw-overflow-hidden htw-bg-white dark:htw-bg-zinc-700 htw-rounded-l-lg htw-relative">
<iframe
ref="iframe"
:src="`/__sandbox?storyId=${story.id}&variantId=${variant.id}`"
class="htw-w-full htw-h-full htw-border htw-border-zinc-100 dark:htw-border-zinc-800 htw-bg-white"
@load="syncState()"
/>
<!-- Markers -->
<div class="htw-absolute htw-top-1 htw-left-4 htw-h-2 htw-w-px htw-bg-zinc-200 dark:htw-bg-zinc-800" />
Expand Down
19 changes: 18 additions & 1 deletion packages/histoire/src/client/app/sandbox.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import './style/sandbox.css'
import { parseQuery } from 'vue-router'
import { computed, createApp, h, ref } from 'vue'
import { computed, createApp, h, ref, toRaw, watch } from 'vue'
import { createPinia } from 'pinia'
import { registerGlobalComponents } from './global-components'
import SandboxVue3 from './components/sandbox/SandboxVue3.vue'
import type { StoryFile } from './types'
import { mapFile } from './util/mapping'
// @ts-expect-error virtual module
import { files } from '$histoire-stories'
import { STATE_SYNC } from './util/const.js'

const query = parseQuery(window.location.search)
const file = ref<StoryFile>(mapFile(files.find(f => f.id === query.storyId)))
Expand All @@ -16,6 +17,22 @@ const app = createApp({
setup () {
const story = computed(() => file.value.story)
const variant = computed(() => story.value?.variants.find(v => v.id === query.variantId))

window.addEventListener('message', event => {
if (event.data?.type === STATE_SYNC) {
Object.assign(variant.value.state, event.data.state)
}
})

watch(() => variant.value.state, value => {
window.parent?.postMessage({
type: STATE_SYNC,
state: toRaw(value),
})
}, {
deep: true,
})

return {
story,
variant,
Expand Down
1 change: 1 addition & 0 deletions packages/histoire/src/client/app/util/const.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const STATE_SYNC = '__histoire:state-sync'

0 comments on commit 9d5b969

Please sign in to comment.