Authoring and Managing JSX Presets

Basic Information

As you might have noticed in the boilerplate repository, Merge requires JSX presets to be stored in the presets subdirectory of every component. Why? Presets are used to render the initial configuration of every component. Merge needs to know which composition of properties (including children) should be rendered by default. This composition will rendered by default whenever you, or anyone on your team, drag & drops a component on the canvas in the UXPin Editor.

A typical preset looks like this: 

import React from 'react';
import Button from '../Button';
 
 
export default (
    <Button         
        uxpId="button1"
        icon={<Icon icon='TickerSvg' size='s' />}
        mode="filled"
        size="s"
        stretched
        type="error"
    >
        Merge!
    </Button>
);

At the top of the file you have to import the React library and all the components that you want to represent in the preset. In the export default() part of the preset, place the JSX code representing the desired, default, composition of your component. The JSX representation of every component, apart from the usual configuration of properties, must have a unique UXPin ID attribute– uxpId. uxpId lets Merge properly render every component and track overrides of components (if it happens in the future).

IDs and Nested Components

Merge JSX presets can represent complex, nested, structures of components. In cases like this, it's very important to remember that all uxpIdattributes have to hold unique values. In a given preset, two components cannot have the same uxpId. Other than that, creating presets for nested structures works just like composing the JSX code in React.js components. You have to import all the components and create the full structure in export default() directive.

import React from 'react';
import SelectItem from '../../SelectItem/SelectItem';
import Select from '../Select';
 
export default (
  <Select uxpId="select1">
    <SelectItem uxpId="select.item.1">Option1</SelectItem>
    <SelectItem uxpId="select.item.2">Option2</SelectItem>
    <SelectItem uxpId="select.item.3">Option3</SelectItem>
  </Select>
);

When choosing the name for uxpId for components, think about the role they're playing. In the future, you may want to automatically replace one nested component with another one (say, a Button has just been deprecated and replaced with ButtonNew). In that case, keeping the same uxpIdwill allow Merge to automatically update all designs with the new component.

Overrides

A changes in the code of a preset is going to be automatically reflected in the UXPin design systems library in the UXPin Editor. Merge is going to modify all the properties, unless a property of a given component was changed by the user in UXPin Editor. A change like that is going to be treated as an override and will remain intact. Take this example:

At first, the default preset for a button looked like this:

import React from 'react';
import Button from '../Button';
 
export default (
  <Button
    uxpId="action1"
    size="small"
    variant="contained"
    color="primary"
    fullWidth
  >
    Click me
  </Button>
);

A user dragged this element to the canvas in UXPin and, in the UXPin interface, changed the property size to largeand changed color to secondary. Subsequently, let's say by the decision of the design systems team, the default preset for Button was modified to:

import React from 'react';
import Button from '../Select';
 
export default (
  <Button
    uxpId="action1"
    size="medium"
    variant="contained"
    color="primary"
    fullWidth
  >
    Click me
  </Button>
);

What happened to the design created in the UXPin Design Editor with this React.js button? Nothing. The properties that have been changed, had been previously overridden by the user. Merge preserved those changes to keep the design intact.

Now, let's say that the default label has been changed as well. This property has not been overridden by the user. What's going to happen? Merge is going to update the user's project:

Merge always compares changes in the code of JSX presets with the implementation to determine whether an update of the user's design is necessary.

Property Requirements

The content of all the properties in JSX presets must be serializable as JSON. You may build custom functions and manipulate data in the preset file, but the end result must be serializable. 

For example, the following JSX preset is valid:

import React from 'react';
import Button from '../Select';
 
const customFunction = () => "HelloWorld";
 
export default (
  <Button
    uxpId="signup1"
    size="large"
    custom={customFunction()}
  >
    Signup Now!
  </Button>
);

While this preset is incorrect (passing a function through props is currently unsupported):

import React from 'react';
import Button from '../Select';
 
const customFunction = () => "HelloWorld";
 
export default (
  <Button
    uxpId="signup1"
    size="large"
    custom={customFunction}
  >
    Signup Now!
  </Button>
);

In the preset files, you can easily import and modify data sets to be used by your component. Take this example:

import React from 'react';
import Table from '../Table';
 
const tableData = {
  header: ['band', 'singer', 'rhythm guitar', 'lead guitar', 'bass', 'drums', 'keyboard'],
  body: [
    {
      band: 'metallica',
      singer: 'james hetfield',
      'rhythm guitar': 'james hetfield',
      'lead guitar': 'kirk hammet',
      bass: 'robert trujillo',
      drums: 'lars ulrich',
    },
    {
      band: 'slayer',
      singer: 'tom araya',
      'rhythm guitar': 'kerry king',
      'lead guitar': 'gary holt',
      bass: 'tom araya',
      drums: 'paul bostaph',
    },
    {
      band: 'black sabbath',
      singer: 'ozzy osbourne',
      'lead guitar': 'tommy iommi',
      bass: 'geezer butler',
      drums: 'bill ward',
    },
    {
      band: 'queen',
      singer: 'freddy mercury',
      'lead guitar': 'brian may',
      bass: 'john deacon',
      drums: 'roger taylor',
      keyboard: 'freddy mercury',
    },
    {
      band: 'led zeppelin',
      singer: 'robert plant',
      'lead guitar': 'jimmy page',
      bass: 'john paul johns',
      drums: 'bonzo bonham',
      keyboard: 'john paul johns',
    },
    {
      band: 'deep purple',
      singer: 'ian gillan',
      'lead guitar': 'ritchie blackmore',
      bass: 'roger glover',
      drums: 'ian paice',
      keyboard: 'jon lord',
    },
  ],
};
 
export default (
  <Table
    data={tableData}
    uxpId="table1"
    width="stretched"
  />
);

This is a perfectly valid JSX preset! And things get even better – your data can be imported from an external JS or JSON file.

Merge Presets are very powerful and with handling this power comes a lot of responsibility! Please remember that changes in the preset will update the design, unless the properties were overridden in a particular project in UXPin.

In the future you may expect us to provide the options to:

  • Build multiple presets for one component and give users in the UXPin Editor the ability to switch between them
  • Detach component from preset in the UXPin Editor
  • Provide support for multiple git branches