JsonForms with Storybook 7

Anybody have any examples on how to make Storybook v7 work with JsonForms? (Ideally Vue, but any language/framework is accepted)

The only example I managed to find was this one: GitHub - shotanue/jsonforms-antdv: JSON Forms renderers, Ant Design Vue
But this repo has Storybook v6, and there is quite a diference in creating stories between v6 and v7

Hi @adamsilva01,

What exactly are you looking for? Would you like to render JSON Forms as part of your StoryBook or would you like to showcase your custom renderer set in a StoryBook? What exactly are you struggling with?

Hey @sdirix ,

I’m trying to create stories for each of my custom renderers. I’m starting with a very basic custom renderer that is only a text field. I created a base template that would be the wrapper for each story:

import type { JsonFormsProps, JsonFormsRendererRegistryEntry } from '@jsonforms/core'
import { JsonForms } from '@jsonforms/vue';
import { markRaw } from 'vue';
import { StoryObj } from '@storybook/vue3'
// various imports of custom renderers


export type JsonFormsTemplateProps = JsonFormsProps & {
    data: Record<string, unknown> | Array<unknown>;
    onChange: (ev: { data: Record<string, unknown> }) => void;
};

export type JsonFormsTemplate = StoryObj<JsonFormsTemplateProps>;

const renderers: JsonFormsRendererRegistryEntry[] = markRaw([
    // ...rendererList
])

export const jsonFormsTemplate: JsonFormsTemplate = (args: any) => ({
    render: (args: any) => ({
        components: { JsonForms },
        setup () {
            args.renderers = markRaw(renderers);
            return { args }
        },
        template: '<json-forms v-bind="args" />',
    }),
});

Then I have the story for the custom renderer:

import type { Meta, StoryObj } from '@storybook/vue3'
import { jsonFormsTemplate } from '~/.storybook/jsonFormsTemplate'

// More on how to set up stories at: https://storybook.js.org/docs/vue/writing-stories/introduction
const meta: Meta = {
    // This component will have an automatically generated docsPage
    // entry: https://storybook.js.org/docs/vue/writing-docs/autodocs
    tags: ['autodocs'],
    args: {
        schema: {
            type: 'object',
            unevaluatedProperties: false,
            properties: {
                '/personal/email': { title: 'Email', description: 'Email address', type: 'string', format: 'email' },
            },
            required: ['/personal/email'],
        },
        uischema: { type: 'Control', scope: '#/properties/~1personal~1email', options: {} },
        path: '',
    }, // default value
} satisfies Meta

export default meta
/*
 *šŸ‘‡ Render functions are a framework specific feature to allow you control on how the component renders.
 * See https://storybook.js.org/docs/vue/api/csf
 * to learn how to use render functions.
 */

export const Primary: StoryObj = jsonFormsTemplate.bind({})
Primary.args = {
    schema: {
        type: 'object',
        unevaluatedProperties: false,
        properties: {
            '/personal/email': { title: 'Email', description: 'Email address', type: 'string', format: 'email' },
        },
        required: ['/personal/email'],
    },
    uischema: { type: 'Control', scope: '#/properties/~1personal~1email', options: {} },
    path: '',
}

I’m getting the following error when opening Storybook and trying to view to story:

TypeError: Failed to fetch dynamically imported module: http://localhost:6006/components/renderers/RenderText.stories.ts?t=1693226780278

Hi @adamsilva01,

Were you able to solve the problem? Did you also try without your custom renderers and just with the @jsonforms/vue-vanilla renderers?

Hey @sdirix ,

Yeah, I managed to implement this. For future reference, it ended up looking like this:
The utils renderer, which basically renders the JSON Forms component, with the necessary renderers and data passed in via parameters:

import { markRaw } from 'vue'
import { JsonForms } from '@jsonforms/vue'
import type { StoryObj } from '@storybook/vue3'
import { vanillaRenderers } from '@jsonforms/vue-vanilla'
import { JsonFormsRendererRegistryEntry } from '@jsonforms/core'

export function JsonFormsWrapper (renderers: JsonFormsRendererRegistryEntry[], data: {} = {}): StoryObj  {
    return {
        render: (args: any) => ({
            components: { JsonForms },
            setup () {
                args.renderers = markRaw([...renderers, ...vanillaRenderers])
                args.data = data
                return { args }
            },
            template: '<json-forms v-bind="args" />',
        })
    }
}

And an example of a simple story using a custom renderer, but even using a pre-made renderer should also work:

import type { Meta, StoryObj } from '@storybook/vue3'
import { entry as numberRenderer } from './RenderNumber.vue'
import { JsonFormsWrapper } from '~/.storybook/utils'

const meta: Meta = {
    title: 'Render/Number',
    tags: ['autodocs'],
} satisfies Meta

export default meta

export const Regular: StoryObj = {
    ...JsonFormsWrapper([numberRenderer]),
    args: {
        schema: SchemaObject // Import the schema from another file or create it in this file,
        uischema: UiSchemaObjectFn // I use a specific function to create the ui schema from the schema due to special needs
        path: '',
    },
}

// This is the story with default data
export const RegularWithDefault: StoryObj = {
    ...Regular,
    ...JsonFormsWrapper([numberRenderer], {
        '/age': 30,
    }),
}

1 Like