Skip to content
Edmund edited this page Jan 22, 2019 · 57 revisions

Props

Prop Type Description
name String The name of the module
[tag='div'] String HTML tag to use when rendering the module
[modifiers] Array Modifiers to add to the rendered module
[className] String CSS classes to add to the rendered module
[before] React Element Content to render before the module
[after] React Element Content to render after the module
[id] String The id HTML attribute to add to the rendered module
[href] String The href HTML attribute
[data‑{attribute}] String Any data-attribute
[on{Event}] Function Any valid GlobalEventHandler (you must use camelCase to be compatible with React)
[modifierGlue='-'] String The glue to use when attaching modifiers to modules/components
[componentGlue='_'] String The glue to use when attaching modifiers to modules/components
[config] Object Configuration to use for module
[init] Function Function to call on rendered DOM element
[styleParser] Function Function to parse and apply styles
[styles] Array Array of parameters to pass to the function defined by styleParser
[ui] * Placeholder property for Synergy framework

Props.modifierGlue

This value can be changed globally

<Module name='foo' modifierGlue='--' bar>My Module</Module>
Output
<div class="foo--bar">My Module</div>

Props.componentGlue

This must be set on <Module> and not <Component>

This value can be changed globally

<Module name='foo' componentGlue='__'>
    <Component name='bar'>My Component</Component>
</Module>
Output
<div class="foo">
    <div class="foo__bar">My Component</div>
</div>

Props.config

  • Automatically merged with config found under Window object
  • Config is attached to the rendered DOM node
  • Config is passed to styleParser function as the third parameter
Example
// Some default pre-existing config attached to `Window`
// - `foo` must match whatever value you pass to `Props.name` on `<Module>`
window.foo.config = {
    fizz: 'buzz',
    someData: [1, 6, 35, 9]
}

// some custom config
const config = {
    fizz: 'bang',
    someData: window.foo.config.someData.concat([11]),
    someMethod: () => { ... }
}
// As the `name` value is `foo`, it will fetch data from `window.foo.config`
<Module name='foo' config={config} id='myModule'>My Module</Module>

After rendering the module on the page you can now do:

var element = document.getElementById('myModule');

element.config.fizz; // returns 'bang'
element.config.someData; // returns [1, 6, 35, 9, 11]
element.config.someMethod(); // executes `someMethod()`

Props.config.name

Overwrite the value of props.name when rendering the module (this allows the name used to reference the Module internally to be different from the name used when rendering the Module to the DOM)

Example
<Module name='foo' config={{ name: 'namespaced-foo' }}>My Module</Module>
Output
<div class="namespaced-foo">My Module</div>

Props.init

A function that will be called when the component renders, where the first and only parameter will be the HTML element of the rendered component

init(node)

Props.styleParser

This property is used to pass a function which would be used to style the component, based off the values passed from the styles prop, and gets invoked like so:

styleParser(node, ...props.styles)

...allowing your styleParser function to contain any number of parameters as long as the first parameter expects the HTML element of the rendered component.

Polymorph was built to be used as a styleParser function to be used with Lucid

Instead of having to pass this prop every time, you can assign your styleParser function to window.Synergy.styleParser where it will automatically be picked up by the <Module> component.

Dynamic styleParser Parameters

Rather than passing the parameters for the styleParser function via Props.styles, Lucid can fetch values from the Window object and pass them in a pre-defined manner. If Props.styles is not set, the styleParser function will be executed like so:

styleParser(node, window.MODULE_NAME.layout, config, ui);

Props.styles

An array of values to be passed as parameters for the styleParser function

Configuration

@TODO

More Than One Module

It's possible to render an element as multiple modules by passing additional module names as props, ensuring that the first letter is capitalised.

<Module name='blockquote' Alert>...</Module>
Output
<div class="blockquote alert">...</div>

Pass Single Modifier

<Module name='blockquote' Alert='success'>...</Module>
Output
<div class="blockquote alert-success">...</div>

Pass Multiple Modifiers

<Module name='blockquote' Alert={['box', 'success']}>...</Module>
Output
<div class="blockquote alert-box-success">...</div>

Additional Modules & styleParser

This feature was introduced for the Synergy framework but can be utilised independently

If you utilise the styleParser property, or use Polymorph, then when you pass additional modules you will likely also want them to be styled as that module.

Lucid handles this use-case and requires only a bit of setup to work. Here's the relevant code from Lucid to handle this behaviour:

Object.keys(props).forEach(prop => {
    const fistLetter = prop[0];

    if (fistLetter === fistLetter.toUpperCase()) {
        if (window[prop] && window[prop].layout && window[prop].config) {
            node.namespace = node.namespace || prop;

            styleParser(node, window[prop].layout, window[prop].config, ui);
        }
    }
});

Reference: /lucid/src/utilities/refHandler.js

From the above code, it can be identified that the following needs to exist for styleParser to work on the additionally applied module:

  • Layout object/function for the additionally applied module, which should be attached to window.MODULE_NAME.layout (this needs to be done manually)
    • this will be passed as the second parameter to styleParser
  • Configuration object for the additionally applied module, which should be attached to window.MODULE_NAME.config (this needs to be done manually)
    • this will passed as the third parameter to styleParser
  • MODULE_NAME must have a capitalised first letter

You'll also notice a ui reference in the above code; this is passed in <Module>'s constructor method, and will either be the result returned from Props.ui, window.ui, or undefined - with the value being passed as the fourth parameter to the styleParser.

Example
window.ui = {
    colors: {
        primary: 'red',
        secondary: 'blue'
    }
}

window.Alert = {
    layout: {
        display: 'block'
    },
    config: {
        color: 'red'
    }
}
<Module name='blockquote' Alert>...</Module>

Now when the above <Module> component is rendered, the styleParser function will be executed like so:

// `node` is the rendered DOM element of `<Module>`
styleParser(node, window.Alert.layout, window.Alert.config, window.ui);

Naturally without knowing what styleParser does there is no result to show here, however for more context you can check out Polymorph, which was built as a styleParser function for Lucid.

For an example of where this feature is used consider looking at the Synergy framework, which is a toolkit consisting of Lucid, Polymorph and sQuery.

Add CSS Class Via Props

It's possible to add CSS classes to an element by passing them as props. In order for the <Module> component to know what CSS classes are allowed, you must add them to a global window.Synergy.CssClassProps array:

window.Synergy.CssClassProps = ['object', 'inline'];

Now in your React component you can do:

<Module name='accordion' object>...</Module>

<Module name='button' inline>...</Module>
Output
<div class="accordion object">...</div>

<div class="button inline">...</div>

If window.Synergy.CssClassProps wasn't defined (or it didn't contain the relevant values), object and inline would instead be treated as modifiers, and the output would be:

<div class="accordion-object">...</div>

<div class="button-inline">...</div>

Dynamic init Method

You can automatically call an init function on the rendered DOM element in the module's componentDidMount lifecycle method by attaching the function to the init property of your module's global object. This object needs to be created manually:

This will only take effect if Props.init is not defined

window.accordion = {
    init: node => {
        // do something with `node`
        ...
    }
}
<Module name='accordion'>...</Module>

Now whenever a <Module> component with a name value of accordion is mounted, the window.accordion.init method will be called upon the rendered DOM element. This is equivalent to passing the same function to the <Module>'s init prop.

Clone this wiki locally