How do I dynamically generate code for the selected variant? #561
Replies: 2 comments
-
I'm also having problems updating the source when I use either a source property or a source slot. I tried creating a computed property. I tried creating a reactive string and either using watch or watchEffect to see changes to the reactive state, but none of those work. The item in my story is updating, so I know that the state is changing, but I suspect that something about the way the story is mounted breaks what I am trying to do. |
Beta Was this translation helpful? Give feedback.
-
I have implemented functionality to make it work specifying a function to generate the source (below is the diff). This is only tested in Vue 3. Is someone else able to pick this up and implement for Vue 2 and Svelte? I don't know how I could get the state into the slot. If someone could point me in the right direction for that, I'd be happy to implement that for Vue 3 too. diff --git a/examples/vue3/src/components/BaseButton.story.vue b/examples/vue3/src/components/BaseButton.story.vue
index 0a1650f..09bdacd 100644
--- a/examples/vue3/src/components/BaseButton.story.vue
+++ b/examples/vue3/src/components/BaseButton.story.vue
@@ -8,6 +8,20 @@ function initState () {
size: undefined,
}
}
+
+const generateSource = (state) => {
+ const lines = []
+ state.disabled && lines.push('disabled')
+ state.color && lines.push(`color="${state.color}"`)
+ state.size && lines.push(`size="${state.size}"`)
+
+ return `Custom generated source:
+
+<BaseButton ${lines.join('\n ')}>
+ Click me
+</BaseButton>`
+}
+
</script>
<template>
@@ -21,6 +35,7 @@ function initState () {
<Variant
title="playground"
:init-state="initState"
+ :source="generateSource"
>
<template #default="{ state }">
<BaseButton
diff --git a/packages/histoire-app/src/app/components/panel/StorySourceCode.vue b/packages/histoire-app/src/app/components/panel/StorySourceCode.vue
index b378726..0896022 100644
--- a/packages/histoire-app/src/app/components/panel/StorySourceCode.vue
+++ b/packages/histoire-app/src/app/components/panel/StorySourceCode.vue
@@ -35,7 +35,8 @@ watch(() => [props.variant, generateSourceCodeFn.value], async () => {
dynamicSourceCode.value = ''
try {
if (props.variant.source) {
- dynamicSourceCode.value = props.variant.source
+ const state = props.variant.state ?? {}
+ dynamicSourceCode.value = typeof props.variant.source === 'function' ? props.variant.source(state) : props.variant.source
} else if (props.variant.slots?.().source) {
const source = props.variant.slots?.().source()[0].children
if (source) {
diff --git a/packages/histoire-plugin-vue/src/client/app/Variant.ts b/packages/histoire-plugin-vue/src/client/app/Variant.ts
index 622561b..cda5eec 100644
--- a/packages/histoire-plugin-vue/src/client/app/Variant.ts
+++ b/packages/histoire-plugin-vue/src/client/app/Variant.ts
@@ -17,7 +17,7 @@ export default defineComponent({
},
source: {
- type: String,
+ type: [String, Function],
default: null,
},
diff --git a/packages/histoire-shared/src/types/story.ts b/packages/histoire-shared/src/types/story.ts
index d4a4c72..5e88b4e 100644
--- a/packages/histoire-shared/src/types/story.ts
+++ b/packages/histoire-shared/src/types/story.ts
@@ -26,7 +26,7 @@ export interface CommonProps {
export interface InheritedProps {
setupApp?: (payload: any) => unknown
- source?: string
+ source?: string | ((state: object) => string)
responsiveDisabled?: boolean
autoPropsDisabled?: boolean
}
@@ -64,7 +64,7 @@ export interface Variant {
setupApp?: (payload: any) => unknown
slots?: () => { default: any, controls: any, source: any }
state: any
- source?: string
+ source?: string | ((state: object) => string)
responsiveDisabled?: boolean
autoPropsDisabled?: boolean
configReady?: boolean |
Beta Was this translation helpful? Give feedback.
-
I have a number of variants on a page. Vue 3 app. I'm using
initState
to set them up, and have a custom control to change the color of the selected one.The built in source generation does not generate what I want. My component's name is represented as its file name whereas I want it to have a prefix (e.g. the component is
Icon
and I want the generated code to call itMpIcon
. I can work around this one by setting thename
attribute to what I want. The other thing is that my dynamic values are all represented as a binding rather than a value e.g.:color="'#ff0000'"
instead ofcolor="#ff0000"
. There are some fields that I would like to be left as bindings so it would need to be configurable.I therefore thought I would take over and generate the source myself.
I can't do it using the
source
attribute of the variant since it doesn't have access to the state. I thought I would try using<template #source="{ state }">
but it appears that the state is not available in that slot, so I can't use it there.I tried going with a global state and updating all the components on the page, but that was really slow, and crashed after a couple of updates, and it was heavy handed regenerating the source code for all after an update.
I can't work out in the histoire source code where the source slot is defined, to see if it would be possible to access the state there (or add that capability).
What I would like, if possible, would be either:
A. More control over the code generation so that I can do things like tell it to generate some fields without the binding syntax, or
B. To have the state available for me to generate the source properly in my stories using the slot, or
C. To be able to specify a function for the source attribute and have that called back with the state to dynamically generate the source, or
D. To find out some other way of generating the source code that allows me to use the dynamic props etc.
All this is no problem with a single story in a file, but immediately becomes a problem with multiple variants.
Keen to hear any workarounds or suggestions about this. I'm happy to look into adding a state to the source slot if someone can point me in the direction of where it is, and where the controls slot is defined to use as an example.
Beta Was this translation helpful? Give feedback.
All reactions