1.0.1 • Published 3 years ago

sms-plugin---components v1.0.1

Weekly downloads
-
License
ISC
Repository
github
Last release
3 years ago

⬅ Back to 🍕

🔌 Components Plugin

Inspired by XState Component Tree

Integrate JavaScript components into a state machine config. This plugin analyzes a state machine in order to build a tree of components to be rendered for the active state. This component tree is stored in your state machine context under the components property.

Add Plugin

import sms from "state-machine-snacks";
import components from "sms-plugin---components";

const config = { /* ...machine config */ };

const service = sms({
    config,

    // Add plugin
    plugins : [
       components(),
    ]
});

service.start(); 
OptionsDescription
contextModify where the component tree is stored in context. Provide a string containing the new context property name.

Usage

Define component states in the state machine config. When a component state is entered, the corresponding component(s) (multiple if parallel state) will be included in the component tree.

component(component, state, props)

In order to define which states are associated with which components, utilize the component() helper provided by the Components plugin.

ArgDescriptionType
componentImported component to be rendered. See MyComponent below.Any
stateXState state object.Object
propsProps to be passed to the component. If any of the object properties are functions, the functions will be handled similar to XState assign. Each function will be called with the latest context and last event. (ctx, event) => propValueObject

Examples

Examples of state machine configs and their component tree outputs for each state.

Single Component

import { component } from "sms-plugin---components";

import ComponentOne from "./component-one.svelte";
import ComponentTwo from "./component-two.svelte";

export default {

    on : {
        HIDE_ALL           : ".hideAll"
        SHOW_COMPONENT_ONE : ".componentStateOne",
        SHOW_COMPONENT_TWO : ".someState.componentStateTwo",
    }

    states : {
        hideAll : {},

        componentStateOne : component(ComponentOne, {
            on : {
                EXIT_COMPONENT : "showNothing",
            }
        }),

        someState : {
            states : {
                componentStateTwo : component(ComponentTwo)
            }
        }
    }
};

hideAll

[
   /* empty */
]

componentStateOne

[
    {   
        component : ComponentOne,
        children : []
    }
]

someState.componentStateTwo

* Non-component states are skipped.

[
    {   
        component : ComponentTwo,
        children : []
    }
]

Nesting Components

This is how you could make something like a multi-tab view or nav bar.

import { component } from "sms-plugin---components";

import TabView from "./tab-view.svelte";

import TabOne from "./tab-component-1.svelte";
import TabTwo from "./tab-component-2.svelte";

export default {
    initial : "hideTabView",

    on :  {
        HIDE_TAB_VIEW : ".hideTabView",
        SHOW_TAB_VIEW : ".showTabView",
    }

    states : {
        hideTabView : {},
        showTabView : component(TabView, {
            on : {
                SHOW_TAB_ONE : ".tabOne",
                SHOW_TAB_TWO : ".tabTwo",
            },

            states : {
                tabOne : component(TabOne),
                tabTwo : component(TabTwo),
            }
        })
    }
};

hideTabView

[
   /* empty */
]

showTabView

[
    {   
        component : TabView,
        children  : []
    }
]

showTabView.tabOne

[
    {   
        component : TabView,
        children  : [
            {
                component : TabOne,
                children  : []
            }
        ]
    }
]

showTabView.tabTwo

[
    {   
        component : TabView,
        children  : [
            {
                component : TabTwo,
                children  : []
            }
        ]
    }
]

Parallel Components

Often times we need to render more than one component at once. To accommodate this, the component tree plugin plays very nicely with XState's concept of parallel states.

import { component } from "sms-plugin---components";

import MainView from "./main-view.svelte";
import Modal from "./modal.svelte";

import SubViewOne from "./sub-view-1.svelte";
import SubViewTwo from "./sub-view-2.svelte";

export default {
    // Important
    type : "parallel",

    states : {
        // An always-on parent view with two child states
        main : component(MainView, {
            on : {
                SUB_VIEW_ONE : ".subViewOne",
                SUB_VIEW_TWO : ".subViewTwo",
            },

            states : {
                subViewOne : component(SubViewOne),
                subViewTwo : component(SubViewTwo),
            }
        }),

        // Rendered at same level as "MainView" but only when in `modal.show`
        modal : {
            initial : "hide",

            on : {
                MODAL_SHOW : ".show"
                MODAL_HIDE : ".hide"
            }

            states : {
                hide : {},
                show : component(Modal)
            }
        }
    }
};

main, modal.hide

[
   {
       component : MainView,
       children  : [],
   }
]

main.subViewOne, modal.hide

[
   {
       component : MainView,
       children  : [
           {
               component : SubViewOne,
               children  : [],
           }
       ],
   }
]

main, modal.show

[
    {
        component : MainView,
        children  : [],
    },
    {
        component : Modal,
        children  : [],
    }
]

main.subViewTwo, modal.show

[
    {
        component : MainView,
        children  : [
            {
                component : SubViewTwo,
                children  : [],
            }
        ],
    },
    {
        component : Modal,
        children  : [],
    }
]

Reading The Component Tree

The component tree will be stored in the context of your state machine. You can access the value with a simple subscription.

Svelte

App.svelte

{#each components as { component, children }}
    <svelte:component this={component} components={children} />
{/each}

<script>
import service from "./service.js";

// XState services similar in shape to Svelte stores.
// This means we can subscribe to them with Svelte's `$`.
$: ({
    components
} = $service.context);
</script>

example-child.svelte To render the additional children, utilize the props passed in by the parent and continue the pattern.

{#each components as { component, children }}
    <svelte:component this={component} components={children} />
{/each}

<script>
export let components;
</script>

Vue

WIP

React

WIP

sms-plugin---components