Components:Prefabs (Experimental) - bettyblocks/cli GitHub Wiki

THIS VERSION OF WRITING PREFABS IS EXPERIMENTAL AND SUBJECT TO CHANGE

A Prefab is something you can drag onto the canvas inside the Page Builder. Prefabs appear in the sidebar of the Page Builder. The following screenshot shows four Prefabs in the category NAVIGATION in the sidebar of the Page Builder.

A category in the sidebar with several Prefabs.

A Prefab is configured by a typescript file returning a prefab structure.

Example

This example configures a heading Prefab containing a single Heading Component:

import { component, prefab, text } from '@betty-blocks/component-sdk';

const attributes = {
  category: 'CONTENT',
  icon: 'HEADING_ICON',
}

const options = {
  text: text('Heading text')
}

export default prefab('Hello World', attributes, undefined, [
  component('Heading', { options }, []);
])

Options

Options are created by functions that can be imported from the component-sdk, they take a label as the first argument and the second argument takes a configuration object that looks the same as it did in the old prefab system.

Examples:

const options = {
  content: variable('Content', { value: ['Default text']}),
  show: toggle('Show', { value: false }),
  backgroundColor: color('Background Color', { value: 'Accent3' })
}

There are some convenience functions for creating conditions in configurations, these are used to show or hide options based on the value of another option (e.g. show styling options, show advanced options, etc.)

const backgroundColor = color('Background color', { 
  value: 'Accent3',
  configuration: { 
    condition: showIfTrue('styling'),
    /* condition: showIf('styling', false) */
    /* condition: hideIf('styling', false) */
  }
})

Refer to the component-sdk documentation for all the types of options and convenience functions we support.

Reusing code

Now that the component set is being properly transpiled by the typescript compiler, it is now possible to import files and/or libraries to generate your prefabs. This needs to be thoroughly tested.

When you want to create a React component in the beforeCreate make sure you import React the following way and give your file the .tsx extension.

import * as React from 'react';

Another important note, files in the root of the prefabs directory are assumed to result in a prefab. If you want to reuse pieces of code, please put them in a subdirectory (e.g. ./src/prefabs/data-table/Column.tsx)

BeforeCreate examples

Before create functions allow you to configure what models and/or properties you want to use in your component. Following examples are for many usecases expand them to see the full code, the LoginFormWizard also contains an example of how to include an interaction (not required). It looks much the same as it did in the previous prefab style.

LoginFormWizard
import * as React from 'react';
import {
 component,
 option,
 prefab,
 BeforeCreateArgs,
 PrefabInteraction,
 InteractionType,
} from '@betty-blocks/component-sdk';

const beforeCreate = ({
 close,
 components: { CreateLoginFormWizard },
 prefab,
 prefabs,
 save,
}: BeforeCreateArgs) => {
 return (
   <CreateLoginFormWizard
     close={close}
     prefab={prefab}
     prefabs={prefabs}
     save={save}
   />
 );
};

const interactions: PrefabInteraction[] = [
 {
   name: 'login',
   sourceEvent: 'onActionSuccess',
   ref: {
     sourceComponentId: '#formId',
   },
   parameters: [],
   type: InteractionType.Global,
 },
];

const attributes = {
 category: 'FORM',
 icon: 'LoginFormIcon',
 interactions,
};

const options = {
 actionId: option('ACTION_JS', { label: 'Action', value: '' }),
};

export default prefab('Login Form', attributes, beforeCreate, [
 component('Form', { options, ref: { id: '#formId' } }, []),
]);
(Create)FormWizard
 import * as React from 'react';
import {
component,
option,
prefab,
model,
filter,
BeforeCreateArgs,
} from '@betty-blocks/component-sdk';
import { Icon } from '@betty-blocks/component-sdk';

const beforeCreate = ({
close,
components: { CreateFormCreateWizard },
prefab,
prefabs,
save,
}: BeforeCreateArgs) => {
return (
  <CreateFormCreateWizard
    close={close}
    prefab={prefab}
    prefabs={prefabs}
    save={save}
  />
);
};

const attributes = {
category: 'FORMV2',
icon: Icon.CreateFormIcon,
};

const options = {
actionId: option('ACTION_JS', { label: 'Action', value: '' }),
modelId: model('Model'),
filter: filter('Filter', { configuration: { dependsOn: 'modelId' } }),
};

export default prefab('Create Form Beta', attributes, beforeCreate, [
component('Action Form Beta', { options }, []),
]);
UpdateFormWizard
import * as React from 'react';
import {
component,
option,
prefab,
model,
filter,
BeforeCreateArgs,
} from '@betty-blocks/component-sdk';
import { Icon } from '@betty-blocks/component-sdk';

const beforeCreate = ({
close,
components: { CreateFormUpdateWizard },
prefab,
prefabs,
save,
}: BeforeCreateArgs) => {
return (
  <CreateFormUpdateWizard
    close={close}
    prefab={prefab}
    prefabs={prefabs}
    save={save}
  />
);
};

const attributes = {
category: 'FORMV2',
icon: Icon.UpdateFormIcon,
};

const options = {
actionId: option('ACTION_JS', { label: 'Action', value: '' }),
modelId: model('Model'),
filter: filter('Filter', { configuration: { dependsOn: 'modelId' } }),
};

export default prefab('Update Form Beta', attributes, beforeCreate, [
component('Action Form Beta', { options }, []),
]);
CreateInputWizard
  import * as React from 'react';
import { BeforeCreateArgs, Icon, prefab } from '@betty-blocks/component-sdk';
import { TextInput } from './structures/TextInput';

const beforeCreate = ({
close,
components: { CreateFormInputWizard },
prefab,
save,
}: BeforeCreateArgs) => {

const actionVariableOption = prefab.structure[0].options.find(
  (option: { type: string }) => option.type === 'ACTION_JS_VARIABLE',
);

if (!actionVariableOption) {
  return <div>Prefab is missing the actionVariable component option</div>;
}

return (
  <CreateFormInputWizard
    supportedKinds={['TEXT', 'URL', 'IBAN', 'STRING']}
    actionVariableOption={actionVariableOption.key}
    labelOptionKey="label"
    nameOptionKey="actionVariableId"
    close={close}
    prefab={prefab}
    save={save}
  />
);
};

const attributes = {
category: 'FORMV2',
icon: Icon.TextInputIcon,
keywords: ['Form', 'input'],
};

export default prefab('Text Field Beta', attributes, beforeCreate, [
TextInput({ label: 'Textfield', type: 'text' }),
]);
NOTE: The CreateFormInputWizard does need a ACTION_JS_VARIABLE option to fill the actionVariableOption variable you see in the example above.

New Options examples

These new ActionJs options are introduced to connect the components directly to the action, any change made is directly change in the action, whether you add, remove or duplicate components the action variables will be in sync.

  • ACTION_JS_PROPERTY

Option that contains the model property.

  • ACTION_JS_VARIABLE

Option that contains action variable information connected to this component, usually being used to get the action variable id.

  • ACTION_JS

Option that contains data about the action itself, usually being used to get the action id.

ACTION_JS_PROPERTY example
  actionProperty: option('ACTION_JS_PROPERTY', {
   label: 'Property',
   value: '',
  }),
ACTION_JS_VARIABLE example
    actionVariableId: option('ACTION_JS_VARIABLE', { label: 'Name', value: '' }),
ACTION_JS example
      actionId: option('ACTION_JS', { label: 'Action', value: '' }),

What does this mean for my component?

Make sure that your component uses the FormHelper to wrap all form inputs.

const { Form } = B;

<Form>
<input id="example">
</Form>

It is important that your inputs use the name of the action variable as part of their name attribute. Like so

const { actionVariableId } = options;

<input name={actionVariableId} value={...} />
⚠️ **GitHub.com Fallback** ⚠️